Kompresja danych
Transkrypt
Kompresja danych
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 nbajtowych 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? – log2 n Przykład: {a, b, c, d, e}; 5 znaków – log2 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, pi prawdopodobieństwem występowania (częstością) i-tego znaku alfabetu. Wtedy entropia określona jest wzorem: n H = ∑ − pi log 2 pi i =1 14 Przykład znak a b c d e częstość 4 5 2 1 1 4 + 5 + 2 + 1 + 1 H = − 4 log 2 5 log 2 2 log 2 log 2 log 2 13 13 13 13 13 15 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ę częstoś stości f [ ] wyjście:: drzewo kodó kodów optymalnych dla C HUFFMAN(C, f ) n ← |C| Q←C for i ← 1 to nn-1 z ← NewNew-Node( ) x ← z.left ← GETGET-MIN(Q) y ← z.right ← GETGET-MIN(Q) f [z] ← f [x] + f [y] INSERT(Q, z) return GETGET-MIN(Q) Czas wykonania O(n lg n) 18 Kody Huffmana Przykład kodowania Huffmana: –tekst: Kodowanie Huffmana –Jest adaptowane dla każdego tekstu –Składa się z • Słownika, mapującego każdą literę tekstu na ciąg binarny • Kod binarny (prefix-free) Prefix-free –Korzysta się z łańcuchów o zmiennej długości s1,s2,...,sm , takich że żaden z łańcuchów si nie jest prefixem sj m a n a m t i a m p i a p t i znak częstość kod a 5 10 i 4 01 p 3 111 m 2 000 t 2 001 n 2 110 Zakodowany tekst: a p i 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 kod a 10 i 01 p 111 m 000 t 001 n 110 częstość a 5 i 4 p 3 m 2 t 2 n 2 1 Zbuduj kod z oznaczeń gałęzi znak znak 0 18 10 1 8 0 0 1 5 1 3 0 2 p 111 n 1 5 4 a 110 10 2 4 0 2 i t m 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 + ∑ si i =1 n- ilość znaków, Si – 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 c = .3 0.7 i −1 f (i ) = ∑ p( j ) j =1 b = .5 0.2 0.0 f(a) = .0, f(b) = .2, f(c) = .7 a = .2 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: l1 = f 1 li = li −1 + si −1 f i s1 = p1 si = si −1 pi Po każdym znaku przedział jest zawężany o współczynnik pi. Ostateczny rozmiar komunikatu to: n sn = ∏ pi i =1 Wynikowy przedział dla komunikatu nazywany jest przedziałem sekwencji 24 Przykład Kodujemy komunikat: bac 1.0 0.7 c = .3 0.7 c = .3 0.55 0.0 a = .2 0.3 0.2 c = .3 0.27 b = .5 b = .5 0.2 0.3 a = .2 b = .5 0.21 a = .2 0.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 c = .3 0.7 0.49 c = .3 0.55 0.49 b = .5 0.2 0.0 0.55 0.7 0.2 c = .3 b = .5 b = .5 0.35 0.3 a = .2 0.49 0.475 a = .2 a = .2 0.3 Komunikat to bbc. 27 Reprezentacja przedziału Ułamkowa reprezentacja binarna: .75 1/ 3 11 / 16 =.11 =.0101 =.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: .11 .101 min .110 .1010 max interval .111 [.75,10 . ) .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 Przedział komunikatu .75 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 0 –Pozwala na efektywne kodowanie Struktura –Krawędzie oznaczone przez litery m a n i t –Węzły ponumerowane Mapowanie 1 2 3 8 9 –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 p p m n t t • 1 = “m” • 6 = “at” 4 5 6 7 11 10 –W przeciwnym kierunku: każde słowo prowadzi do pewnego liścia kodowanie “manamanatapitipitipi” i –(albo przynajmniej jakiś prefix musi –1,2,3,4,5,6,7,8,9,10,11,12 lub prowadzić do liścia) –1,5,4,5,6,7,11,10,11,10,8 • “it” = 11 12 • “manaman” - “m” prowadzi do 1 Dekodowanie 5,11,2 –“an”, “it”, “a” = anita 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 b c d a b c d ... z z przykład: nanananananana a n a ... n ... a na 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”, ... przykład: nanananananana a n LZW-Trie-Builder(T) ... a ... n 1. n ← length(T) a 2. i ← 1 po: nanananananana 3. TRIE ← start-TRIE na 4. m ← ilość węzłów w TRIE 5. u ← root(TRIE) 6. while i ≤ n do dalej po: 7. if brak krawędzi oznaczonej T[i] poniżej u then na 8. m ← m+1 nanananananana 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] pozostało do przeczytania: 13. i ← i +1 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) 0 2. i ← 1 3. TRIE ← start-TRIE m n a 4. m ← ilość węzłów w TRIE i t p 5. u ← root(TRIE) m n a i t p 6. while i ≤ n do 7. if brak krawędzi oznaczonej T[i] poniżej u then 8. output (u,T[i]) a a t p t p i 9. m ← m+1 10. dołącz liść m do u z etykietą krawędzi T[i] 256 257 259 260 261 262 264 11. u ← root(TRIE) 12. else n i 13. u ← węzeł poniżej u z etykietą krawędzi T[i] 14. i ← i +1 258 263 15. od Kodowanie dla m a n a m a n a t a p i t i p i t i p i 16. if u ≠ root(TRIE) then 17. output (u) (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 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 0 m n m n a a a a t t i p t t p p i 256 257 259 260 261 262 264 n i 258 Kodowanie dla (m,a) (n,a) 256 257 ma na p i 263 manamana tapitipitipi (256,n) 258 (ma)n (a,t) 259 at (a,p) 260 ap (i,t) (i,p) (261,i) (p,i) 261 262 264 264 it ip (it)i pi 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 K1(x) i K2(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: K1(x) ≤ K2(x) + c 40 Dowód własnści Dowód: Niech M1 będzie poszukiwanym programem dla x w pierwszym języku Niech U będzie uniwersalnym programem w drugim języku symulującym maszynę M1 dla pierwszego języka Wyjściem U(M1,εε) będzie wtedy x Można więc znaleźć maszynę M2 o długości |U|+|M1|+O(1) o tej samej funkcjonalności co U(M1,εε) – z lematu o translacji (twierdzenie Smn) 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