Wolna encyklopedia

Lempel-Ziv 77, skracane zwykle do LZ77 (algorytm LZ77) - metoda strumieniowej słownikowej kompresji danych. Obrazowo patrząc, metoda LZ77 wykorzystuje fakt, iż w danych powtarzają się ciągi bajtów (np. w tekstach naturalnych będą to słowa, frazy lub całe zdania) - kompresja polega na zastępowaniu powtórzonych ciągów o wiele krótszymi liczbami, wskazującymi kiedy wcześniej wystąpił ciąg i z ilu bajtów się składał; z punktu widzenia człowieka jest to informacja postaci "taki sam ciąg o długości 15 znaków wystąpił 213 znaków wcześniej".

Algorytm LZ77 jest wolny od wszelkich patentów co w dużej mierze przyczyniło się do jego popularności i szerokiego rozpowszechnienia. Doczekał się wielu ulepszeń i modyfikacji, dających albo lepsze współczynniki kompresji, albo dużą szybkość działania. Na LZ77 opiera się m.in. algorytm deflate, używany jest również w programach zip, gzip, ARJ, RAR, PKZIP, a także w formacie PNG.

Algorytm został opracowany w 1977 przez Abrahama Lempela i Jacoba Ziv i opisany w artykule "A universal algorithm for sequential data compression" opublikowanym w IEEE Transactions on Information Theory (str. 8-19)[1]. Rok później autorzy opublikowali ulepszoną wersję metody, znaną pod nazwą LZ78.

Organizacja IEEE uznała algorytm Lempel-Ziv za kamień milowy w rozwoju elektroniki i informatyki[2].

Spis treści

Zasada działania

W LZ77 zapamiętywana jest w słowniku pewna liczba ostatnio kodowanych danych - przeciętnie kilka, kilkadziesiąt kilobajtów - i jeśli jakiś ciąg powtórzy się, to zostanie zastąpiony przez liczby określające jego pozycję w słowniku oraz długość ciągu; do zapamiętania tych dwóch liczb trzeba przeznaczyć zazwyczaj o wiele mniej bitów, niż do zapamiętania zastępowanego ciągu.

Metoda LZ77 zakłada, że ciągi powtarzają się w miarę często, tzn. na tyle często, żeby wcześniejsze wystąpienia można było zlokalizować w słowniku - ciągi powtarzające się zbyt rzadko nie są brane pod uwagę. Wady tej pozbawiona jest metoda LZ78 (również opracowana przez autorów LZ77), w której - przynajmniej teoretycznie - słownik rozszerza się w nieskończoność.

Bardzo dużą zaletą kodowania LZ77 (a także innych metod słownikowych z rodziny LZ, tj. LZSS, LZ78, LZW itp.) jest to, że słownika nie trzeba zapamiętywać i przesyłać wraz z komunikatem - zawartość słownika będzie na bieżąco odtwarzana przez dekoder.

Algorytm kompresji jest bardziej złożony i trudniejszy w realizacji, niż algorytm dekompresji. W metodzie LZ77 można - regulując parametry kodera (rozmiar słownika i bufora kodowania) - wpływać na prędkość kompresji oraz zapotrzebowania pamięciowe.

Algorytm kompresji

Metoda LZ77 korzysta z bufora (okna), które logicznie podzielone jest na dwie części:

Bufor słownikowy obejmuje indeksy 0\ldots k-1, bufor wejściowy k\ldots k+n-1.

Rozmiary n i k mogą być dowolne, w praktyce dobiera się je tak, aby były całkowitą potęgą dwójki, dzięki czemu w pełni wykorzystywane są słowa bitowe przeznaczone do ich zapamiętania. Rozmiar bufora słownikowego wynosi w praktyce kilka-kilkadziesiąt kilobajtów, bufor kodowania jest dużo mniejszy. Na przykład w programie gzip słownik ma 32kB, bufor kodowania natomiast 258 bajtów.

Algorytm przebiega następująco:

Stopień kompresji LZ77 w dużej mierze zależy od długości słownika oraz długości bufora wejściowego (bufora kodowania). Programy wykorzystujące tę metodę mają zwykle możliwość ustalania rozmiaru słownika, istnieją również programy dynamicznie zmieniające rozmiar słownika.

