Algorytm LZW
Kompresja oparta na s艂owniku u偶ywana w obrazach GIF i Unix compress.
Nowe Podej艣cie do Redundancji: Poza Pojedyncze Symbole
W naszej eksploracji kompresji bezstratnej przeanalizowali艣my metody statystyczne, takie jak kodowanie Huffmana, kt贸re w genialny spos贸b redukuj膮 rozmiar danych poprzez przypisywanie kr贸tszych kod贸w do cz臋艣ciej wyst臋puj膮cych symboli. To podej艣cie jest pot臋偶ne, ale skupia si臋 na prawdopodobie艅stwie pojedynczych znak贸w. Jednak偶e, dane w 艣wiecie rzeczywistym zawieraj膮 inny, bardziej ustrukturyzowany rodzaj nadmiarowo艣i: powtarzanie si臋 ca艂ych sekwencji, fraz i wzorc贸w. Rozwa偶my polskie zdanie "Kr贸l Karol kupi艂 kr贸lowej Karolinie korale koloru koralowego"; zbitka liter "kr贸l" pojawia si臋 dwukrotnie, a "koral" a偶 trzykrotnie. Metoda statystyczna skompresowa艂aby ka偶d膮 z tych instancji na podstawie wysokiej cz臋stotliwo艣ci liter k, r, 贸, l, ale straci艂aby okazj臋 do zauwa偶enia, 偶e ca艂a czteroliterowa sekwencja powr贸ci艂a.
Aby wykorzysta膰 ten rodzaj redundancji strukturalnej, potrzebujemy innej klasy algorytm贸w, znanych jako . Filozofia stoj膮ca za tymi metodami jest prosta i intuicyjna: po co pisa膰 t臋 sam膮 d艂ug膮 fraz臋 w k贸艂ko, skoro mo偶na po prostu wskaza膰 na miejsce, w kt贸rym napisali艣my j膮 po raz pierwszy? Jednym z najbardziej eleganckich i historycznie znacz膮cych algorytm贸w w tej rodzinie jest algorytm Lempel-Ziv-Welch, czyli LZW.
Algorytm LZW: Budowanie S艂ownika w Locie
Opracowany przez Terry'ego Welcha w 1984 roku, LZW jest ulepszeniem wcze艣niejszego algorytmu LZ78 stworzonego przez Abrahama Lempela i Jacoba Ziva. Jego geniusz tkwi w zdolno艣ci do adaptacyjnego budowania s艂ownika powtarzaj膮cych si臋 fraz podczas przetwarzania danych wej艣ciowych. Oznacza to, 偶e wymaga on tylko jednego przebiegu przez dane i, co kluczowe, nie musi przesy艂a膰 samego s艂ownika wraz ze skompresowanym wynikiem. Dekompresor jest w stanie idealnie odtworzy膰 dok艂adnie ten sam s艂ownik na podstawie samych skompresowanych danych.
Mechanizm Dzia艂ania
Algorytm LZW utrzymuje tablic臋 ci膮g贸w znak贸w, czyli s艂ownik, kt贸ry mapuje sekwencje znak贸w na kody numeryczne. Proces dzia艂a nast臋puj膮co:
- Inicjalizacja S艂ownika: S艂ownik jest wst臋pnie zape艂niony wszystkimi mo偶liwymi pojedynczymi znakami. W przypadku standardowych danych 8-bitowych oznacza to, 偶e s艂ownik pocz膮tkowo zawiera 256 wpis贸w, mapuj膮cych ka偶dy znak od kodu 0 do 255.
- Przetwarzanie Strumienia Wej艣ciowego: Algorytm odczytuje dane wej艣ciowe znak po znaku, pr贸buj膮c znale藕膰 najd艂u偶sz膮 mo偶liw膮 sekwencj臋, kt贸ra ju偶 istnieje w jego s艂owniku.
- G艂贸wna P臋tla: Za艂贸偶my, 偶e najd艂u偶sza znaleziona do tej pory sekwencja to P. Algorytm odczytuje nast臋pny znak, C. Nast臋pnie sprawdza, czy po艂膮czona sekwencja P + C istnieje w s艂owniku.
- Je艣li TAK: Sekwencja jest rozpoznana. Algorytm aktualizuje P do postaci P + C i czeka na nast臋pny znak, kontynuuj膮c poszukiwania jeszcze d艂u偶szej znanej sekwencji.
- Je艣li NIE: Osi膮gni臋to koniec rozpoznanej sekwencji. Algorytm wykonuje dwie czynno艣ci:
- Wypisuje na wyj艣cie kod numeryczny dla ostatniej znanej sekwencji, P.
- Dodaje now膮, nierozpoznan膮 sekwencj臋 P + C do s艂ownika z nast臋pnym dost臋pnym kodem numerycznym.
- Reset i Powt贸rka: Nast臋pnie algorytm resetuje si臋, rozpoczynaj膮c nowe poszukiwania od pojedynczego znaku C jako nowej pocz膮tkowej sekwencji P. P臋tla jest kontynuowana, a偶 ca艂y strumie艅 wej艣ciowy zostanie przetworzony.
Kodowanie LZW: Szczeg贸艂owy Przyk艂ad
Abstrakcyjne zasady staj膮 si臋 znacznie ja艣niejsze dzi臋ki szczeg贸艂owemu przyk艂adowi. Skompresujmy znane polskie 艂ama艅ce j臋zykowe: KR脫L KAROL KUPI艁 KR脫LOWEJ.
Krok 0: Inicjalizacja S艂ownikaNasz s艂ownik na pocz膮tku zawiera wpisy dla ka偶dego znaku z naszego alfabetu. Przypiszmy nast臋pne dost臋pne kody, zaczynaj膮c od 256. Dla uproszczenia wymie艅my tylko znaki, kt贸rych b臋dziemy u偶ywa膰: K, R, 脫, L, spacja, A, O, U, P, I, W, E, J.
Tabela Procesu KodowaniaB臋dziemy 艣ledzi膰 stan kodera krok po kroku.
| Bie偶膮ca Sekwencja (P) | Nast臋pny Znak (C) | Czy P + C jest w S艂owniku? | Kod Wyj艣ciowy | Nowy Wpis w S艂owniku |
|---|---|---|---|---|
| K | R | Nie | kod(K) | 256: KR |
| R | 脫 | Nie | kod(R) | 257: R脫 |
| 脫 | L | Nie | kod(脫) | 258: 脫L |
| L | spacja | Nie | kod(L) | 259: L spacja |
| spacja | K | Nie | kod(spacja) | 260: spacja K |
| K | A | Nie | kod(K) | 261: KA |
| A | R | Nie | kod(A) | 262: AR |
| R | O | Nie | kod(R) | 263: RO |
| O | L | Nie | kod(O) | 264: OL |
| L | spacja | Tak (259) | - | - |
| L spacja | K | Nie | 259 | 265: L spacja K |
| K | U | Nie | kod(K) | 266: KU |
| ... | ... | ... (proces jest kontynuowany) ... | ... | ... |
Wynik Ko艅cowy: Pocz膮tkowo wyj艣cie sk艂ada si臋 z kod贸w pojedynczych znak贸w. Jednak w miar臋 jak algorytm przetwarza tekst, jego s艂ownik wzbogaca si臋 o coraz d艂u偶sze, powtarzaj膮ce si臋 sekwencje (jak "KR脫L" czy "OWEJ"). Przy drugim i kolejnym wyst膮pieniu tych fraz algorytm wypisze ju偶 pojedynczy kod, reprezentuj膮cy ca艂膮 sekwencj臋, co prowadzi do znacz膮cej kompresji. Kody numeryczne by艂yby reprezentowane binarnie za pomoc膮 zmiennej liczby bit贸w; gdy s艂ownik przekroczy 511 wpis贸w, na przyk艂ad kody zmieni膮 si臋 z 9-bitowych na 10-bitowe.
Proces Dekompresji LZW
Elegancja LZW w pe艂ni ujawnia si臋 podczas dekompresji. Dekoder otrzymuje sekwencj臋 kod贸w i, zaczynaj膮c z tym samym pocz膮tkowym s艂ownikiem pojedynczych znak贸w, idealnie odtwarza oryginalny tekst. Robi to poprzez wnioskowanie o nowych wpisach s艂ownikowych z przychodz膮cych kod贸w.
Og贸lna zasada brzmi: dla ka偶dego otrzymanego kodu, wypisz na wyj艣cie ci膮g, kt贸ry on reprezentuje z bie偶膮cego s艂ownika. Nast臋pnie utw贸rz nowy wpis w s艂owniku, 艂膮cz膮c ci膮g, kt贸ry w艂a艣nie wypisa艂e艣, z pierwszym znakiem nast臋pnego ci膮gu, kt贸ry zaraz wypiszesz.
| Kod Wej艣ciowy | Ci膮g Wyj艣ciowy | Nowy Wpis w S艂owniku |
|---|---|---|
| kod(K) | K | ... |
| kod(R) | R | 256: K + R = KR |
| kod(脫) | 脫 | 257: R + 脫 = R脫 |
| kod(L) | L | 258: 脫 + L = 脫L |
| ... | ... | ... kontynuacja ... |
Istnieje specjalny przypadek, gdy dekoder otrzymuje kod, kt贸rego jeszcze nie ma w swoim s艂owniku. Dzieje si臋 to tylko wtedy, gdy sekwencja jest tworzona, a nast臋pnie natychmiast u偶ywana przez koder. Dekoder mo偶e sobie z tym poradzi膰, wiedz膮c, 偶e nieznany znak musi by膰 taki sam jak pierwszy znak poprzednio wypisanego ci膮gu. To zapewnia, 偶e synchronizacja "krok w krok" mi臋dzy koderem a dekoderem nigdy nie zostaje zerwana.
Zastosowanie w Praktyce: Format Obraz贸w GIF
LZW sta艂 si臋 powszechnie znany dzi臋ki swojej implementacji w formacie GIF (Graphics Interchange Format). Jest on szczeg贸lnie dobrze dopasowany do tego formatu z kilku powod贸w:
- Ograniczona Paleta Kolor贸w: Obrazy GIF s膮 ograniczone do maksymalnie 256 kolor贸w. Algorytm LZW nie operuje na surowych warto艣ciach kolor贸w, ale na 8-bitowych warto艣ciach indeks贸w, kt贸re wskazuj膮 na kolor w palecie. Oznacza to, 偶e pocz膮tkowy rozmiar s艂ownika jest ma艂y i sta艂y.
- Redundancja Przestrzenna: Obrazy generowane komputerowo, takie jak logotypy czy diagramy, cz臋sto maj膮 du偶e obszary jednolitego koloru lub powtarzaj膮ce si臋 wzory. Gdy dane obrazu s膮 odczytywane linia po linii, te wzory przestrzenne zamieniaj膮 si臋 w d艂ugie, powtarzalne sekwencje indeks贸w kolor贸w w strumieniu wej艣ciowym, kt贸re LZW potrafi bardzo skutecznie kompresowa膰.
Mocne Strony, S艂abo艣ci i Dziedzictwo
Dziedzictwo LZW w 艣wiecie kompresji jest znacz膮ce, ale wa偶ne jest r贸wnie偶 zrozumienie jego kompromis贸w.
Mocne Strony
- Algorytm Jednoprzebiegowy: Nie musi analizowa膰 ca艂ego pliku z g贸ry. Buduje sw贸j model adaptacyjnie, co czyni go odpowiednim do zastosowa艅 strumieniowych.
- Brak Transmisji S艂ownika: Zdolno艣膰 dekompresora do odbudowy s艂ownika jest g艂贸wn膮 zalet膮, eliminuj膮c膮 znacz膮cy narzut.
- Wzgl臋dna Prostota i Szybko艣膰: Algorytm jest koncepcyjnie prosty i generalnie szybki, zw艂aszcza podczas dekompresji.
S艂abo艣ci
- Problem Pe艂nego S艂ownika: S艂ownik ma sta艂y rozmiar (np. 4096 wpis贸w dla kod贸w 12-bitowych). Je艣li dane wej艣ciowe s膮 bardzo zr贸偶nicowane, s艂ownik mo偶e si臋 zape艂ni膰. R贸偶ne implementacje radz膮 sobie z tym na r贸偶ne sposoby: niekt贸re przestaj膮 dodawa膰 nowe wpisy, inne resetuj膮 s艂ownik, a jeszcze inne u偶ywaj膮 bardziej z艂o偶onych strategii czyszczenia. Mo偶e to wp艂ywa膰 na wydajno艣膰 kompresji.
- Wra偶liwo艣膰 na B艂臋dy: Pojedynczy b艂膮d bitu w skompresowanym strumieniu kod贸w mo偶e spowodowa膰, 偶e s艂ownik dekompresora straci synchronizacj臋 ze s艂ownikiem kodera, co prowadzi do katastrofalnej awarii dekompresji od tego momentu.
- Historia Patentowa: Przez wiele lat algorytm LZW by艂 chroniony patentami, w szczeg贸lno艣ci patentem nale偶膮cym do firmy Unisys. Doprowadzi艂o to do kontrowersji i problem贸w licencyjnych, zw艂aszcza dla formatu GIF, i pobudzi艂o rozw贸j wolnych od patent贸w alternatyw, takich jak format PNG, kt贸ry u偶ywa algorytmu Deflate (kombinacja LZ77 i kodowania Huffmana).
Cho膰 teraz wolny od ogranicze艅 patentowych, LZW zosta艂 w du偶ej mierze wyparty przez bardziej zaawansowane warianty LZ i inne algorytmy, takie jak Deflate. Jednak jego historyczne znaczenie jest niezaprzeczalne, a jego podstawowe zasady adaptacyjnej kompresji s艂ownikowej pozostaj膮 kamieniem w臋gielnym redukcji danych bezstratnych.