530 likes | 703 Views
Kompresja danych. Instytut Informatyki UWr Studia dzienne Wykł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/16 Mamy H(1/16, 15/16) = -1/16*log(1/16)-15/16*log(15/16) 0.34
E N D
Kompresja danych Instytut Informatyki UWr Studia dzienne Wykł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/16 Mamy 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)=1 Czyli 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/16 Wprowadź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.
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ładziePkto 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 alfabetu Twierdzenie Niech Pkbę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, żeH(Pk-1) = (k-1) H(P). Wówczas:
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 Pkodpowiadaksymbolom 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) + 1 gdzie 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ść Wniosek Uż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 Huffmana Waż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 Huffmana Numerowanie wierzchołków drzewa: • od dołu do góry • od lewej do prawej 7 6 A 5 3 B 4 C D 1 2
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 11 6 5 3 3 1 2
Niezmiennik W optymalnym drzewie kodu dla n symboli istnieje numerowanie wszystkich wierzchołków v1,,v2n-1speł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 numery I 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 silniejszy Przypomnijmy W optymalnym drzewie kodu dla n symboli istnieje numerowanie wszystkich wierzchołków v1,,v2n-1speł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 numery I 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 drzewo o głębokości e+1 i staramy się wykorzystać „wolne” liście (dwa liście na poziomie e+1 dpowiadają jednemu wierzchołkowi na poziomie e) FAKT: kod stały jest kodem prefiksowym (ćw.)
Kodowanie Dla 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 b 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) • 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
Dekodowanie Dopó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 kodu CEL - 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 nie nlog n ....
Aktualizacja drzewa kodu c.d. Blok: • zbiór wierzchołków o tej samej wadze. UWAGI: • Jeśli numeracja v1,,v2n-1speł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. Huffman Alfabet {A, B, C, D, ..., J} – 10 elementów. Tekst do zakodowania: A A B C D A D Kody stałe: Drzewo kodu: 0 NP
Przykład c.d. 21 0 A A B C D A D Drzewo kodu: OUTPUT: 0000 kod stały A UWAGA: kod wierzchołka NP jest pusty! NP
Przykład c.d.: A A B C D A D 21 1 19 0 1 20 Drzewo kodu: OUTPUT: 0000 kod stały A UWAGA: kod wierzchołka NP jest pusty! NP A
Przykład c.d.: A A B C D A D 1 21 0 1 20 19 Drzewo kodu: OUTPUT: 00001 NP A
Przykład c.d.: A A B C D A D 2 21 19 0 2 20 Drzewo kodu: OUTPUT: 00001 NP A
Przykład c.d.: A A B C D A D 2 21 19 0 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 kod NP kod stały B NP A
Przykład c.d.: A A B C D A D 2 21 19 0 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 A 17 0 0 18 NP B
Przykład c.d.: A A B C D A D 3 21 19 1 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 A 17 0 1 18 NP B
Przykład c.d.: A A B C D A D 3 21 19 1 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 000010 kod NP kod stały C A 17 0 1 18 NP B
Przykład c.d.: A A B C D A D 3 21 19 1 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 000010 A 17 0 1 18 B 0 0 15 16 NP c
Przykład c.d.: A A B C D A D 4 21 19 2 2 20 Drzewo kodu: Popraw. śc. OUTPUT: 0000 1 0 0001 000010 A 17 1 1 18 B 0 1 15 16 NP c
Przykład c.d.: A A B C D A D 4 21 19 2 2 20 Drzewo kodu: Popraw. śc. OUTPUT: 0000 1 0 0001 00 0010000 0011 kod NP kod stały D A 17 1 1 18 B 0 1 15 16 NP c
Przykład c.d.: A A B C D A D 4 21 19 2 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 0011 A 17 1 1 18 B 0 1 15 16 c 0 0 13 14 NP D
Przykład c.d.: A A B C D A D 4 21 19 2 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 0011 A 17 1 1 18 B ZAMIANA! 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 4 21 19 2 2 20 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 0011 A 1 17 2 18 B ZAMIANA! 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 4 21 20 3 2 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 0011 A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 5 21 20 3 2 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 0011 A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 5 21 20 3 2 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 00110 Uwaga: A był kodowany jako 0000, 1 a na końcu jako 0. A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 6 21 20 3 3 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 00110 A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 6 21 20 3 3 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 00110 1101 A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 6 21 ZAMIANA! 20 3 3 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 00110 1101 A 1 2 18 17 B 1 1 15 16 c 0 1 13 14 NP D
Przykład c.d.: A A B C D A D 7 21 20 4 3 19 Drzewo kodu: OUTPUT: 0000 1 0 0001 00 0010000 001101101 A 2 2 18 17 D 1 1 15 16 c 0 1 13 14 NP B
Dynamiczny Huffman: struktury danych 7 21 20 4 3 19 • 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 A 2 2 18 17 D 1 1 15 16 c 0 1 13 14 NP B
Dynamiczny Huffman: niezmiennik? Chcemy pokazać, że algorytm modyfikacji drzewa kodu zachowuje własności: • Numeracja w algorytmie v1,,v2n-1jest 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: podsumowanie Wł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