<?xml version="1.0" encoding="UTF-8" standalone="yes"?><oembed><version><![CDATA[1.0]]></version><provider_name><![CDATA[The ryg blog]]></provider_name><provider_url><![CDATA[https://fgiesen.wordpress.com]]></provider_url><author_name><![CDATA[fgiesen]]></author_name><author_url><![CDATA[https://fgiesen.wordpress.com/author/fgiesen/]]></author_url><title><![CDATA[rANS notes]]></title><type><![CDATA[link]]></type><html><![CDATA[<p>We&#8217;ve been spending some time at RAD looking at Jarek Duda&#8217;s ANS/ABS coders (<a href="http://arxiv.org/abs/1311.2540">paper</a>). This is essentially a new way of doing arithmetic coding with some different trade-offs from the standard methods. In particular, they have a few sweet spots for situations that were (previously) hard to handle efficiently with regular arithmetic coding.</p>
<p>The paper covers numerous algorithms. Of those given, I think what Jarek calls &#8220;rANS&#8221; and &#8220;tANS&#8221; are the most interesting ones; there&#8217;s plenty of binary arithmetic coders already and &#8220;uABS&#8221;, &#8220;rABS&#8221; or &#8220;tABS&#8221; do not, at first sight, offer any compelling reasons to switch (that said, there&#8217;s some non-obvious advantages that I&#8217;ll get to in a later post).</p>
<p>Charles has already posted a good <a href="http://cbloomrants.blogspot.com/2014/02/02-02-14-understanding-ans-4.html">introduction</a>; I recommend you start there. Charles has also spent a lot of time dealing with the table-based coders, and the table-based construction allows some extra degrees of freedom that make it hard to see what&#8217;s actually going on. In this post, I&#8217;m going to mostly talk about rANS, the range coder equivalent. Charles already describes it up to the point where you try to make it &#8220;streaming&#8221; (i.e. finite precision); I&#8217;m going to continue from there.</p>
<h3>Streaming rANS</h3>
<p>In Charles&#8217; notation (which I&#8217;m going to use because the paper uses both indexed upper-case I&#8217;s and indexed lower-case l&#8217;s, which would make reading this with the default font a disaster), we have two functions now: The coding function C and the decoding function D defined as</p>
<p><img src="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%3A%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%3A%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%3A%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="C(s,x) := M &#92;lfloor x/F_s &#92;rfloor + B_s + (x &#92;bmod F_s)" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=D%28x%29+%3A%3D+%28s%2C+F_s+%5Clfloor+x%2FM+%5Crfloor+%2B+%28x+%5Cbmod+M%29+-+B_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=D%28x%29+%3A%3D+%28s%2C+F_s+%5Clfloor+x%2FM+%5Crfloor+%2B+%28x+%5Cbmod+M%29+-+B_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=D%28x%29+%3A%3D+%28s%2C+F_s+%5Clfloor+x%2FM+%5Crfloor+%2B+%28x+%5Cbmod+M%29+-+B_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="D(x) := (s, F_s &#92;lfloor x/M &#92;rfloor + (x &#92;bmod M) - B_s)" class="latex" /> where <img src="https://s0.wp.com/latex.php?latex=s+%3D+s%28x+%5Cbmod+M%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=s+%3D+s%28x+%5Cbmod+M%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=s+%3D+s%28x+%5Cbmod+M%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="s = s(x &#92;bmod M)" class="latex" />.</p>
<p>D determines the encoded symbol s by looking at (x mod M) and looking up the corresponding value in our cumulative frequency table (s is the unique s such that <img src="https://s0.wp.com/latex.php?latex=B_s+%5Cle+x+%5Cbmod+M+%3C+B_s+%2B+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=B_s+%5Cle+x+%5Cbmod+M+%3C+B_s+%2B+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=B_s+%5Cle+x+%5Cbmod+M+%3C+B_s+%2B+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="B_s &#92;le x &#92;bmod M &lt; B_s + F_s" class="latex" />).</p>
<p>Okay. If you&#039;re working with infinite-precision integers, that&#039;s all you need, but that&#039;s not exactly suitable for fast (de)compression. We want a way to perform this using finite-precision integers, which means we want to limit the size of x somehow. So what we do is define a &quot;normalized&quot; interval</p>
<p><img src="https://s0.wp.com/latex.php?latex=I+%3A%3D+%5C%7B+L%2C+L%2B1%2C+%5Cdots%2C+bL+-+1+%5C%7D+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I+%3A%3D+%5C%7B+L%2C+L%2B1%2C+%5Cdots%2C+bL+-+1+%5C%7D+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I+%3A%3D+%5C%7B+L%2C+L%2B1%2C+%5Cdots%2C+bL+-+1+%5C%7D+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I := &#92;{ L, L+1, &#92;dots, bL - 1 &#92;} = [L:bL)" class="latex" /></p>
<p>The [L:bL) thing on the right is the notation I&#039;ll be using for a half-open interval of integers). b is the radix of our encoder; b=2 means we&#039;re emitting bits at a time, b=256 means we&#039;re emitting bytes, and so forth. Okay. We now want to keep x in this range. Too large x don&#039;t fit in finite-precision integers, but why not allow small x? The (hand-wavey) intuition is that too small x don&#039;t contain enough information; as Charles mentioned, x essentially contains about <img src="https://s0.wp.com/latex.php?latex=%5Clog_2%28x%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5Clog_2%28x%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5Clog_2%28x%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;log_2(x)" class="latex" /> bits of information. If x &lt; 4, it can only be one of four distinct values, and as you saw above the value of x (mod M) directly determines which symbol we&#039;re coding. So we want x just right: not too large, not too small. Okay. Now let&#039;s look at how a corresponding decoder would look:</p>
<pre>
  while (!done) {
    // Loop invariant: x is normalized.
    assert(L &lt;= x &amp;&amp; x &lt; b*L);

    // Decode a symbol
    s, x = D(x);

    // Renormalization: While x is too small,
    // keep reading more bits (nibbles, bytes, ...)
    while (x &lt; L)
      x = x*b + readFromStream();
  }
</pre>
<p>Turns out that&#8217;s actually our decoding algorithm, period. What we need to do now is figure out how the corresponding encoder looks. As long as we&#8217;re only using C and D with big integers, it&#8217;s simple; the two are just inverses of each other. Likewise, we want our encoder to be the inverse of our decoder &#8211; exactly. That means we have to do the inverse of the operations the decoder does, in the opposite order. Which means our encoder has to look something like this:</p>
<pre>
  while (!done) {
    // Inverse renormalization: emit bits/bytes etc.
    while (???) {
      writeToStream(x % b);
      x /= b;
    }

    // Encode a symbol
    x = C(s, x);
 
    // Loop invariant: x is normalized
    assert(L &lt;= x &amp;&amp; x &lt; b*L);
  }
</pre>
<p>So far, this is purely mechanical. The only question is what happens in the &#8220;???&#8221; &#8211; when exactly <em>do</em> we emit bits? Well, for the encoder and decoder to be inverses of each other, the answer has to be &#8220;exactly when the decoder would read them&#8221;. Well, the decoder reads bits whenever the normalization variant is violated after decoding a symbol, to make sure it holds for the next iteration of the loop. The encoder, again, needs to do the opposite &#8211; we need to proactively emit bits <em>before</em> coding s to make sure that, after we&#8217;ve applied C, x will be normalized.</p>
<p>In fact, that&#8217;s all we need for a first sketch of renormalization:</p>
<pre>
  while (!done) {
    // Keep trying until we succeed
    for (;;) {
      x_try = C(s, x);
      if (L &lt;= x_try &amp;&amp; x_try &lt; b*L) { // ok?
        x = x_try;
        break;
      } else {
        // Shrink x a bit and try again
        writeToStream(x % b);
        x /= b;
      }
    }

    x = x_try;
  }
</pre>
<p>Does this work? Well, it might. It depends. We certainly can&#8217;t guarantee it from where we&#8217;re standing, though. And even if it does, it&#8217;s kind of ugly. Can&#8217;t we do better? What about the normalization &#8211; I&#8217;ve just written down the normalization loops, but just because both decoder and encoder maintain the same invariants doesn&#8217;t necessarily mean they are in sync. What if at some point of the loop, there are more than two possible normalized configurations &#8211; can this happen? Plus there&#8217;s some hidden assumptions in here: the encoder, by only ever shrinking x before C, assumes that C always causes x to increase (or at least never causes x to decrease); similarly, the decoder assumes that applying D won&#8217;t increase x. </p>
<p>And I&#8217;m afraid this is where the proofs begin.</p>
<h3>Streaming rANS: the proofs (part 1)</h3>
<p>Let&#8217;s start with the last question first: does C always increase x? It certainly looks like it might, but there&#8217;s floors involved &#8211; what if there&#8217;s some corner case lurking? Time to check:</p>
<p><img src="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=C%28s%2Cx%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="C(s,x)" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%3D+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="= M &#92;lfloor x/F_s &#92;rfloor + B_s + (x &#92;bmod F_s)" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%3D+F_s+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28x+%5Cbmod+F_s%29+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%3D+F_s+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28x+%5Cbmod+F_s%29+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%3D+F_s+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28x+%5Cbmod+F_s%29+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="= F_s &#92;lfloor x/F_s &#92;rfloor + (x &#92;bmod F_s) + (M - F_s) &#92;lfloor x/F_s &#92;rfloor + B_s" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%3D+x+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%3D+x+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%3D+x+%2B+%28M+-+F_s%29+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="= x + (M - F_s) &#92;lfloor x/F_s &#92;rfloor + B_s" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5Cge+x&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5Cge+x&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5Cge+x&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;ge x" class="latex" /></p>
<p>since <img src="https://s0.wp.com/latex.php?latex=x%2FF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%2FF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%2FF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x/F_s" class="latex" />, <img src="https://s0.wp.com/latex.php?latex=B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=B_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="B_s" class="latex" />, and <img src="https://s0.wp.com/latex.php?latex=M+-+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=M+-+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=M+-+F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="M - F_s" class="latex" /> are all non-negative (the latter because <img src="https://s0.wp.com/latex.php?latex=F_s+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=F_s+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=F_s+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="F_s &lt; M" class="latex" /> &#8211; each symbol&#039;s frequency is less than the sum of all symbol frequencies). So C indeed always increases x, or more precisely, never decreases it.</p>
<p>Next up: normalization. Let&#039;s tackle the decoder first. First off, is normalization in the decoder unique? That is, if <img src="https://s0.wp.com/latex.php?latex=x+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x &#92;in I" class="latex" />, is that the only normalized x it could be at that stage in the decoding process? Yes, it is: <img src="https://s0.wp.com/latex.php?latex=x+%5Cin+I+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x+%5Cin+I+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x+%5Cin+I+%3D+%5BL%3AbL%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x &#92;in I = [L:bL)" class="latex" />, so <img src="https://s0.wp.com/latex.php?latex=x+%5Cge+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x+%5Cge+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x+%5Cge+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x &#92;ge L" class="latex" />, so</p>
<p><img src="https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cge+bx+%5Cge+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cge+bx+%5Cge+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cge+bx+%5Cge+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="bx + d &#92;ge bx &#92;ge bL" class="latex" /> where <img src="https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="d &#92;in [0:b)" class="latex" /> arbitrary</p>
<p>That is, no matter what bit / byte / whatever the decoder would read next (that&#039;s &#039;d&#039;), running through the normalization loop once more would cause x to become too large; there&#039;s only one way for x to be normalized. But do we always end up with a normalized x? Again, yes. Suppose that <img src="https://s0.wp.com/latex.php?latex=x+%3C+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x+%3C+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x+%3C+L&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x &lt; L" class="latex" />, then (because we&#039;re working in integers) <img src="https://s0.wp.com/latex.php?latex=x+%5Cle+L+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x+%5Cle+L+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x+%5Cle+L+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x &#92;le L - 1" class="latex" />, and hence</p>
<p><img src="https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cle+bL+-+b+%2B+d+%5Cle+bL+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cle+bL+-+b+%2B+d+%5Cle+bL+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=bx+%2B+d+%5Cle+bL+-+b+%2B+d+%5Cle+bL+-+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="bx + d &#92;le bL - b + d &#92;le bL - 1" class="latex" /> (again <img src="https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=d+%5Cin+%5B0%3Ab%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="d &#92;in [0:b)" class="latex" /> arbitrary)</p>
<p>The same kind of argument works for the encoder, which floor-divides by b instead of multiplying b it. The key here is that our normalization interval I has a property the ANS paper calls &#8220;b-uniqueness&#8221;: it&#8217;s of the form <img src="https://s0.wp.com/latex.php?latex=I%3D%5Bk%3Abk%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I%3D%5Bk%3Abk%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I%3D%5Bk%3Abk%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I=[k:bk)" class="latex" /> for some positive integer k (its upper bound is b times its lower bound). Any process that grows (or shrinks) x in multiples of b can&#8217;t &#8220;skip over&#8221; I (as in, transition from being larger than the largest value in I to smaller than the smallest value in I or vice versa) in a single step. Simultaneously, there&#8217;s also never two valid states the encoder/decoder could be in (which could make them go out of sync: both encoder and decoder think they&#8217;re normalized, but they&#8217;re at different state values).</p>
<p>To elaborate, suppose we have b=2 and some interval where the ratio between lower and upper bound is a tiny bit less than 2: say <img src="https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k-1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k-2+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k-1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k-2+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k-1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k-2+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I&#039; = [k:2k-1) = &#92;{ k, k+1, &#92;dots, 2k-2 &#92;}." class="latex" /> There&#8217;s just one value missing. Now suppose the decoder is in state <img src="https://s0.wp.com/latex.php?latex=x%3Dk-1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3Dk-1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3Dk-1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=k-1" class="latex" /> and reads a bit, which turns out to be 1. Then the new state is <img src="https://s0.wp.com/latex.php?latex=x%27+%3D+2x%2B1+%3D+2%28k-1%29+%2B+1+%3D+2k+-+1+%5Cnot%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%27+%3D+2x%2B1+%3D+2%28k-1%29+%2B+1+%3D+2k+-+1+%5Cnot%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%27+%3D+2x%2B1+%3D+2%28k-1%29+%2B+1+%3D+2k+-+1+%5Cnot%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x&#039; = 2x+1 = 2(k-1) + 1 = 2k - 1 &#92;not&#92;in I&#039;" class="latex" /> &#8211; we overshot! We were below the lower bound of I&#8217;, and yet with a single bit read, we&#8217;re now past its upper bound. I&#8217; is &#8220;too small&#8221;.</p>
<p>Now let&#8217;s try the other direction; again b=2, and this time we make the ratio between upper and lower bound a bit too high: set <img src="https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k%2B1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k%2B1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I%27+%3D+%5Bk%3A2k%2B1%29+%3D+%5C%7B+k%2C+k%2B1%2C+%5Cdots%2C+2k+%5C%7D.&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I&#039; = [k:2k+1) = &#92;{ k, k+1, &#92;dots, 2k &#92;}." class="latex" /> There&#8217;s no risk of not reaching a state in that interval now, but now there is ambiguity. Where&#8217;s the problem? Suppose the encoder is in state <img src="https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=2k" class="latex" />. Coding any symbol will require renormalization to &#8220;shift out&#8221; one bit. The encoder writes that bit (a zero), goes to state <img src="https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=k" class="latex" />, and moves on. But there&#8217;s a problem: the decoder, after decoding that symbol, will be in state <img src="https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3Dk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=k" class="latex" /> too. And it doesn&#8217;t know that the encoder got there from state <img src="https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3D2k&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=2k" class="latex" /> by shifting a bit; all the decoder knows is that it&#8217;s in state <img src="https://s0.wp.com/latex.php?latex=x%3Dk+%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=x%3Dk+%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=x%3Dk+%5Cin+I%27&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="x=k &#92;in I&#039;" class="latex" />, which is normalized and doesn&#8217;t require reading any more bits. So the encoder has written a bit that the decoder doesn&#8217;t read, and now the two go out of sync.</p>
<p>Long story short: if the state intervals involved aren&#8217;t b-unique, bad things happen. And on the subject of bad things happening, our encoder tries to find an x such that C(s,x) is inside I by shrinking x &#8211; but what if that process doesn&#039;t find a suitable x? We need to know a bit more about which values of x lead to C(s,x) being inside I, which leads us to the sets</p>
<p><img src="https://s0.wp.com/latex.php?latex=I_s+%3A%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_s+%3A%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_s+%3A%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_s := &#92;{ x | C(s,x) &#92;in I &#92;}" class="latex" /></p>
<p>i.e. the set of all x such that encoding &#039;s&#039; puts us into I again. If all these sets turn out to be b-unique intervals, we&#039;re good. If not, we&#039;re in trouble. Time for a brief example.</p>
<h3>Intermission: why b-uniqueness is necessary</h3>
<p>Let&#8217;s pick L=5, b=2 and M=3. We have just two symbols: &#8216;a&#8217; has probability <img src="https://s0.wp.com/latex.php?latex=P_a%3D2%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=P_a%3D2%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=P_a%3D2%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="P_a=2/3" class="latex" />, and &#8216;b&#8217; has probability <img src="https://s0.wp.com/latex.php?latex=P_b%3D1%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=P_b%3D1%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=P_b%3D1%2F3&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="P_b=1/3" class="latex" />, which we turn into <img src="https://s0.wp.com/latex.php?latex=F_a+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=F_a+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=F_a+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="F_a = 2" class="latex" />, <img src="https://s0.wp.com/latex.php?latex=B_a+%3D+0&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=B_a+%3D+0&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=B_a+%3D+0&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="B_a = 0" class="latex" />, <img src="https://s0.wp.com/latex.php?latex=F_b+%3D+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=F_b+%3D+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=F_b+%3D+1&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="F_b = 1" class="latex" />, <img src="https://s0.wp.com/latex.php?latex=B_b+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=B_b+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=B_b+%3D+2&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="B_b = 2" class="latex" />. Our normalization interval is <img src="https://s0.wp.com/latex.php?latex=I+%3D+%5B5%3A2%5Ccdot5%29+%3D+%5C%7B5%2C+6%2C+7%2C+8%2C+9%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I+%3D+%5B5%3A2%5Ccdot5%29+%3D+%5C%7B5%2C+6%2C+7%2C+8%2C+9%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I+%3D+%5B5%3A2%5Ccdot5%29+%3D+%5C%7B5%2C+6%2C+7%2C+8%2C+9%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I = [5:2&#92;cdot5) = &#92;{5, 6, 7, 8, 9&#92;}" class="latex" />. By computing C(s,x) for the relevant values of s and x, we find out that</p>
<p><img src="https://s0.wp.com/latex.php?latex=I_a+%3D+%5C%7B+4%2C5%2C6+%5C%7D+%3D+%5B4%3A7%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_a+%3D+%5C%7B+4%2C5%2C6+%5C%7D+%3D+%5B4%3A7%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_a+%3D+%5C%7B+4%2C5%2C6+%5C%7D+%3D+%5B4%3A7%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_a = &#92;{ 4,5,6 &#92;} = [4:7)" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=I_b+%3D+%5C%7B+1%2C2+%5C%7D+%3D+%5B1%3A3%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_b+%3D+%5C%7B+1%2C2+%5C%7D+%3D+%5B1%3A3%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_b+%3D+%5C%7B+1%2C2+%5C%7D+%3D+%5B1%3A3%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_b = &#92;{ 1,2 &#92;} = [1:3)" class="latex" /></p>
<p>Uh-oh. Neither of these two intervals is b-unique. <img src="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_a" class="latex" /> is too small, and <img src="https://s0.wp.com/latex.php?latex=I_b&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_b&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_b&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_b" class="latex" /> is too big. So what goes wrong?</p>
<p>Well, suppose that we&#8217;re in state x=7 and want to encode an &#8216;a&#8217;. 7 is not in <img src="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_a" class="latex" /> (too large). So the encoder emits the LSB of x, divides by 2 and&#8230; now x=3. Well, that&#8217;s not in <img src="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_a&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_a" class="latex" /> either (too small), and shrinking it even further won&#8217;t help that. So at this point, the encoder is stuck; there&#8217;s no x it can reach that works.</p>
<h3>Proofs (part 2): a sufficient condition for b-uniqueness</h3>
<p>So we just saw that in certain scenarios, rANS can just get stuck. Is there anything we can do to avoid it? Yes: the paper points out that the embarrassing situation we just ran into can&#8217;t happen when M (the sum of all symbol frequencies, the denominator in our probability distribution) divides L, our normalization interval lower bound. That is, <img src="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="L=kM" class="latex" /> for some positive integer k. It doesn&#8217;t give details, though; so, knowing this, can we prove anything about the <img src="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_s" class="latex" /> that would help us? Well, let&#8217;s just look at the elements of <img src="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_s" class="latex" /> and see what we can do:</p>
<p><img src="https://s0.wp.com/latex.php?latex=I_s+%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_s+%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_s+%3D+%5C%7B+x+%7C+C%28s%2Cx%29+%5Cin+I+%5C%7D&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_s = &#92;{ x | C(s,x) &#92;in I &#92;}" class="latex" /></p>
<p>let&#8217;s work on that condition:</p>
<p><img src="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=C%28s%2Cx%29+%5Cin+I&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="C(s,x) &#92;in I" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+C%28s%2Cx%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+C%28s%2Cx%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+C%28s%2Cx%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow L &#92;le C(s,x) &lt; bL" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+L+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bL&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow L &#92;le M &#92;lfloor x/F_s &#92;rfloor + B_s + (x &#92;bmod F_s) &lt; bL" class="latex" /></p>
<p>at this point, we can use that <img src="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="L=kM" class="latex" /> and divide by M:</p>
<p><img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kM+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kM+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kM+%5Cle+M+%5Clfloor+x%2FF_s+%5Crfloor+%2B+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+bkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow kM &#92;le M &#92;lfloor x/F_s &#92;rfloor + B_s + (x &#92;bmod F_s) &lt; bkM" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow k &#92;le &#92;lfloor x/F_s &#92;rfloor + (B_s + (x &#92;bmod F_s))/M &lt; bk" class="latex" /></p>
<p>Now, for arbitrary real numbers r and natural numbers n we have that</p>
<p><img src="https://s0.wp.com/latex.php?latex=n+%5Cle+r+%5CLeftrightarrow+n+%5Cle+%5Clfloor+r+%5Crfloor+%5Cquad+%5Ctextrm%7Band%7D+%5Cquad+r+%3C+n+%5CLeftrightarrow+%5Clfloor+r+%5Crfloor+%3C+n&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=n+%5Cle+r+%5CLeftrightarrow+n+%5Cle+%5Clfloor+r+%5Crfloor+%5Cquad+%5Ctextrm%7Band%7D+%5Cquad+r+%3C+n+%5CLeftrightarrow+%5Clfloor+r+%5Crfloor+%3C+n&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=n+%5Cle+r+%5CLeftrightarrow+n+%5Cle+%5Clfloor+r+%5Crfloor+%5Cquad+%5Ctextrm%7Band%7D+%5Cquad+r+%3C+n+%5CLeftrightarrow+%5Clfloor+r+%5Crfloor+%3C+n&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="n &#92;le r &#92;Leftrightarrow n &#92;le &#92;lfloor r &#92;rfloor &#92;quad &#92;textrm{and} &#92;quad r &lt; n &#92;Leftrightarrow &#92;lfloor r &#92;rfloor &lt; n" class="latex" /></p>
<p>Using this, we get:</p>
<p><img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+%5Clfloor+x%2FF_s+%5Crfloor+%2B+%28B_s+%2B+%28x+%5Cbmod+F_s%29%29%2FM+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow k &#92;le &#92;lfloor &#92;lfloor x/F_s &#92;rfloor + (B_s + (x &#92;bmod F_s))/M &#92;rfloor &lt; bk" class="latex" /></p>
<p>note the term in the outer floor bracket is the sum of an integer and a real value inside <img src="https://s0.wp.com/latex.php?latex=%5B0%2C1%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5B0%2C1%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5B0%2C1%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="[0,1)" class="latex" />, since <img src="https://s0.wp.com/latex.php?latex=0+%5Cle+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=0+%5Cle+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=0+%5Cle+B_s+%2B+%28x+%5Cbmod+F_s%29+%3C+M&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="0 &#92;le B_s + (x &#92;bmod F_s) &lt; M" class="latex" />, so we can simplify drastically</p>
<p><img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+%5Clfloor+x%2FF_s+%5Crfloor+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow k &#92;le &#92;lfloor x/F_s &#92;rfloor &lt; bk" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+x%2FF_s+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+x%2FF_s+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+k+%5Cle+x%2FF_s+%3C+bk&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow k &#92;le x/F_s &lt; bk" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kF_s+%5Cle+x+%3C+bkF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kF_s+%5Cle+x+%3C+bkF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+kF_s+%5Cle+x+%3C+bkF_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow kF_s &#92;le x &lt; bkF_s" class="latex" /><br />
<img src="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+x+%5Cin+%5BkF_s%3AbkF_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+x+%5Cin+%5BkF_s%3AbkF_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=%5CLeftrightarrow+x+%5Cin+%5BkF_s%3AbkF_s%29&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="&#92;Leftrightarrow x &#92;in [kF_s:bkF_s)" class="latex" /></p>
<p>where we applied the floor identities above again and then just multiplied by <img src="https://s0.wp.com/latex.php?latex=F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=F_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="F_s" class="latex" />. Note that the result is an interval of integers with its (exclusive) upper bound being equal to b times its (inclusive) lower bound, just like we need &#8211; in other words, assuming that <img src="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=L%3DkM&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="L=kM" class="latex" />, all the <img src="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002" srcset="https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002 1x, https://s0.wp.com/latex.php?latex=I_s&#038;bg=ffffff&#038;fg=000&#038;s=0&#038;c=20201002&#038;zoom=4.5 4x" alt="I_s" class="latex" /> are b-unique and we&#039;re golden (this is mentioned in the paper in section 3.3, but not proven, at least not in the Jan 6 2014 version).</p>
<p>Note that this also gives us a much nicer expression to check for our encoder. In fact, we only need the upper bound (due to b-uniqueness, we know there&#039;s no risk of us falling through the lower bound), and we end up with the encoding function</p>
<pre>
  while (!done) {
    // Loop invariant: x is normalized
    assert(L &lt;= x &amp;&amp; x &lt; b*L);

    // Renormalize
    x_max = (b * (L / M)) * freq[s]; // all but freq[s] constant
    while (x &gt;= x_max) {
      writeToStream(x % b);
      x /= b;
    }

    // Encode a symbol
    // x = C(s, x);
    x = freq[s] * (x / M) + (x % M) + base[s];
  }
</pre>
<p>No &#8220;???&#8221;s left &#8211; we have a &#8220;streaming&#8221; (finite-precision) version of rANS, which is almost like the arithmetic coders you know and love (and in fact quite closely related) except for the bit where you need to encode your data in reverse (and reverse the resulting byte stream).</p>
<p>I put an actual implementation on <a href="https://github.com/rygorous/ryg_rans">Github</a> for the curious.</p>
<h3>Some conclusions</h3>
<p>This is an arithmetic coder, just a weird one. The reverse encoding seems like a total pain at first, and it kind of is, but it comes with a bunch of really non-obvious but amazing advantages that I&#8217;ll cover in a later post (or just read the comments in the code). The fact that M (the sum of all frequencies) has to be a multiple of L is a serious limitation, but I don&#8217;t (yet?) see any way to work around that while preserving b-uniqueness. So the compromise is to pick M and L to be both powers of 2. This makes the decoder&#8217;s division/mod with M fast. The power-of-2 limitation makes rANS really bad for adaptive coding (where you&#8217;re constantly updating your stats, and resampling to a power-of-2-sized distribution is expensive), but hey, so is Huffman. As a Huffman replacement, it&#8217;s really quite good.</p>
<p>In particular, it supports a divide-free decoder (and actually no per-symbol division in the encoder either, if you have a static table; see my code on Github, <code>RansEncPutSymbol</code> in particular). This is something you can&#8217;t (easily) do with existing multi-symbol arithmetic coders, and is a really cool property to have, because it really puts it a lot closer to being a viable Huffman replacement in a lot of places that do care about the speed.</p>
<p>If you look at the decoder, you&#8217;ll notice that its entire behavior for a decoding step only depends on the value of <code>x</code> at the beginning: figure out the symbol from the low-order bits of x, go to a new state, read some bits until we&#8217;re normalized again. This is where the table-based versions (tANS etc.) come into play: you can just tabulate their behavior! To make this work, you want to keep b and L relatively small. Then you just make a table of what happens in every possible state.</p>
<p>Interestingly, because these tables really do tabulate the behavior of a &#8220;proper&#8221; arithmetic coder, they&#8217;re <em>compatible</em>: if you have two table-baked distributions with use that same values of b and L (i.e. the same interval I), you can switch between them freely; the states mean the same in both of them. It&#8217;s not at all obvious that it&#8217;s even possible for a table-based encoder to have this property, so it&#8217;s even cooler that it comes with no onerous requirements on the distribution!</p>
<p>That said, as interesting as the table-based schemes are, I think the non-table-based variant (rANS) is actually more widely useful. Having small tables severely limits your probability resolution (and range precision), and big tables are somewhat dubious: adds, integer multiplies and bit operations are fine. We can do these quickly. More compute power is a safe thing to bet on right now (memory access is not). (I do have some data points on what you can do on current HW, but I&#8217;ll get there in a later post.)</p>
<p>As said, rANS has a bunch of really cool, unusual properties, some of which I&#8217;d never have expected to see in any practical entropy coder, with cool consequences. I&#8217;ll put that in a separate post, though &#8211; this one is long (and technical) enough already. Until then!</p>
]]></html></oembed>