Kompresja danych Instytut Informatyki UWr Studia dzienne Wykład nr 2: rozszerzone i dynamiczne Huffmana
Mar 18, 2016
Kompresja danych
Instytut Informatyki UWrStudia dzienneWykład nr 2: rozszerzone i dynamiczne Huffmana
Kod Huffmana - niemiłe przypadki...Niech alfabet składa się z 2 liter:
P(a)=1/16 P(b)=15/16Mamy
H(1/16, 15/16) = -1/16*log(1/16)-15/16*log(15/16) 0.34
Natomiast algorytm Huffmana daje kod K:
K(a)=0 K(b)=1Czyli
S(K) = 1/16*1+15/16*1 = 1... żadnej kompresji, prawie 3 razy gorzej od entropii...
Kod Huffmana - rozszerzamy...Dla rozkładu prawdopodobieńtw jak poprzednio:
P(A)=1/16 P(B)=15/16Wprowadźmy rozszerzony alfabet {AA, AB, BB, BA}
średnia długość powyższego kodu Huffmana:S(H) = 1/256 * 3 + 15/256 * 3 +15/256 * 2 + 225/256*1 1.18
a entropia:H(1/256, 15/256, 15/256, 225/256) 0.68
Czyli już „tylko” niecałe 2 razy gorzej od entropii.
Para P(para) Kod Huffm
AA 1 / 256 100
AB 15 / 256 101
BB 225 / 256 0
BA 15 / 256 11
Uogólnijmy rozszerzanie...Uogólniamy (dla ciągów niezależnych): Dany rozkład prawdopodobieństw P = { p1,,pn }
odpowiadający symbolom a1,,an
k-tym rozszerzeniem Pk rozkładu P nazywamy rozkład odpowiadający wszystkim k-elementowym ciągom symboli ze zbioru { a1,,an }
prawdopodobieństwo ciągu ai1 aik w rozkładzie Pk to pi1*pi2* *pik
Jak zmieni się entropia? rozkład prawdopodobieństwa oryginalnych symboli nie
zmienił się! A zatem „zawartość informacyjna” danych również powinna
ulec zmianie!!!
Entropia dla rozszerzonego alfabetuTwierdzenieNiech Pk będzie rozkładem prawdopodobieństw k-tego
rozszerzenia alfabetu z rozkładem P. Wówczas:H(Pk) = k H(P)
Dowód:k = 1: oczywiste
Krok indukcyjny:Załóżmy, że H(Pk-1) = (k-1) H(P).
Wówczas:
Dowód c.d.
)(
)()1(log
log)(
]log)log(
)]log()[log(
)log()(
1
11
1
1
1
1
1
1
2
22
2
2
1
1
21
2
2
1
1
1
1
1
1
,,,,
,,
,,
PHk
pPHkpp
pPHp
pppppppp
pppppp
ppppPH
iii
ii
ik
ii
iiiiiiii
iii
ii
iiiiiii
ii
iiiii
ik
k
k
kk
k
kk
k
kk
k
Rozszerzony alfabet c.d.Skoro
H(Pk) = k H(P)
to znaczy, że zgodnie z intuicją liczba „bitów informacji” przypadających na jeden
symbol rozszerzonego alfabetu jest k-krotnie większa od liczby bitów „informacji” na symbol oryginalnego alfabetu
ale jeden symbol w Pk odpowiada k symbolom w P czyli liczba bitów na „oryginalny” symbol nie zmienia
się.
A jak z jakością kodów Huffmana dla rozszerzonego alfabetu?
Jakość Huffmana dla rozszerzonego...
WniosekŚrednia długość kodu Huffmana dla rozszerzonego
alfabetu z rozkładem Pk odpowiadająca przypadająca na jeden symbol alfabetu oryginalnego wynosi co najwyżej H(P)+1/k.
Dowód:Optymalność kodu Huffmana gwarantuje, że
S( Huffmank ) H(Pk) + 1gdzie Huffmank to kod Huffmana dla Pk.A zatem na jeden symbol alfabetu oryginalnego przypada
co najwyżej:S( Huffmank ) / k (H(Pk) + 1) / k = H(P) + 1/k
bitów.
Kompresja a wydajnośćWniosekUżywając rozszerzonych kodów Huffmana dla coraz
większych k osiągamy kompresję coraz bliższą entropii.Ale związane są z tym koszty: W k-tym rozszerzeniu alfabetu o rozmiarze n
uzyskujemy alfabet rozmiaru nk (wzrost wykładniczy!) Oznacza to wykładniczy wzrost czasu tworzenia kodu ...oraz wykładniczy wzrost pamięci potrzebnej na
przechowywanie (drzewa) kodu Ale czas kompresji/dekompresji pozostaje liniowy!
W praktyce: Trzeba wybrać kompromis między kompresją a
czasem/pamięcią
Problem techniczny: tekst musi mieć długość podzielną przez k.
Skąd brać prawdopodobieństwa? Prawdopodobieństwa ustalone z góry, w oparciu o
specyfikę danych:– z góry znane koderowi i dekoderowi (np. standard wideo
H.263)– ale przestaje działać gdy zmieni się charakterystyka danych
Wyznaczamy prawdopodobieństwa w oparciu o częstość występowania symboli w kodowanym tekście:
– konieczne 2 przebiegi: najpierw zliczanie częstości, potem kodowanie
– konieczne dołączenie kodu lub częstości do zakodowanych danych (dekoder ich nie zna!)
Kodowanie dynamiczne:– w każdym kroku korzystamy z częstości w dotychczas
zakodowanej części tekstu (znać ją będzie też dekoder)– wystarczy jeden przebieg– nie trzeba dołączać kodu ani prawdopodobieństw (pbb) do
danych.
Dynamiczne kody Huffmana... czyli wystarczy tylko raz policzyć do nieskończoności
Idea: Przy kodowaniu każdej litery stosujemy kod
Huffmana dla pbb opartych na częstościach już zakodowanej części
Prawdopodobieństwa te znane są również dekoderowi:
– Przy odkodowywaniu p-tej litery znane są już litery od pierwszej do (p-1)-szej
Po każdej literze konieczne modyfikowanie (drzewa) kodu
ALE wystarczy jeden przebieg kodowanego pliku!CEL: Przebudowa kodu po każdym kroku nie powinna być
kosztowna!
Dynamiczne kody HuffmanaWażne przy kodowaniu modyfikujemy kod po zakodowaniu
symbolu przy dekodowaniu modyfikujemy kod przed
odkodowaniem symbolu
W ten sposób koder i dekoder przy każdym symbolu używają tego samego drzewa kodu!
Dynamiczne kody HuffmanaNumerowanie wierzchołków drzewa: od dołu do góry od lewej do prawej
A
B
C D1 2
43
6
5
7
Dynamiczne kody Huffmana c.d.Wagi wierzchołków: waga liścia = liczba wystąpień odpowiadającego mu symbolu waga wierzchołka wewnętrznego = suma wag liści w jego
poddrzewie
5
3
1 2
3
6
11
NiezmiennikW optymalnym drzewie kodu dla n symboli istnieje
numerowanie wszystkich wierzchołków v1,,v2n-1
spełniające warunki: w(v1) w(v2) w(v2n-1), gdzie w(x) to waga
wierzchołka x wierzchołki mające wspólnego rodzica mają sąsiednie
numeryI na odwrót: Jeśli drzewo kodu ma numerowanie spełniające
powyższe warunki, kod jest optymalny
Obserwacja: W kodzie Huffmana taką numerację można uzyskać poprzez numerowanie (od końca) w kolejności usuwania elementów (poprzez zsumowanie ich prawdopodobieństw)
CEL: zachowywać tę własność w kodowaniu dynamicznym, bez przebudowywania całego drzewa.
Niezmiennik silniejszyPrzypomnijmyW optymalnym drzewie kodu dla n symboli istnieje
numerowanie wszystkich wierzchołków v1,,v2n-1
spełniające warunki: w(v1) w(v2) w(v2n-1), gdzie w(x) to waga
wierzchołka x wierzchołki mające wspólnego rodzica mają sąsiednie
numeryI na odwrót: Jeśli drzewo kodu ma numerowanie
spełniające powyższe warunki, kod jest optymalny
Dla nas interesujące jest tylko to, że powyższe własności zachodzą dla numerowania, które sobie zdefiniowaliśmy:
od dołu do góry od lewej do prawej.
Inicjalizacja
Na początku (alfabet a1,…,am):
drzewo kodu: złożone z jednego wierzchołka NP (od „nie przesłany”) o wadze 0 i numerze 2m-1;UWAGI:
– wierzchołek NP będzie w drzewie symbolizować wszystkie symbole, które jeszcze nie pojawiły się w tekście
– numer 2m-1 dlatego, że będzie 2m-1 wierzchołków docelowo (m liści)
Wszystkich literom przyporządkowujemy kody stałe, wykorzystywane tylko przy pierwszym pojawieniu się danej litery w tekście:
Kody stałe
Niech e i r takie, że m = 2e + r i 0 r < 2e. Literze ai przyporządkowujemy kod stały: (e+1) -bitowej reprezentacji liczby i-1 gdy 1 i 2r e-bitowej reprezentacji liczby i-r-1 w przeciwnym
przypadku.
Czyli Kod stały równy kodowi o stałej długości równej log
m, gdy m jest potęgą dwójki Mała optymalizacja kodu o stałej długości, gdy m nie
jest potęgą dwójki: – 2r symboli ma kod o długości log m– m - 2r symbol ma kod o długości log m
Kody stałe - przykład
Niech m = 10 (alfabet ma 10 symboli).Wtedy : 10 = 23+2, czyli e=3 r=2
Inaczej: rysujemy drzewoo głębokości e+1 i staramy sięwykorzystać „wolne” liście(dwa liście na poziomie e+1dpowiadają jednemuwierzchołkowi na poziomie e)
FAKT: kod stały jest kodem prefiksowym (ćw.)
Litera Kod
A1 0000
A2 0001
A3 0010
A4 0011
A5 010
A6 011
A7 100
A8 101
A9 110
A10 111
KodowanieDla kolejnego symbolu tekstu b: jeśli w drzewie kodu nie ma liścia o etykiecie b,
kodujemy b jako:– kod wierzchołka NP– a za nim kod stały odpowiadający symbolowi bDodaj 2 dzieci wierzchołka NP (o numerze p)– lewe dziecko to nowy NP (numerze p-2, waga 0)– prawe dziecko ma etykietę b (numer p-1, waga 1)
Jeśli w drzewie kodu jest liść o etykiecie b: – kodujemy b za pomocą odpowiadającego mu w
drzewie kodu słowa kodowego
wykonaj aktualizację drzewa kodu
DekodowanieDopóki nie ma końca zakodowanego pliku: odkoduj słowo kodowe odpowiadające liściowi
aktualnego drzewa kodu jeśli odkodowane słowo kodowe odpowiada literze
alfabetu: zapisz ją.
jeśli odkodowane słowo kodowe odpowiada wierzchołkowi NP:
– odkoduj kolejną literę według kodu stałego (e lub e+1 bitów według drzewa kodu stałego): zapisz ją.
Następnie, dodaj 2 dzieci wierzchołka NP (o numerze p)– lewe dziecko to nowy NP (numerze p-2, waga 0)– prawe dziecko ma etykietę b (numer p-1, waga 1)
wykonaj aktualizację drzewa kodu.
Aktualizacja drzewa koduCEL - zachowanie niezmiennika: numerowanie wszystkich wierzchołków v1,,v2n-1 (od dołu do
góry, od lewej do prawej) ma spełniać warunek: w(v1) w(v2) w(v2n-1), gdzie w(x) to waga
wierzchołka x
Idea rozwiązania: przechodzimy ścieżkę od liścia odpowiadającego
ostatniemu symbolowi i zwiększamy wagi wszystkich wierzchołków o 1
gdy zwiększenie wagi zaburza powyższy niezmiennik, zamieniamy aktualny wierzchołek z najwyżej położonym wierzchołkiem o takiej samej wadze.
Efekt: koszt proporcjonalny do długości słowa kodowego a nien log n ....
Aktualizacja drzewa kodu c.d.Blok: zbiór wierzchołków o tej samej wadze.
UWAGI: Jeśli numeracja v1,,v2n-1 spełnia warunek w(v1)
w(v2) w(v2n-1), to wszystkie wierzchołki z jednego bloku tworzą spójny obszar w tej numeracji
Jak reprezentujemy bloki: lista dwustronna w kolejności odpowiadającej
numeracji wszystkich wierzchołków dodatkowo wskaźniki na początki bloków
Aktualizacja drzewa kodu c.d.Niech v to wierzchołek odpowiadający ostatnio
zakodowanemu bądź odkodowanemu symbolowi:Dopóki v jest różny od korzenia: jeśli numer v nie jest największy w bloku do którego v
należy: zamień v z wierzchołkiem w o największym numerze w bloku (o ile w nie jest rodzicem v).UWAGI:
– zamieniamy całe poddrzewa– v i w zamieniają się numerami– ale numery pozostałych wierzchołków nie
zmieniają się zwiększ wagę v o jeden: w(v) w(v)+1 v rodzic(v)
Przykład: dyn. HuffmanAlfabet {A, B, C, D, ..., J} – 10 elementów.Tekst do zakodowania:
A A B C D A D
Kody stałe: Drzewo kodu:Litera Kod
A 0000
B 0001
C 0010
D 0011
E 010
F 011
G 100
H 101
I 110
J 111
0NP
Przykład c.d.A A B C D A D
Drzewo kodu:
OUTPUT: 0000 kod stały AUWAGA: kod wierzchołka NP jest pusty!
0NP
21
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 kod stały A
UWAGA: kod wierzchołka NP jest pusty!
1
A
0 1
NP
21
19 20
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 00001
1
A
0 1
NP19 20
21
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 00001
2
A
0 2
NP
19 20
21
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 kod NP kod stały B
2
A
0 2
NP
19 20
21
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001
2
A
0 2
0 0NP B
19 20
21
17 18
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001
3
A
1 2
0 1NP B
19 20
21
17 18
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 kod NP kod stały C
3
A
1 2
0 1NP B
19 20
21
17 18
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010
3
A
1 2
0 1
NP
B
19 20
21
17 18
0 0c
15 16
Przykład c.d.: A A B C D A DDrzewo kodu:Popraw. śc.
OUTPUT: 0000 1 0 0001 00 0010
4
A
2 2
1 1
NP
B
19 20
21
17 18
0 1c
15 16
Przykład c.d.: A A B C D A DDrzewo kodu:Popraw. śc.
OUTPUT: 0000 1 0 0001 00 0010 000 0011 kod NP kod stały D
4
A
2 2
1 1
NP
B
19 20
21
17 18
0 1c
15 16
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011
4
A
2 2
1 1
NP
B
19 20
21
17 18
0 1c
15 16
0 0D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011
4
A
2 2
1 1
NP
B
19 20
21
17 18
1 1c
15 16
0 1D
13 14
ZAMIANA!
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011
4
A
2 2
21
NP
B
19 20
21
1718
1 1c
15 16
0 1D
13 14
ZAMIANA!
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011
4
A
32
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011
5
A
32
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011 0Uwaga: A był kodowany jako 0000, 1 a na końcu jako 0.
5
A
32
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011 0
6
A
33
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011 0 1101
6
A
33
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011 0 1101
6
A
33
21
NP
B
2019
21
17 18
1 1c
15 16
0 1D
13 14
ZAMIANA!
Przykład c.d.: A A B C D A DDrzewo kodu:
OUTPUT: 0000 1 0 0001 00 0010 000 0011 0 1101
7
A
43
22
NP
D
2019
21
17 18
1 1c
15 16
0 1B
13 14
Dynamiczny Huffman: struktury danych Tabela kodu stałego Binarne drzewo kodu H. Wskaźniki na liście dla każdej
litery Lista dwustronna wg numeracji
(oraz wskaźniki na początki bloków)
CZAS: liniowy względem rozmiaru kodu
7
A43
22
NP
D
2019
21
17 18
1 1c
15 16
0 1B
13 14A
B
C
D
Dynamiczny Huffman: niezmiennik?Chcemy pokazać, że algorytm modyfikacji drzewa kodu
zachowuje własności: Numeracja w algorytmie v1,,v2n-1 jest numeracją od
dołu do góry i od lewej do prawej Wagi wierzchołków spełniają warunek: w(v1) w(v2)
w(v2n-1)
Szkic dowodu: Zamiana z największym w bloku gwarantuje, że zanim
zwiększymy wagę wierzchołka, „wypchniemy” go przed wszystkie wierzchołki, których waga stanie się mniejsza (czyli „na początek” jego bloku)
Ale razem z wierzchołkiem „przestawiamy” całe jego poddrzewo... co może zaburzyć numerację
Jednak: wszystkie wierzchołki pomiędzy dwoma zamienianymi są liśćmi (poza jednym przypadkiem...)
Kodowanie Huffmana: podsumowanieWłasności Optymalny wśród prefiksowych Kodowanie i dekodowanie w czasie liniowym! Kody rozszerzone: kompromis między zasobami a
kompresją Możliwość implementacji jednoprzebiegowej,
dynamicznej: kompresja zbliżona do kodu statycznego, dodatkowy czas liniowy
Zastosowania: pkZIP, lha, gz, zoo, arj. formaty JPEG i MPEG (jako
jeden z etapów, czasem zmodyfikowany)
Eksperymenty Bezstratna kompresja obrazów: współczynnik 1,5 Kompresja tekstów w języku naturalnym: wsp. 2 Kompresja dźwięku: wsp. 1,5 (kodowanie różnic)
Jak robiono to dawniej...Kody Shannona ... czyli nierówność Krafta jest konstruktywna: p1 … pn to prawdopodobieństwa symboli Fi = p1 + p2 +...+ pi-1
Kod: Słowo kodowe symbolu ai to pierwszych
li = log (1/pi) bitów (``po przecinku'') w binarnej reprezentacji liczby Fi.
Ale: Pokazaliśmy wcześniej, że kod o takich
długościach ma średnią długość co najwyżej H(p1,…, pn )+1
Jak robiono to dawniej...Trzeba tylko pokazać, że:Kod Shannona jest kodem prefiksowym.
Dowód (szkic): Fi+1 – Fi = pi 1 / 2l_i oraz li+1 li
gwarantuje, że słowa kodowe coraz dłuższe a różnica między kodem ai i kodem aj dla j > i musi wystąpić wśród pierwszych li pozycji.
Do tego tematu wrócimy...
Jak robiono to dawniej... dziel i zwyciężajKod Shannon-Fano v1.0.0: Niech p1 … pn to prawdopodobieństwa symboli Jeśli n = 1, to kod(a1)=0. Jeśli n=2, to kod(a1)=0, kod(a2)=1. Jeśli n > 2 :
– podziel ciąg {p1,..., pn} na dwa podciągi R = {p1,...,pn1} i S={pn1+1,..., p n} takie, że różnica
|(p1+...+pn1) – (pn1+1+...+pn)| jest minimalna.
Rekurencyjnie, znajdź kody Shannon-Fano dla prawdopodobieństw p1,...,pn1 oraz pn1+1,...,pn
Poprzedź kody symboli z S bitem 0, kody symboli z R, bitem 1.
Jak robiono to dawniej... dziel i zwyciężajKod Shannon-Fano v1.0.1 Niech p1 … pn to
prawdopodobieństwa symboli– Wybieramy nie punkt podziału w
uporządkowanym ciągu p1,..., pn lecz podział zbioru {p1,..., pn} na dwa podzbiory dające minimalną różnicę sum prawdopodobieństw