Gibt es eine Verallgemeinerung der Huffman-Codierung auf die arithmetische Codierung?

11

Beim Versuch, die Beziehungen zwischen Huffman-Codierung, arithmetischer Codierung und Bereichscodierung zu verstehen, begann ich über die Mängel der Huffman-Codierung nachzudenken, die mit dem Problem der fraktionierten Bitpackung zusammenhängen .

Angenommen, Sie haben 240 mögliche Werte für ein Symbol und müssen diese in Bits codieren. Sie würden also mit 8 Bits pro Symbol stecken bleiben, obwohl Sie keine "volle" 8 benötigen, da 8 256 mögliche Werte ausdrücken kann pro Symbol. Eine Lösung für dieses Problem ist etwas, das ich als "fraktionierte Bitpackung" bezeichnet habe, bei der Sie durch Multiplikation eine "Bitverschiebung" durch eine Nicht-Zweierpotenz erzielen können. So wie sich die Multiplikation von Zweierpotenzen verschiebt x * 2 == x << 1und x * 4 == x << 2so weiter für alle Zweierpotenzen, können Sie auch mit einer Nicht-Zweierpotenz "verschieben", indem Sie stattdessen multiplizieren und Symbole in Bruchbitgröße einpacken .

Das Problem ist bei der Huffman-Codierung ähnlich: Sie erhalten Codes, deren Länge nicht fraktionell bitgroß sein muss, und daher weist sie diese Ineffizienz beim Packen auf. Sie können jedoch nicht einfach die Lösung der Fracitonal-Bit-Packung verwenden, da diese Lösung Symbole mit fester Größe voraussetzt.

Die Frage ist, gibt es irgendwelche Papiere oder Lösungen, um die Huffman-Codierung mit einer ähnlichen Idee wie die fraktionierte Bitpackung zu verbessern, um etwas Ähnliches wie die arithmetische Codierung zu erreichen? (oder gegenteilige Ergebnisse).

Realz Slaw
quelle
1
Die arithmetische Codierung ist bereits optimal. Es besteht keine Notwendigkeit, es zu verbessern.
Yuval Filmus
@ YuvalFilmus Ja, ich meinte, wie man die Huffman-Codierung verbessert, um sie mit der arithmetischen Codierung gleichzusetzen.
Realz Slaw
1
Nur als Vorschlag ist die Codierung des asymmetrischen Zahlensystems (ANS) möglicherweise leichter zu verstehen als die arithmetische Codierung. Insbesondere ist es etwas einfacher, diese bestimmte Formulierung als "fraktionierte Bitpackung" zu sehen.
Pseudonym
@ Pseudonym Ich habe diese Seite gefunden , die diese Verbindung zwischen rANS und Huffman Coding herzustellen scheint. Ich kann noch nicht sagen, dass ich es verstehe, aber ich denke, es reicht aus. Wenn Sie dem Kommentar eine Antwort geben, werde ich akzeptieren.
Realz Slaw
@YuvalFilmus Ich hoffe, ich habe den Fall gemacht, dass die arithmetische Codierung verbessert werden musste, und ANS ist eine Verbesserung.
Pseudonym

Antworten:

12

Schauen wir uns eine etwas andere Sichtweise der Huffman-Codierung an.

Angenommen, Sie haben ein Alphabet mit drei Symbolen, A, B und C, mit Wahrscheinlichkeiten von 0,5, 0,25 und 0,25. Da die Wahrscheinlichkeiten alle inverse Zweierpotenzen sind, hat dies einen optimalen Huffman-Code (dh er ist identisch mit der arithmetischen Codierung). Wir werden für dieses Beispiel den kanonischen Code 0, 10, 11 verwenden.

s

encode(s,A)=2sencode(s,B)=4s+2encode(s,C)=4s+3

Beginnen wir also mit dem Zustand 11 (der binär 1011 ist) und codieren Sie das Symbol B. Der neue Zustand ist 46, der binär 101110 ist. Wie Sie sehen können, ist dies der "alte" Zustand mit der am Ende hinzugefügten Sequenz 10. Wir haben im Wesentlichen die Bitfolge 10 "ausgegeben".

So weit, ist es gut.

[04,24)[24,34)[34,44)

Grundsätzlich multiplizieren wir hier alles mit dem gemeinsamen Nenner. Stellen Sie sich vor, der Zustand befand sich tatsächlich in Basis 4. Das Codieren eines Symbols B gibt tatsächlich die Ziffer 2 in dieser Basis aus, und das Codieren eines Symbols C gibt die Ziffer 3 in dieser Basis aus.

Symbol A ist jedoch etwas anders, da es in Basis 4 keine ganze Ziffer ist.

Stattdessen können wir uns das Alphabet als die Menge der Symbole A_0, A_1, B, C mit gleicher Wahrscheinlichkeit vorstellen. Dies hat wiederum einen optimalen Huffman-Code 00, 01, 10, 11. Oder wir können uns dies in Basis 4 vorstellen. Um ein Symbol zu codieren, tun wir einfach:

encode(s,A0)=4s+0encode(s,A1)=4s+1encode(s,B)=4s+2encode(s,C)=4s+3

A0A1

s

s=s2
i=smod2

und dann .encode(s,Ai)

Anhand unseres vorherigen Beispiels, , stellen wir fest, dass und und dann . Der neue Status ist 10101 in binär.s=11s=5i=1encode(5,A1)=4×5+1=21

