Tomasz Wykład 4: kodowanie słownikowe
Motywacja Motywacje 1 kodowane dane nie tworza ciagu wartości niezależnych, rozkład prawdopodobieństwa zależy od symboli poprzedzajacych symbol kodowany; 2 pewne sekwencje (słowa) często się powtarzaja. Słowniki statyczne: korzystamy z ustalonego słownika; tekst kodujemy jako ciag słów ze słownika, każde słowo kodowane przez jego pozycję w słowniku. Co z elementami, których brak w słowniku: można np. umieścić w nim pojedyncze litery.
Przykład: kodowanie digramowe Przykład: kodowanie digramowe słownik o ustalonej wielkości składa się ze wszystkich liter i tylu par liter, ile się w nim zmieści (wybieramy najbardziej prawdopodobne pary). przykład: dla słownika o rozmiarze 256 i alfabetu złożonego z drukowalnych znaków ASCII, których jest 95, w słowniku można umieścić161 par.
Słowniki dynamiczne Dlaczego słowniki statyczne nieskuteczne Wrażliwe na zmianę charakteru danych. Na czym polega słownik dynamiczny dostosowany do charakteru danych; tworzony w trakcie kodowania; zmienia się w trakcie kodowania; dekoder może go odtworzyć w oparciu o odkodowana część danych (nie trzeba słownika dołaczać do danych);
czyli nietypowy słownik Ziv i Lempel, 1977; Idea: słownikiem jest zakodowana/odkodowana część tekstu. Dokładniej: dla zakodowanej części x 1...x n i niezakodowanej x n+1...x m szukamy najdłuższego podsłowa x 1...x n, które jest prefiksem x n+1...x m, czyli dopasowania... i kodujemy ten prefiks poprzez wskazanie jego pozycji w x 1...x n.
Jak kodujemy dopasowanie Kodowanie dopasowania jako para (j,k), gdzie j to odległość między poczatkiem kodowanej części (pozycja n + 1) a poczatkiem dopasowania k to długość dopasowania. Przykład tekst: ABXAXABAXAXBBAB zakodowane: ABXAXABA, niezakodowane: XAXBBAB najdłuższe dopasowanie ABXAX ABAXAX BBAB kodowanie: (6, 3).
Problem 1 Co z brakiem dopasowania tekst: ABXAXABADAXBBAB zakodowane: ABXAXABA, niezakodowane: DAXBBAB najdłuższe dopasowanie: brak! rozwiazanie: (0,0,kod(D)). gdzie kod jest pewnym ustalonym kodem prefiksowym dla alfabetu wejściowego. Ogólnie Kodujemy dopasowanie przy pomocy trójki przesunięcie długość dopasowania kod symbolu występujacego za dopasowaniem w niezakodowanej części tekstu.
Kodowanie: przykłady Sytuacja typowa tekst: ABXAXABAXAXBBAB zakodowane: ABXAXABA, niezakodowane: XAXBBAB najdłuższe dopasowanie ABXAX ABAXAX BBAB kodowanie: (6, 3, kod(b)). Sytuacja nietypowa tekst: ABXAXABADAXBBAB zakodowane: ABXAXABA, niezakodowane: DAXBBAB najdłuższe dopasowanie: brak! kodowanie: (0, 0, kod(d)).
Kodowanie: przykłady Sytuacja nietypowa Zaczynamy kodowanie, czyli część zakodowana jest pusta: pierwsza literę x 1 kodujemy jako (0,0,kod(x 1 )) czyli uznajemy, że brakuje dopasowania.
Kodowanie: sytuacje nietypowe Dopasowanie wybiega poza zakodowana część tekst: ADABRARRARRAD zakodowane: ADABRAR, niezakodowane: RARRAD najdłuższe dopasowanie standardowo : ADABRARRARRAD standardowe kodowanie: (3, 3, kod(r))... można wydłużyć do 5 znaków: (3,5,kod(D))
Kodowanie ogólnie Ogólnie dla zakodowanej części x 1...x n i niezakodowanej x n+1...x m szukamy najdłuższego podsłowa x 1...x m, które zaczyna się w części x 1...x n i jest prefiksem x n+1...x m... i kodujemy ten prefiks poprzez wskazanie przesunięcia, dopasowania i znaku za dopasowaniem: (p,d,kod(x n+1+d )) gdzie x n+1 p...x n+1 p+d 1 = x n+1...x n+1+d 1.
Problemy z kodowaniem Problemy z kodowaniem trójek Efekty wartości przesunięcia z potencjalnie nieskończonego zbioru; podobnie długości dopasowania. nie możemy stosować kodów o stałej długości; długi czas poszukiwania dopasowania! konieczność przechowywania (najlepiej) w pamięci operacyjnej całej zakodowanej już części tekstu.
LZ 77 Jak na prawdę wyglada bufor słownikowy: sufiks już zakodowanej części tekstu, o ustalonym rozmiarze s; bufor kodowania: prefiks jeszcze nie zakodowanej części tekstu, o ustalonym rozmiarze t; okno: bufor słownikowy + bufor kodowania; rozmiar okna s + t. : jak kodujemy dopasowań szukamy tylko w buforze słownikowym dopasowanie nie może wybiegać poza bufor kodowania (wcześniejszy tekst): (p,d,kod(x n+1+d )) gdzie x n+1 p...x n+1 p+d 1 = x n+1...x n+1+d 1 oraz n + 1 p + d 1 n + 1 + t 1 (t: rozmiar bufora kodowania).
LZ 77: długość reprezentacji trójek Kodujemy trójkę (p, d, kod(a)) p s, a zatem można zapisać na logs bitach; d s + t, a zatem można zapisać na log(s + d) bitach;
: ostateczny algorytm kodowania Krok algorytmu Znajdź najdłuższe dopasowanie dla prefiksu bufora kodowania w buforze słownikowym: szukamy w buforze słownikowym od końca (zakładamy, że bardziej prawdopodobne sa powtórzenia w małej odległości). Zakoduj dopasowanie przy pomocy trójki: (p, d, C), gdzie: p to przesunięcie (odległość poczatku najlepszego dopasowania od bufora kodowania) d to długość dopasowania C to kod symbolu występujacego za dopasowanym prefiksem bufora kodowania Przesuń okno o d + 1 pozycji w prawo.
: przykład kodowania Przykład bufor słownikowy: s = 4; bufor kodowania: t = 4; kodowany tekst: aaaabababaaab$ aaaa bababaaab$ 0, 0, a aaaab ababaaab$ 1, 3, b aaaababab aaab$ 2, 5, a aaaabababaaab$ 4, 2, $ zielony: bufor kodowania, czerwony: bufor słownikowy.
: dekodowanie Dekodowanie Dane: Ciag trójek (p 1,d 1,kod(c 1 ))...(p n,d n,kod(c n )). Odkodowany tekst x zainicjuj jako tekst pusty. Dla i = 1,2,...,n Przetwarzaj trójkę (p i,d i,kod(c i )): do odkodowanego tekstu x = x 1...x m dołacz fragment x m pi +1...x m pi +d i c i : x x 1...x m x m pi +1...x m pi +d i c i.
: implementacja Dekodowanie Nie ma potrzeby wyszukiwania dopasowania: dekodowanie dużo prostsze. Kodowanie jak szybko można szukać dopasowań?
Szukanie dopasowań ZIP i GZIP rozmiar okna: bufor słownikowy 32KB, bufor kodowania 258 bajtów; reprezentacja słownika (czyli zawartości bufora słownikowego): tablica hashujaca pozycji poczatkowych dla ciagów 3-literowych; elementy tablicy to listy, w których na przodzie najpóźniejsze wpisy (najbliższe dopasowania); wpisy spoza bufora słownikowego usuwane ( leniwie, po odwiedzeniu ich). krotki kodowane przy pomocy algorytmu Huffmana (adaptacyjnie, dla uniknięcia 2 przebiegów); kodowanie w blokach.
Szukanie dopasowań Storer, Szymanski (w opisie LZSS) bufor kodowania w kolejce cyklicznej; wszystkie t-elementowe podsłowa bufora słownikowego w drzewie binarnym: szczegóły na ćwiczeniach.
Modyfikacje Stopień kompresji LZSS: usuwamy trzeci element, dodajemy flagę bitowa informujac a do każdej trójki, czy było niezerowe dopasowanie: jeśli nie, kodujemy tylko jeden znak jego standardowym kodem), jeśli tak, kodujeym wartości przesunięcia i długości; kompresje powstajacych trójek (Huffman, kodowanie arytmetyczne,...) lub trzeciego elementu trójki (np. w ZIP, ARJ), zmiana rozmiaru buforów w trakcie (de)kodowania.
: podsumowanie Podsumowanie oparty na założeniu: powtórzenia występuja w niedużej odległości; wiele zastosowań: zip, gzip, PNG, PKzip, arj, rar,... kodowanie bardziej kosztowne od dekodowania, możliwy kompromis między stopniem kompresji a szybkościa algorytmu.
: idea : idea Cel: odejść od założenia, że powtórzenia występuja w małej odległości. Słownik: poindeksowany zbiór słów. Zawartość słownika: tworzona w oparciu o zakodowana/odkodowan a część tekstu. Kodowanie: ciag indeksów odowiadajacych słowom ze słownika.
: Algorytm 1 Słownik zbiór pusty Aż do zakodowania całego tekstu: znajdź w- najdłuższy prefiks niezakodowanej części tekstu występujacy w słowniku, symbol występujacy w niezakodowanej części tekstu za w oznaczmy przez a, pozycję w w słowniku przez n, zakoduj wa za pomoca pary (n,kod(a)) UWAGA: jeśli pierwszy znak niezakodowanej części tekstu nie występuje w słowniku, to n = 0 dodaj do słownika słowo wa.
: przykład Tekst: T A T A T A T A T Zakodowane: Słownik: pusty
: przykład Tekst: T A T A T A T A T Zakodowane: (0, T) Słownik: 1 T
: przykład Tekst: T A T A T A T Zakodowane: (0, T) (0, A) 1 T Słownik: 2 A
: przykład Tekst: T A T A T A T A T Zakodowane: (0, T) (0, A) (1,A) 1 T Słownik: 2 A 3 TA
: przykład Tekst: T A T A T A T A T Zakodowane: (0, T) (0, A) (1,A) (3,T) 1 T 2 A Słownik: 3 TA 4 TAT
: przykład Tekst: T A T A T A T A T A T Zakodowane: (0, T) (0, A) (1,A) (3,T) (2,T) 1 T 2 A Słownik: 3 TA 4 TAT 5 AT
: dekodowanie : Algorytm dekodowania Słownik zbiór pusty Odkodowujemy pary na podstawie zawartości słownika: dla kolejnej pary (n, kod(a)) na koniec odkodowanej części tekstu dodajemy xa, gdzie x to element słownika na pozycji n; jeśli słownik nie jest pełen: po odkodowaniu xa (x - element słownika, a - znak za nim występujacy), dodajemy xa do słownika. : kodowanie a dekodowanie kodowanie: szukamy najdłuższego dopasowania do pozycji w słowniku; dekodowanie: bez szukania dopasowań, kopiujemy odpowiednie fragmenty.
: stary problem... Jak reprezentować pary pozycje w słowniku: jaki zakres? na ilu bitach? litery: ustalony kod stały. : standardowe rozwiazanie rozmiar słownika z góry ustalony; po wypełnieniu słownika, kodujemy kolejne dopasowania bez modyfikacji słownika.
: inny stary problem... Co z drugim elementem każdej pary potrzebny dla pierwszych wystapień liter w tekście; zmniejsza stopień kompresji: część tekstu kodowana bez wykorzystania kontekstu!
LZW, czyli optymalizujemy... LZW: idea zamiast pary (pozycja, litera), kodujemy tylko pozycję w słowniku znalezionego w nim prefiksu niezakodowanej części tekstu w, ALE na poczatku w słowniku umieszczamy wszystkie symbole alfabetu, bo... w przeciwnym razie nie moglibyśmy zaczać kodowania i kontynuować w momencie napotkania symbolu, od którego nie zaczyna się żadna pozycja słownika. LZW: jak rozszerzamy słownik zgodnie z : do słownika dodajemy konkatenację zakodowanego elementu słownika w i występujacego za nim znaku a.
LZW: kodowanie LZW: algorytm kodowania Umieść w słowniku wszystkie możliwe ciagi jednoliterowe (czyli litery alfabetu). Dopóki niezakodowana część tekstu nie jest pusta: znajdź w najdłuższy prefiks niezakodowanej części tekstu, który występuje w słowniku; zakoduj w jako n, jego pozycję w słowniku; dodaj do słownika wa, gdzie a jest symbolem występujacym za prefiksem w w niezakodowanej części tekstu.
LZW: przykład kodowania Tekst: T A T A T A T A T Zakodowane: 1 T Słownik: 2 A
LZW: przykład kodowania Tekst: T A T A T A T A T Zakodowane: 1 1 T Słownik: 2 A 3 TA
LZW: przykład kodowania Tekst: T A T A T A T A T Zakodowane: 1 2 1 T 2 A Słownik: 3 TA 4 AT
LZW: przykład kodowania Tekst: T A T A T A T Zakodowane: 1 2 3 1 T 2 A Słownik: 3 TA 4 AT 5 TAT
LZW: przykład kodowania Tekst: T A T A T A T Zakodowane: 1 2 3 5 1 T 2 A Słownik: 3 TA 4 AT 5 TAT
LZW: problemy z dekodowaniem LZW: dekoder wie za mało? W jednym kroku: koder dodaje do słownika słowo wa i koduje w dekoder dekoduje w, ale nie zna jeszcze a! Rozwiazanie brakujac a literę odkodujemy w następnym kroku... jest nia pierwsza litera następnego odkodowanego fragmenty... czyli pierwsza litera pozycji słownika, która odkodujemy jako następna.
LZW: przykład dekodowania Tekst: Zakodowane: 1 2 3 5 1 T Słownik: 2 A
LZW: przykład dekodowania Tekst: T Zakodowane: 1 2 3 5 1 T Słownik: 2 A 3 T?
LZW: przykład dekodowania Tekst: T A Zakodowane: 1 2 3 5 1 T 2 A Słownik: 3 T A 4 A?
LZW: przykład dekodowania Tekst: T A T A Zakodowane: 1 2 3 5 1 T 2 A Słownik: 3 T A 4 A T 5 T A? Problem: odkodowujemy pozycję 5, która nie jest do końca znana! ale zgodnie z reguła, ta pozycja jest równa pierwszej pozycji właśnie odkodowanej pozycji słownika, czyli T; zatem pozycja 5 jest równa T A T!
LZW: przykład dekodowania Tekst: T A T A T A T Zakodowane: 1 2 3 5 1 T 2 A 3 T A Słownik: 4 A T 5 T A T 6 T A T?
LZW: dekodowanie LZW: algorytm dekodowania Dane: ciag liczb p 1,...,p n. Algorytm: Umieszczamy w słowniku S wszystkie możliwe ciagi jednoliterowe (czyli litery alfabetu). Dla i = 1,2,...,n, Jeśli w poprzednim kroku do słownika dodany był element w?, to zamień go na ws pi [1] (czyli pierwsza literę ze słowa o numerze p i ) Do tekstu odkodowanego dołacz na koniec element słownika z pozycji p i, czyli S pi do słownika dodaj element S pi?.
LZW: implementacja Jak przyspieszyć wyszukiwanie Wszystkie elementy słownika przechowujemy w strukturze trie.
LZW: zastosowania compress - Unix Modyfikacje LZW: rozmiar słownika zmienny (od 512 do 2 max, gdzie max 16), na poczatku rozmiar słownika to 512 (gdy słownik jest mniejszy, stosujemy krótsze słowa kodowe!) gdy słownik pełny i spada stopień kompresji - oczyszczanie słownika. Strategie oczyszczania słownika usunięcie wszystkiego i tworzenie od nowa; usuwanie najdawniej użytej pozycji; usuwanie pozycji najwcześniej wstawionej do słownika.
LZW: zastosowania GIF=Graphics Interchange Format Modyfikacje algorytmu LZW i format danych: pierwszy bajt pliku określa b, minimalna liczbę bitów na piksel (w postaci zakodowanej) poczatkowy rozmiar słownika to 2 b+1, liczba 2 b oznacza kod oczyszczajacy (wystapienie go oznacza operację czyszczenia słownika) rozmiar słownika podwajany po wypełnieniu, do rozmiaru 4096 pozycji (mało!); potem słownik statyczny organizacja danych: podział na bloki znaków (o długości co najwyżej 255), blok zakończony kodem końca bloku, poprzedzony informacja o jego długości (możliwość pomijania fragmentów, korekcja błędów).
LZW: zastosowania Kompresja danych przesyłanych przez modem - V.42 bis Modyfikacje LZW: rezygnacja z używania pozycji słownika, które nie jest znana w momencie dekodowania; słownik o dynamicznym rozmiarze (od 512 do 2048 lub więcej) kody sterujace umożliwiajace operacje: przejście do trybu przezroczystego (bez kompresji -np. dla danych skompresowanych, losowych); oczyszczenie słownika; zwiększenie rozmiaru słownika - oczyszczanie słownika stopniowe, zaczyna się od najstarszych wpisów.