Asymmetric numeral systems

Asymmetric numeral systems (ANS)[1] is a family of entropy encoding methods introduced by Jarosław (Jarek) Duda[2] from Jagiellonian University, used in data compression since 2014[3] due to improved performance compared to previously used methods, being up to 30 times faster.[4] ANS combines the compression ratio of arithmetic coding (which uses a nearly accurate probability distribution), with a processing cost similar to that of Huffman coding. In the tabled ANS (tANS) variant, this is achieved by constructing a finite-state machine to operate on a large alphabet without using multiplication.

Among others, ANS is used in the Facebook Zstandard compressor[5][6] (also used e.g. in Linux kernel,[7] Android[8] operating system, was published as RFC 8478 for MIME[9] and HTTP[10]), in the Apple LZFSE compressor,[11] Google Draco 3D compressor[12](used e.g. in Pixar Universal Scene Description format[13]) and PIK image compressor,[14] in CRAM DNA compressor[15] from SAMtools utilities, Dropbox DivANS compressor,[16] and in JPEG XL[17] next generation image compression standard.

The basic idea is to encode information into a single natural number . In the standard binary number system, we can add a bit of information to by appending at the end of which gives us . For an entropy coder, this is optimal if . ANS generalizes this process for arbitrary sets of symbols with an accompanying probability distribution . In ANS, if is the result of appending the information from to , then . Equivalently, , where is the number of bits of information stored in the number and is the number of bits contained in the symbol .

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 the symbols to encode. Then to add information from symbol into the information already stored in the current number , we go to number being the position of the -th appearance from the -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.

Entropy codingEdit

Suppose a sequence of 1,000 zeros and ones would be encoded, which would take 1000 bits to store directly. However, if it is somehow known that it only contains 1 zero and 999 ones, it would be sufficient to encode the zero's position, which requires only   bits here instead of the original 1000 bits.

Generally, such length   sequences containing   zeros and   ones, for some probability  , are called combinations. Using Stirling's approximation we get their asymptotic number being


called Shannon entropy.

Hence, to choose one such sequence we need approximately   bits. It is still   bits if  , however, it can also be much smaller. For example we need only   bits for  .

An entropy coder allows the encoding of a sequence of symbols using approximately the Shannon entropy bits per symbol. For example ANS could be directly used to enumerate combinations: assign a different natural number to every sequence of symbols having fixed proportions in a nearly optimal way.

In contrast to encoding combinations, this probability distribution usually varies in data compressors. For this purpose, Shannon entropy can be seen as a weighted average: a symbol of probability   contains   bits of information. ANS encodes information into a single natural number  , interpreted as containing   bits of information. Adding information from a symbol of probability   increases this informational content to  . Hence, the new number containing both information should be  .

Basic concepts of ANSEdit

Comparison of the concept of arithmetic coding (left) and ANS (right). Both can be seen as generalizations 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 47 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 one 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 one to retrieve the bit sequence in reversed order.

The above procedure is optimal for the 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 are 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)Edit

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


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), this is the same as new_x = floor(x*(1-p))
if s = 1 then new_x = ceil(x*p)  // D(x) = (new_x, 1)


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 amounts to the standard binary system (with 0 and 1 inverted), for a different   it becomes optimal for this given probability distribution. For example, for   these formulas lead to a 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

The symbol   corresponds to a subset of natural numbers with 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 coding   can be found by taking the row corresponding to a given symbol  , and choosing the given   in this row. Then the top row provides  . For example,   from the middle to the top row.

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

Range variants (rANS) and streamingEdit

The range variant also uses arithmetic formulas, but allows operation on a 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 quantization 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)Edit

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 which yields a finite-state machine avoiding the need of multiplication.

Finally, the step of the decoding loop can be written as:

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

The step of the encoding loop:

s = ReadSymbol();
nbBits = (x + ns[s]) >> r;  // # of bits for renormalization
writeBits(x, nbBits);  // send the least significant 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.

Example of generation of tANS tables for m = 3 size alphabet and L = 16 states, then applying them for stream decoding. First we approximate probabilities using fraction with denominator being the number of states. Then we spread these symbols in nearly uniform way, optionally the details may depend on cryptographic key for simultaneous encryption. Then we enumerate the appearances starting with value being their amount for a given symbol. Then we refill the youngests bits from the stream to return to the assumed range for x (renormalization).


As for Huffman coding, modifying the probability distribution of tANS is relatively costly, hence it is mainly used in static situations, usually with some Lempel–Ziv scheme (e.g. ZSTD, LZFSE). In this case, the file is divided into blocks - for each of them symbol frequencies are independently counted, then after approximation (quantization) written in the block header and used as static probability distribution for tANS.

In contrast, rANS is usually used as a faster replacement for range coding (e.g. CRAM, LZNA, Draco,[12] AV1). 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, making it a stack for symbols. This inconvenience is usually resolved by encoding in backward direction, after which decoding can be done forward. For context-dependence, like Markov model, the encoder needs to use context from the perspective of later decoding. For adaptivity, the encoder should first go forward to find probabilities which will be used (predicted) by decoder and store them in a buffer, then encode in backward direction using the buffered 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. For example, instead of starting with "10000" state, start with "1****" state, where "*" are some additional stored bits, which can be retrieved at the end of the decoding. Alternatively, this state can be used as a checksum by starting encoding with a fixed state, and testing if the final state of decoding is the expected one.

See alsoEdit


  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. ^
  3. ^ Duda, Jarek (October 6, 2019). "List of compressors using ANS, implementations and other materials". Retrieved October 6, 2019.
  4. ^ "Google Accused of Trying to Patent Public Domain Technology". Bleeping Computer. September 11, 2017.
  5. ^ Smaller and faster data compression with Zstandard, Facebook, August 2016
  6. ^ 5 ways Facebook improved compression at scale with Zstandard, Facebook, December 2018
  7. ^ Zstd Compression For Btrfs & Squashfs Set For Linux 4.14, Already Used Within Facebook, Phoronix, September 2017
  8. ^ "Zstd in Android P release".
  9. ^ Zstandard Compression and The application/zstd Media Type (email standard)
  10. ^ Hypertext Transfer Protocol (HTTP) Parameters, IANA
  11. ^ Apple Open-Sources its New Compression Algorithm LZFSE, InfoQ, July 2016
  12. ^ a b Google Draco 3D compression library
  13. ^ Google and Pixar add Draco Compression to Universal Scene Description (USD) Format
  14. ^ Google PIK: new lossy image format for the internet
  15. ^ CRAM format specification (version 3.0)
  16. ^ Building better compression together with DivANS
  17. ^ Rhatushnyak, Alexander; Wassenberg, Jan; Sneyers, Jon; Alakuijala, Jyrki; Vandevenne, Lode; Versari, Luca; Obryk, Robert; Szabadka, Zoltan; Kliuchnikov, Evgenii; Comsa, Iulia-Maria; Potempa, Krzysztof; Bruse, Martin; Firsching, Moritz; Khasanova, Renata; Ruud van Asseldonk; Boukortt, Sami; Gomez, Sebastian; Fischbacher, Thomas (2019). "Committee Draft of JPEG XL Image Coding System". arXiv:1908.03565 [eess.IV].
  18. ^ Data Compression Explained, Matt Mahoney

External linksEdit