Prędkość kompresji natomiast jest uzależniona głównie od efektywności procedury wyszukującej najdłuższy prefiks. Używane są tutaj różne rozwiązania. Np. w programie gzip używa się tablicy haszującej adresowanej pierwszymi trzema literami z bufora kodowania. Stosowane są również zwykłe tablice, a do lokalizacji prefiksu używa się algorytmów wyszukiwania wzorca, np. algorytmu Karpa-Rabina.

Jeśli słownik jest realizowany jako tablica, to aby uniknąć fizycznego, czasochłonnego przesuwania danych w oknie (punkt 3. algorytmu), używa się buforów cyklicznych.

Przykładowy krok algorytmu

1. Wyszukanie najdłuższego podciągu równego początkowi bufora wejściowego (tutaj: aac).

          słownik               |  bufor wejściowy  | nieprzetworzone symbole
  0   1   2   3   4   5   6   7 | 0   1   2   3   4 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-----
| a | a | a | a | c | c | a | b | a | a | c | b | a | c | a | b | a | c | ...
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+-----
|                      okno                         |

2. Wynik wyszukiwania:

P = 2 (pozycja w słowniku)
C = 3 (długość podciągu)
S = b (symbol z bufora wejściowego następujący po dopasowanym podciągu)

3. Przesunięcie bufora o C + 1 pozycji, dopisanie do bufora wejściowego nieprzetworzonych symboli.

          słownik               |  bufor wejściowy  | nieprzetworzone symbole
  0   1   2   3   4   5   6   7 | 0   1   2   3   4 |
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---------------------
| c | c | a | b | a | a | c | b | a | c | a | b | a | c | ...
+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---------------------

Przykład

Kilka początkowych kroków LZ77
sytuacja początkowa
inicjalizacja słownika pierwszym symbolem, wypisanie go na wyjście
przesunięcie okna o 1 pozycję w lewo
symbolu 'b' nie ma w słowniku
przesunięcie okna o 1 pozycję
znaleziono ciąg 'aa' (długość 2, pozycja 0), wypisanie dodatkowo następnego symoblu z bufora kodowania 'c'
przesunięcie okna o 2+1 pozycji
znaleziono ciąg 'baa' (długość 3, pozycja 2), wypisanie na wyjście pozycji tego ciągu oraz następnego symblu z bufora kodowania 'c'
przesunięcie okna o 3+1 pozycji
symbolu 'd' nie ma w słowniku (itd.)

Algorytm dekompresji

Dekompresja danych w metodzie LZ77 jest o wiele prostsza i szybsza niż kompresja. Do zdekodowania wymagane jest istnienie bufora (okna) o dokładnie takich samych parametrach jak przy kodowaniu - bufor podzielony jest na część słownikową obejmującą k pierwszych pozycji i bufor wyjściowy zajmujący n kolejnych pozycji.

Dekodowanie przebiega następująco:

Ad 1) Jeśli przy kompresji podciąg obejmował także bufor wejściowy, to należy bufor słownikowy tymczasowo "przedłużyć" i wypełnić brakującymi symbolami. Podciągi takie mają strukturę xYxYx, gdzie x to pojedynczy symbol, a Y ciąg znajdujący się już w buforze słownikowym. Uzupełnienie polega na cyklicznym kopiowaniu końcówki bufora słownikowego (którą obejmuje początek podciągu). Np. jeśli podciąg ma długość 8 i tylko 3 symbole bca znajdują się w słowniku, to odtworzony ciąg ma postać: bcabcabc. Nie ma potrzeby fizycznego rozszerzania słownika i kopiowania danych - wystarczy odpowiednio przeliczać indeksy.

Tego specjalnego przypadku można uniknąć na etapie kompresji, biorąc pod uwagę tylko te podciągi, które w całości znajdują się w słowniku - przy dużych rozmiarach słownika i niewielkich bufora wejściowego praktycznie nie rzutuje to na stopień kompresji i jest to rozwiązanie stosowane w rzeczywistych zastosowaniach.

Modyfikacja algorytmu

Algorytm LZ77 stał się podstawą dla wielu rozwiązań:

Przykład kompresji