Dies erzeugt nicht genau die gleiche Bitausgabe wie die Huffman-Codierung, sondern eine Ausgabe mit der gleichen Länge. Und ich hoffe, Sie können sehen, dass dies auch einzigartig dekodierbar ist. Um ein Symbol zu dekodieren, nehmen wir den Rest, wenn er durch 4 geteilt wird. Wenn der Wert 2 oder 3 ist, ist das Symbol B bzw. C. Wenn es 0 oder 1 ist, ist das Symbol A, und dann können wir das Informationsbit zurücksetzen, indem wir den Zustand mit 2 multiplizieren und entweder 0 oder 1 addieren.

Das Schöne an diesem Ansatz ist, dass er sich natürlich auf die Bruchbitcodierung erstreckt, wenn der Zähler und / oder der Nenner der Wahrscheinlichkeiten keine Zweierpotenzen sind. Angenommen, wir haben zwei Symbole, A und B, wobei die Wahrscheinlichkeit von A und die Wahrscheinlichkeit von B . Dann können wir ein Symbol codieren mit:3525

encode(s,A0)=5s+0encode(s,A1)=5s+1encode(s,A2)=5s+2encode(s,B0)=5s+3encode(s,B1)=5s+4

Um das Symbol A zu codieren, nehmen wir und und dann .i=smod3codieren(s',Ai)s=s3i=smod3encode(s,Ai)

Dies entspricht einer arithmetischen Codierung. Es ist eigentlich eine Familie von Methoden, die als asymmetrische Zahlensysteme bekannt sind und in den letzten Jahren von Jarek Duda entwickelt wurden. Die Bedeutung des Namens sollte offensichtlich sein: Um ein Symbol mit der Wahrscheinlichkeit zu codieren , stehlen Sie konzeptionell eine Basis-p-Ziffer aus dem Status und fügen dann eine Basis-q-Ziffer hinzu. Die Asymmetrie ergibt sich aus der Interpretation des Zustands als Zahl in zwei verschiedenen Grundlagen.pq

Der Grund, warum es sich um eine Familie von Codierungsmethoden handelt, ist, dass das, was wir hier gesehen haben, für sich genommen unpraktisch ist. Es sind einige Änderungen erforderlich, um die Tatsache zu berücksichtigen, dass Sie wahrscheinlich keine Ganzzahlen mit unendlicher Genauigkeit haben, um die Statusvariable effizient zu manipulieren, und es gibt verschiedene Möglichkeiten, wie Sie dies erreichen können. Die arithmetische Codierung hat natürlich ein ähnliches Problem mit der Genauigkeit ihres Zustands.

Praktische Varianten sind rANS ("r" bedeutet "Verhältnis") und tANS ("tabellengesteuert").

ANS hat einige interessante Vorteile gegenüber der arithmetischen Codierung, sowohl in der Praxis als auch in der Theorie:

  • Im Gegensatz zur arithmetischen Codierung ist der "Zustand" eher ein einzelnes Wort als ein Wortpaar.
  • Darüber hinaus haben ein ANS-Codierer und sein entsprechender Decodierer identische Zustände und ihre Operationen sind vollständig symmetrisch. Dies eröffnet einige interessante Möglichkeiten, z. B. dass Sie verschiedene Ströme codierter Symbole verschachteln können und alles perfekt synchronisiert ist.
  • Praktische Implementierungen müssen natürlich Informationen "ausgeben", während Sie fortfahren, und sie nicht nur in einer großen Ganzzahl sammeln, die am Ende geschrieben werden soll. Die Größe der "Ausgabe" kann jedoch als Gegenleistung für (normalerweise bescheidene) Komprimierungsverluste konfiguriert werden. Wenn also arithmetische Codierer jeweils ein Bit ausgeben müssen, kann ANS jeweils ein Byte oder ein Nybble ausgeben. Dies gibt Ihnen einen direkten Kompromiss zwischen Geschwindigkeit und Komprimierung.
  • Es scheint auf Hardware der aktuellen Generation ungefähr so ​​schnell zu sein wie die binäre arithmetische Codierung und daher mit der Huffman-Codierung konkurrenzfähig zu sein. Dies macht es viel schneller als die arithmetische Codierung mit großem Alphabet und ihre Varianten (z. B. Bereichscodierung).
  • Es scheint patentfrei zu sein.

Ich glaube nicht, dass ich jemals wieder arithmetisch codieren werde.

Pseudonym
quelle
3
Das ist die klarste Erklärung für die ANS-Codierung, die ich je gesehen habe.
Michael Deardeuff
2

Wenn Sie beispielsweise drei Symbole mit einer Wahrscheinlichkeit von jeweils 1/3 hätten, würde Ihre optimale Huffman-Codierung die drei Symbole 0, 10 und 11 mit einem Durchschnitt von 5/3-Bits verwenden.

Es gibt 243 Symbole, die durch Verketten von 5 der ursprünglichen Symbole mit einer Wahrscheinlichkeit von jeweils 1/243 erstellt wurden. Welches ist viel näher an 1/256. Die optimale Huffman-Codierung codiert 13 dieser Gruppen in 7 Bit und 230 Gruppen in 8 Bit für durchschnittlich 7,9465 Bit pro Gruppe oder 1,5893 Bit pro Originalsymbol, verglichen mit 1,6667 Bit für die ursprüngliche Huffman-Codierung, wobei die arithmetische Codierung 1,5850 beträgt Bits.

Theoretisch könnten Sie also einfach zwei Symbole zu einem größeren Symbol oder drei Symbole zu einem größeren Symbol kombinieren und die Hufman-Codierung für die Kombinationen verwenden.

gnasher729
quelle