Wykład 5 Kompresja danych 1
Metody kompresji - przegląd Co to jest kompresja danych Definicje Kompresja bezstratna i stratna Kody o stałej i zmiennej długości Entropia i warunek Shannon a Metody kodowania Kody Huffmana Kodowanie arytmetyczne Kody Lempel a-ziv a (LZW) Poszukiwanie w tekście kodowanym Złożoność Kołmogorowa 2
Co to jest kompresja danych? Przetworzenie danych do bardziej zwartej postaci Powinny zajmować mniej miejsca niż poprzednio Po co kompresować dane? Oszczędność przy składowaniu danych (HDD, etc.) Bardziej efektywne przesyłanie (sieci komputerowe) 3
Co to jest kompresja tekstu? Zadanie: Mamy tekst s Σ n Chcemy znaleźć wersję skompresowaną tego tekstu c Σ m, takąże m < n Taką, że możliwe jest odtworzenie s na podstawie c Czyli: Szukamy odwracalnej funkcji kompresji f : Σ * Σ * Fakt: Większości tekstów nie da się efektywnie skompresować Dowód: Można skonstruować ( Σ m+1-1)/( Σ -1) o łańcuchów długości nie przekraczającej m Istnieje Σ n łańcuchów o długości n Czyli tylko Σ m-n+1 /( Σ -1)-ta część łańcuchów znajduje jednoznaczny odpowiednik Np. dla Σ = 256 i m=n-10 daje 8.3 10-25 A to oznacza, ze tylko ok. 8.3 10-25 cześć wszystkich plików n- bajtowych może zostać skompresowania do rozmiaru n-10 4
Czemu zatem udaje się kompresować teksty? Zwykle litery w tekście występują ze zróżnicowaną częstością Dla j. angielskiego(cryptographical Mathematics, Robert E. Lewand): e: 12%, t: 10%, a: 8%, i: 7%, n: 7%, o: 7%... k: 0.4%, x: 0. 2%, j: 0. 2%, q: 0. 09%, z:0. 06% Znaki specjalne ($,%,#) występują rzadko Niektóre znaki występują sporadycznie (są właściwie niewykorzystywane), np. początkowe znaki kodu ASCII Teksty (pliki) podlegają pewnym regułom Słowa się powtarzają (występują jedynie słowa z pewnego słownika) Nie każda kombinacja słów jest możliwa Zdania mają określoną strukturę (gramatyka) Programy korzystają z określonych słów (elementy języka programowania) Wzorce są często powielane Obrazy kodowane cyfrowo mają jednolite obszary (bez zmian koloru) 5
Najprostszy przykład Przyjmijmy, że kod znaku w ASCII zajmuje 1 bajt Przypuścimy, że mamy tekst składający się ze 100 znaków a Tekst powinien zajmować 100 bajtów Przechowując tekst w postaci 100a możemy dostać dokładnie taką samą informację Rozmiar nowego pliku wyniesie 4 bajty Oszczędność: 4/100 96% 6
Kompresja bezstratna W 100% odwracalna, poprzez dekompresję można odzyskać oryginalne dane Poprzedni przykład pokazywał taką kompresję Musi być stosowana tam, gdzie istotna jest integralność danych Przykłady oprogramowania: winzip, gzip, compress, bzip, GIF 7
Kompresja stratna stratna oznacza, że oryginalna informacja nie może być w całości odzyskana Zmniejsza rozmiar przez permanentne usunięcie pewnej części informacji Po dekompresji dostajemy jedynie część początkowej informacji (ale użytkownik może tego wcale nie zauważyć) kiedy stosujemy metody kompresji stratnej? dla plików audio, obrazów, video formaty: jpeg, mpeg 8
Kody Metody reprezentacji informacji Kod dla pojedynczego znaku często nazywany jest słowem kodowym Dla kodów binarnych Każdy znak reprezentowany jest przez unikalne binarne słowo kodowe Kody o stałej długości słowa Długość słowa kodowego dla każdego znaku jest taka sama Np. ASCII, Unicode 9
Kody o stałej długości Przypuśćmy, ze mamy n znaków Jaka jest minimalna ilość bitów dla kodów o stałej długości? log 2 n Przykład: {a, b, c, d, e}; 5 znaków log 2 5 = 2.3 = 3 bity na znak Możemy zakodować np. tak: a=000, b=001, c=010, d=011, e=100 10
Kody o zmiennej długości Długość słowa kodowego może być różna dla różnych znaków Znaki występujące częściej dostają krótsze kody Znaki występujące sporadycznie dostają długie kody Przykład: a b c d e f częstość 46 13 12 16 8 5 kod 0 101 100 111 1101 1100 11
Kody o zmiennej długości Musimy mieć pewność, że żadne słowo kodowe nie występuje jako prefix innego Potrzebujemy kodów typu prefixowego (prefix-free) Ostatni przykład taki był Kody prefix-free pozwalają na jednoznaczne dekodowanie Np.: 001011101 odpowiada w poprzednim przykładzie ciągowi aabe Metoda Huffmana jest przykładem konstrukcji takiego kodu (będzie pokazana później) 12
Entropia Entropia jest jednym z podstawowych pojęć teorii informacji Za ojca teorii informacji uważa się Claude a E. Shannona, który prawdopodobnie po raz pierwszy użył tego terminu w 1945 roku, w swojej pracy zatytułowanej "A Mathematical Theory of Cryptography". Natomiast w 1948 roku, w kolejnej pracy pt. "A Mathematical Theory of Communication" przedstawił najważniejsze zagadnienia związane z tą dziedziną nauki. Entropia pokazuje, ze istnieje ograniczenie dla bezstratnej kompresji 13
Entropia Ta granica jest nazywana entropia źródła H H określa średnią liczbą bitów niezbędną dla zakodowania znaku Niech n będzie rozmiarem alfabetu, p i prawdopodobieństwem występowania (częstością) i-tego znaku alfabetu. Wtedy entropia określona jest wzorem: H = n p log p i 2 i i= 1 14
15 Przykład 1 d 1 2 5 4 częstość e c b a znak 13 1 log 13 1 log 13 2 2 log 13 5 5 log 13 4 log 4 2 2 2 2 2 + + + + = H
Algorytm kodowania Huffmana Huffman wymyślił sprytną metodę konstrukcji optymalnego kody prefixowego (prefix-free) o zmiennej długości słów kodowych Kodowanie opiera się o częstość występowania znaków Optymalny kod jest przedstawiony w postaci drzewa binarnego Każdy węzeł wewnętrzny ma 2 potomków Jeśli C jest rozmiarem alfabetu to ma ono C liści i C -1 węzłów wewnętrznych 16
Algorytm kodowania Huffmana Budujemy drzewo od liści (bottom-up) Zaczynamy od C liści Przeprowadzamy C -1 operacji łączenia Niech f [c] oznacza częstość znaku c w kodowanym tekście Wykorzystamy kolejkę priorytetową Q, w której wyższy priorytet oznacza mniejszą częstotliwość znaku: GET-MIN(Q) zwraca element o najniższej częstości i usuwa go z kolejki 17
Algorytm Huffmana wejście: alfabet C i często stości f [ ] wyjście: drzewo kodów optymalnych dla C HUFFMAN(C, f ) n C Q C for i 1 to n-1 z New-Node( Node( ) x z.left GET-MIN(Q) y z.right GET-MIN(Q) f [z] f [x] + f [y] INSERT(Q, z) return GET-MIN(Q) Czas wykonania O(n lg n) 18
Kody Huffmana Kodowanie Huffmana Jest adaptowane dla każdego tekstu Przykład kodowania Huffmana: tekst: Składa się z m a n a m a m a p a Słownika, mapującego każdą literę tekstu na ciąg binarny Kod binarny (prefix-free) t i p i t i p i Prefix-free Korzysta się z łańcuchów o zmiennej długości s 1,s 2,...,s m, takich że żaden z łańcuchów s i nie jest prefixem s j znak a i częstość 5 4 kod 10 01 p 3 111 m 2 000 t 2 001 Zakodowany tekst: n 2 110 000 10 110 10 000 10 000 10 111 10 001 01 111 01 001 01 111 01 m a n a m a m a p a t i p i t i p i 19
Budowanie kodów Huffmana Znajdujemy częstości znaków Tworzymy węzły (wykorzystując częstości) powtarzaj Stwórz nowy węzeł z dwóch najrzadziej występujących znaków (połącz drzewa) Oznacz gałęzie 0 i 1 znak a i p m t n częstość 5 4 3 2 2 2 Zbuduj kod z oznaczeń gałęzi znak kod a 10 i 01 p 111 m 000 t 001 n 110 1 1 5 0 10 1 0 18 0 1 3 2 5 4 2 2 8 0 4 1 0 p n a i t m 111 110 10 01 001 000 20
Poszukiwanie w kodach Huffmana Niech u będzie rozmiarem skompresowanego tekstu Niech v będzie rozmiarem wzorca (zakodowanego na podstawie słownika) KMP może odnaleźć wzorzec w kodach Huffmana w czasie O(u+v+m) Zakodowanie wzorca zajmie O(v+m) kroków Budowanie prefixów zajmie czas O(v) Poszukiwanie na poziomie bitowym zajmie czas O(u+v) Problem: Algorytm rozważa bity, a można działać na poziomie bajtów 21
Kodowanie arytmetyczne - wprowadzenie Pozwala na mieszanie bitów w sekwencji komunikatu Pozwala na redukcję bitów potrzebnych do kodowania do poziomu: n l < 2 + s i i= 1 n- ilość znaków, S i ilość wystąpień i-tego znaku Wykorzystuje się je w PPM, JPEG/MPEG (opcja), DMM 22
Kodowanie arytmetyczne (przedziały) Dla każdego znaku komunikatu przypisujemy podprzedział przedziału [0,1). np. bacbabcbcb 1.0 0.7 0.2 0.0 c =.3 b =.5 a =.2 i 1 j= 1 f ( i) = p( j) f(a) =.0, f(b) =.2, f(c) =.7 Dla każdego komunikatu przedział ten nazywa się przedziałem komunikatu(dla b jest to w przykładzie[.2,.7)) 23
Kodowanie arytmetyczne (kolejne przedziały) Kodując komunikat korzystamy z zależności: l = f l = l s f 1 1 + 1 1 s = p s = s p i i i i 1 1 i i 1 i Po każdym znaku przedział jest zawężany o współczynnik p i. Ostateczny rozmiar komunikatu to: s n = n i= 1 Wynikowy przedział dla komunikatu nazywany jest przedziałem sekwencji p i 24
Przykład Kodujemy komunikat: bac 1.0 0.7 c =.3 0.7 0.55 c =.3 0.3 0.27 c =.3 b =.5 b =.5 b =.5 0.2 0.0 a =.2 0.3 0.2 a =.2 0.21 0.2 a =.2 Wynikowy przedział to [.27,.3) 25
Przedział komunikatu jest unikalny Istotna własność: przedziały wynikowe dla różnych komunikatów o długości n są zawsze rozłączne Stąd: podanie dowolnej liczby z przedziału komunikatu jednoznacznie identyfikuje ten komunikat Dekodowanie jest procesem podobnym do kodowania, odczytujemy znak i zawężamy przedział 26
Przykład dokodowania Dekodujemy liczbę 0.49, znamy początkowe przedziały i długość komunikatu 3: 1.0 0.7 0.49 c =.3 b =.5 0.7 0.55 0.49 c =.3 b =.5 0.55 0.49 0.475 c =.3 b =.5 0.2 0.0 a =.2 0.3 0.2 a =.2 0.35 0.3 a =.2 Komunikat to bbc. 27
Reprezentacja przedziału Ułamkowa reprezentacja binarna:. 75 =. 11 1/ 3 =. 0101 11/ 16 =. 1011 Tak więc możemy korzystać z krótszej ułamkowej reprezentacji binarnej dla wartości z przedziału dla komunikatu. np. [0,.33) =.01 [.33,.66) =.1 [.66,1) =.11 28
Reprezentacja przedziału Ułamki binarne można uważać za reprezentację przedziałów: min max interval. 11. 110. 111 [. 75, 10. ). 101. 1010. 1011 [. 625,. 75) Będziemy to nazywać przedziałem kodowym. Lemat: Jeśli zbiór przedziałów kodowych jest parami rozłączny, odpowiadające im kodowanie tworzy kod prefixowy. 29
Wybór przedziałów kodowania Aby utworzyć kod prefixowy znajdujemy takie ułamki binarne, dla których przedziały kodowe zawierają się w przedziałach komunikatów..79.75 Przedział komunikatu Przedział kodowy (.101).61.625 np. [0,.33) =.00 [.33,.66) =.100 [.66,1) =.11 30
Kody Ziv-Lempel-Welch (LZW) Kody z tej rodziny (Ziv-Lempel-Family) LZ77, LSZZ, LZ78, LZW, LZMZ, LZAP Literatura LZW: Terry A. Welch: "A Technique for High Performance Data Compression", IEEE Computer vol. 17 no. 6, Juni 1984, p. 8-19 LZ77 J. Ziv, A. Lempel: "A Universal Algorithm for Sequential Data Compression", IEEE Transactions, p. 337-343 LZ78 J. Ziv, A. Lempel: "Compression of Individual Sequences Via Variable-Rate Coding", IEEE Transactions on Information, p. 530-536 Znane jako komenda Unix a: compress Wykorzystują: Struktury drzewiaste - TRIE 31
Trie = retrieval TREE Drzewo Przechowuje tekst/pozwala zakodować tekst Pozwala na efektywne kodowanie Struktura Krawędzie oznaczone przez litery Węzły ponumerowane Mapowanie Każda krawędź koduje słowo tekstu Tekst dla węzła odczytywany z krawędzi po drodze od korzenia do tego węzła 1 = m 6 = at W przeciwnym kierunku: każde słowo prowadzi do pewnego liścia (albo przynajmniej jakiś prefix musi prowadzić do liścia) it = 11 manaman - m prowadzi do 1 0 m a n i t 1 2 3 8 9 m n t p t p 4 5 6 7 11 10 kodowanie manamanatapitipitipi 1,2,3,4,5,6,7,8,9,10,11,12 lub 1,5,4,5,6,7,11,10,11,10,8 Dekodowanie 5,11,2 an, it, a = anita i 12 32
Budowa drzewa TRIE przy pomocy LZW LZW Pracuje na poziomie bajtów Rozpoczynamy od drzewa o 256 liściach a, b,... oznaczonych a, b,... LZW-Trie-Builder(T) 1. n length(t) 2. i 1 3. TRIE start-trie 4. m ilość węzłów w TRIE 5. u root(trie) 6. while i n do 7. if brak krawędzi oznaczonej T[i] poniżej u then 8. m m+1 9. dołącz liść m do u z etykietą krawędzi T[i] 10. u root(trie) 11. else 12. u węzeł poniżej u z etykietą krawędzi T[i] 13. i i +1 a a b b - c c d d z... z przykład: nanananananana a a... a na - n n po przeczytaniu: na... 33
Budowa drzewa TRIE przy pomocy LZW LZW Pracuje na poziomie bajtów Rozpoczynamy od drzewa o 256 liściach a, b,... LZW-Trie-Builder(T) 1. n length(t) 2. i 1 3. TRIE start-trie 4. m ilość węzłów w TRIE 5. u root(trie) 6. while i n do 7. if brak krawędzi oznaczonej T[i] poniżej u then 8. m m+1 9. dołącz liść m do u z etykietą krawędzi T[i] 10. u root(trie) 11. else 12. u węzeł poniżej u z etykietą krawędzi T[i] 13. i i +1 przykład: nanananananana a a... po: nanananananana dalej po: nanananananana a - n na n na... pozostało do przeczytania: nanananananana 34
Kodowanie za pomocą LZW LZW-Encoder(T) 1. n length(t) 2. i 1 3. TRIE start-trie 4. m ilość węzłów w TRIE 5. u root(trie) 6. while i n do 7. if brak krawędzi oznaczonej T[i] poniżej u then 8. output (u,t[i]) 9. m m+1 10. dołącz liść m do u z etykietą krawędzi T[i] 11. u root(trie) 12. else 13. u węzeł poniżej u z etykietą krawędzi T[i] 14. i i +1 15. od 16. if u root(trie) then 17. output (u) start-trie = 256 liści zakodowanych jako 0,1,2,..,255 35
Przykład kodowania LZW LZW-Encoder(T) 1. n length(t) 2. i 1 3. TRIE start-trie 4. m ilość węzłów w TRIE 5. u root(trie) 6. while i n do 7. if brak krawędzi oznaczonej T[i] poniżej u then 8. output (u,t[i]) 9. m m+1 10. dołącz liść m do u z etykietą krawędzi T[i] 11. u root(trie) 12. else 13. u węzeł poniżej u z etykietą krawędzi T[i] 14. i i +1 15. od 16. if u root(trie) then 17. output (u) a m m a 256 257 n 258 n n t 0 a p i i t 261 t p t 262 Kodowanie dla m a n a m a n a t a p i t i p i t i p i (m,a) (n,a) (256,n) (a,t) (a,p) (i,t) (i,p) (261,i) (p,i) 256 257 258 259 260 261 262 264 264 ma na (ma)n at ap it ip (it)i pi a 259 260 i 263 p i p 264 36
Dekoder LZW-Decoder(Code) 1. i 1 2. TRIE start-trie 3. m 255 4. for i 0 to 255 do C(i)= i od 5. while not end of file do 6. (u,c) read-next-two-symbols(code); 7. if c exists then 8. output (C(u), c) 9. m m+1 10. dołącz liść m do krawędzi c 11. C(m) (C(u),c) 12. else 13. output (C(u)) 14. od Dla ostatniego łańcucha kodu nie tworzy się nowego węzła w drzewie, ale wyprowadza łańcuch a m m a 256 257 n 258 n n t 0 a p i i t 261 t p t 262 Kodowanie dla m a n a m a n a t a p i t i p i t i p i (m,a) (n,a) (256,n) (a,t) (a,p) (i,t) (i,p) (261,i) (p,i) 256 257 258 259 260 261 262 264 264 ma na (ma)n at ap it ip (it)i pi a 259 260 i 263 p p i 264 37
Złożoność obliczeniowa LZW Kodowanie może być realizowane w czasie O(n) n długość kodowanego tekstu Dekodowanie może być realizowane w czasie O(n) n długość nieskompresowanego tekstu tekstu Pamięć potrzebna do kodowania jest liniowo zależna od rozmiaru zakodowanego tekstu LZW można łatwo implementowana sprzętowo Software nie jest opatentowany Bardzo popularny, np. compress dla UNIX-a LZW możne powtórnie kodować np. kodami Huffmana Poszukiwanie w kodach LZW jest kłopotliwe Kody oparte o tekst (adaptatywne) Dla poszukiwania w zakodowanym tekście istnieje liniowa ilość możliwości zakodowania wzorca 38
Poszukiwanie idealnego kodowania Przykład: rozważmy tekst 128 bajtowy: abbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba abbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabbaabba Można go zakodować przy pomocy 16 bajtów (plus dodatkowy bajt na słownik): 0110011001100110011001100110011001100110011001100110011001100110 0110011001100110011001100110011001100110011001100110011001100110 To nie jest najlepszy możliwy sposób kodowania takiego tekstu np. korzystając z formy (abba)^32 można zrobić to przy pomocy 9 bajtów Idealny kod: Samorozpakowujący się program dla łańcucha x (wykonuje się bez wejścia, na wyjściu produkuje x) Tak więc minimalny taki program będzie tym, czego szukamy Złożoność Kołmogorowa K(x) dla łańcucha x podaję długość takiego programuj dla x 39
Złożoność Kołmogorowa Czy złożoność Kołmogorowa zależy od języka programowania? Nie, o ile język jest uniwersalny, tj. program może być symulowany na maszynie Turinga Własność: Niech K 1 (x) i K 2 (x) oznaczają złożoności Kołmogorowa dla dwóch uniwersalnych języków programowania. Wtedy istnieje stała c, taka że dla każdego łańcucha x: K 1 (x) K 2 (x) + c 40
Dowód własnści Dowód: Niech M 1 będzie poszukiwanym programem dla x w pierwszym języku Niech U będzie uniwersalnym programem w drugim języku symulującym maszynę M 1 dla pierwszego języka Wyjściem U(M 1,ε) będzie wtedy x Można więc znaleźć maszynę M 2 o długości U + M 1 +O(1) o tej samej funkcjonalności co U(M 1,ε) z lematu o translacji (twierdzenie S mn ) Ponieważ U ma niezmienny rozmiar więc maszyna ta spełnia założenia lematu. 41
Algorytm Amira, Bensona i Faracha Let Sleeping Files Lie Pomysł Zbudować drzewo LZW-Trie, ale nie dekodować Skorzystać z KMP-Matcher dla węzłówt LZW-Trie Przygotować strukturę danych w oparciu o wzorzec m Wtedy czytać tekst i modyfikować tę strukturę Cel: czas wykonania O(n + f(m)) gdzie n długość kodu f(m) pewien wielomian zależny od wzorca m Dla dobrze skompresowanego kodu i f(m)<n powinno to by c szybsze niż dekodowanie i przeszukiwanie zdekodowanego tekstu 42