Niech długość słownika i bufora wejściowego będą równe 4, tzn. n = k = 4. Do zapisu pozycji w słowniku (P) jak i długości ciągu (C) wystarczą 2 bity. Kodowany komunikat składa się z trzynastu symboli: aabbcabbcdddc.

# słownik|bufor wejściowy wyjście kodera uwagi
1 aaaa|aabb a słownik wypełniany jest pierwszym symbolem, symbol ten jest zapisywany
2 aaaa|aabb (0,2,b) w słowniku znajduje się 2-elementowy podciąg równy początkowi bufora wejściowego; bufor jest przesuwany o 3 pozycje w lewo
3 aaab|bcab (3,1,c) w słowniku znajduje się 1-elementowy podciąg równy początkowi bufora wejściowego; bufor jest przesuwany o 2 pozycje w lewo
4 abbc|abbc (0,3,c) w słowniku znajduje się 3-elementowy podciąg równy początkowi bufora wejściowego; bufor jest przesuwany o 4 pozycje w lewo
5 abbc|dddc (0,0,d) w słowniku nie ma żadnego podciągu zaczynającego się od d; bufor jest przesuwany o 1 pozycję w lewo
6 bbcd|ddc (3,2,c) w buforze znajduje się 2-elementowy podciąg równy początkowi bufora wejściowego: pierwszy element ciągu znajduje się w słowniku, drugi w buforze wejściowym; bufor jest przesuwany o 3 pozycje w lewo

Zakodowane zostało 13 symboli; symbole to przeważnie bajty (8 bitów), więc cały komunikat 13 \cdot 8 = 104 bity.

Dane wyjściowe kodera to:

Ostatecznie rozmiar skompresowanych danych wynosi 68 bitów, co daje współczynnik kompresji ok. 34%.

Przykład dekompresji

Dekompresji zostaną poddane dane otrzymane we wcześniejszym przykładzie:

# wejście dekodera słownik|bufor wyjściowy wyjście dekodera uwagi
1 a aaaa| słownik jest wypełniany początkowym symbolem
2 (0,2,b) aaaa|aab aab ze słownika do bufora wyjściowego kopiowane są 2 symbole i "doklejany" 3. symbol z trójki; bufor wyjściowy jest wyprowadzany na wyjście, a cały bufor przesuwany o 3 pozycje w lewo
3 (3,1,c) aaab|bc bc ze słownika do bufora wyjściowego kopiowany jest jeden symbol i "doklejany" 2. symbol z trójki; bufor wyjściowy jest wyprowadzany na wyjście, a cały bufor przesuwany o 2 pozycje w lewo
4 (0,3,c) abbc|abbc abbc ze słownika do bufora wyjściowego kopiowane są 3 symbole i "doklejany" 4. symbol z trójki; bufor wyjściowy jest wyprowadzany na wyjście, a cały bufor przesuwany o 4 pozycje w lewo
5 (0,0,d) abbc|d d do bufora wyjściowego wprowadzany jest tylko jeden symbol zapisany w trójce; bufor przesuwany jest o 1 pozycję w lewo
6 (3,2,c) bbcd|ddc ddc przed wypełnieniem bufora wyjściowego słownik zawiera 4 symbole: bbcd, kopiowane na wyjście mają być 2 symbole, w tym jeden nie zapisany w słowniku - istniejący symbol jest powielany i słownik na chwilę wydłużany: bbcdd; podkreślone symbole są kopiowane do bufora wyjściowego, dopisywany jest symbol z trójki, a cały bufor wyjściowy kopiowany na wyjście

Ostatecznie zdekodowany komunikat ma postać: aabbcabbcdddc.

Przypisy

  1. Praca w 1979 roku uznana przez IEEE Information Theory Society za najlepszą publikację z dziedzinie teorii informacji; Information Theory Paper Award (en). itsoc.org : IEEE Information Theory Society. [dostęp 25 września 2008].
  2. IEEE History Center: Milestones Chronological Listing (en). ieee.org : IEEE. [dostęp 25 września 2008].
  3. Sposób inicjalizacji słownika może być inny, jedyny wymóg, aby został jednakowo przeprowadzony przy kodowaniu i dekodowaniu.

Bibliografia

Zobacz też

Linki zewnętrzne

Źródło: „haslo,LZ77