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

Podobne dokumenty