Veamos una forma ligeramente diferente de pensar sobre la codificación de Huffman.
Suponga que tiene un alfabeto de tres símbolos, A, B y C, con probabilidades 0.5, 0.25 y 0.25. Debido a que todas las probabilidades son potencias inversas de dos, esto tiene un código Huffman que es óptimo (es decir, es idéntico a la codificación aritmética). Utilizaremos el código canónico 0, 10, 11 para este ejemplo.
Supongamos que nuestro estado es un número entero grande, al que llamaremos . Puede pensar en la codificación como una función que toma el estado actual, y un símbolo para codificar, y devuelve el nuevo estado:s
codificar ( s , A )codificar (s,B)codificar (s,C)= 2 s= 4 s + 2= 4 s + 3
Comencemos con el estado 11 (que es 1011 en binario), codifique el símbolo B. El nuevo estado es 46, que es 101110 en binario. Como puede ver, este es el estado "antiguo" con la secuencia 10 agregada al final. Básicamente, hemos "generado" la secuencia de bits 10.
Hasta ahora tan bueno.
Ahora piense por un momento acerca de cómo funciona la codificación aritmética. Si coloca las probabilidades sobre un denominador común, el símbolo A en realidad representa el rango , el símbolo B representa el rango[2[ 04 4, 24 4)y el símbolo C representa el rango[3[ 24 4, 34 4).[ 34 4, 44 4)
Básicamente, lo que estamos haciendo aquí es multiplicar todo por el común denominador. Imagine que el estado estaba realmente en la base 4. La codificación de un símbolo B realmente genera el dígito 2 en esa base, y la codificación de un símbolo C genera el dígito 3 en esa base.
Sin embargo, el símbolo A es un poco diferente, porque no es un dígito completo en la base 4.
En cambio, podemos pensar en el alfabeto como el conjunto de símbolos A_0, A_1, B, C, con igual probabilidad. Esto, nuevamente, tiene un código óptimo de Huffman 00, 01, 10, 11. O, nuevamente, podemos pensar en esto en la base 4. Para codificar un símbolo, simplemente hacemos:
codificar (s, A0 0)codificar (s, A1)codificar (s,B)codificar (s,C)= 4 s + 0= 4 s + 1= 4 s + 2= 4 s + 3
UN0 0UN1
s
s′= ⌊ s2⌋
i = s mod 2
y luego .codificar ( s′, Ayo)
Usando nuestro ejemplo anterior, , encontramos que e , y luego . El nuevo estado es 10101 en binario.s ′ = 5 i = 1 codificar ( 5 , A 1 ) = 4 × 5 + 1 = 21s = 11s′= 5i = 1codificar (5, A1) = 4 × 5 + 1 = 21
Ahora, esto no produce exactamente la misma salida de bits que la codificación Huffman, pero genera una salida que tiene la misma longitud. Y lo que espero que puedan ver es que esto también es decodificable de forma única. Para decodificar un símbolo, tomamos el resto cuando se divide entre 4. Si el valor es 2 o 3, entonces el símbolo es B o C, respectivamente. Si es 0 o 1, entonces el símbolo es A, y luego podemos recuperar el bit de información multiplicando el estado por 2 y agregando 0 o 1.
Lo bueno de este enfoque es que se extiende naturalmente a la codificación de bits fraccionales, cuando el numerador y / o denominador de las probabilidades no son potencias de dos. Supongamos que tenemos dos símbolos, A y B, donde la probabilidad de A es y la probabilidad de B es . Entonces podemos codificar un símbolo con: 235 525 5
codificar (s, A0 0)codificar (s, A1)codificar (s, A2)codificar (s, B0 0)codificar (s, B1)= 5 s + 0= 5 s + 1= 5 s + 2= 5 s + 3= 5 s + 4
Para codificar el símbolo A, tomamos e , y luego .s′= ⌊ s3⌋i = s mod 3codificar ( s′, Ayo)
Esto es equivalente a la codificación aritmética. En realidad, es una familia de métodos conocidos como sistemas numéricos asimétricos , y fue desarrollada en los últimos años por Jarek Duda. El significado del nombre debe ser obvio: para codificar un símbolo con probabilidad , conceptualmente robas un dígito base-p del estado y luego agregas un dígito base-q. La asimetría proviene de interpretar el estado como un número en dos bases diferentes.pagsq
La razón por la cual es una familia de métodos de codificación es que lo que hemos visto aquí no es práctico por sí mismo; necesita algunas modificaciones para lidiar con el hecho de que probablemente no tenga enteros de precisión infinita para manipular la variable de estado de manera eficiente, y hay varias formas de lograrlo. La codificación aritmética, por supuesto, tiene un problema similar con precisión para su estado.
Las variantes prácticas incluyen rANS (la "r" significa "relación") y tANS ("controlado por tabla").
ANS tiene algunas ventajas interesantes sobre la codificación aritmética, tanto práctica como teórica:
- A diferencia de la codificación aritmética, el "estado" es una sola palabra, en lugar de un par de palabras.
- No solo eso, sino que un codificador ANS y su decodificador correspondiente tienen estados idénticos y sus operaciones son completamente simétricas. Esto plantea algunas posibilidades interesantes, como que puede intercalar diferentes flujos de símbolos codificados y todo se sincroniza perfectamente.
- Las implementaciones prácticas necesitan, por supuesto, "generar" información sobre la marcha, y no solo recopilarla en un gran número entero que se escribirá al final. Sin embargo, el tamaño de la "salida" se puede configurar a cambio de una pérdida de compresión (generalmente modesta). Entonces, cuando los codificadores aritméticos deben generar un bit a la vez, ANS puede generar un byte o un nybble a la vez. Esto le proporciona un compromiso directo entre velocidad y compresión.
- Parece ser tan rápido en el hardware de la generación actual como la codificación aritmética binaria y, por lo tanto, competitivo con la codificación Huffman. Esto lo hace mucho más rápido que la codificación aritmética de alfabeto grande y sus variantes (por ejemplo, la codificación de rango).
- Parece estar libre de patentes.
No creo que vuelva a hacer codificación aritmética.