Tomasz Wykład 6: kodowanie gramatykowe
Sequitur: wprowadzenie Sequitur 1 Autorzy: Nevill-Manning, Witten: 1996.
Sequitur: wprowadzenie Sequitur 1 Autorzy: Nevill-Manning, Witten: 1996. 2 Reprezentacja danych: gramatyka bezkontekstowa generujaca jeden napis (bez cykli ).
Sequitur: wprowadzenie Sequitur 1 Autorzy: Nevill-Manning, Witten: 1996. 2 Reprezentacja danych: gramatyka bezkontekstowa generujaca jeden napis (bez cykli ). 3 Skad gramatyka: tworzona dynamicznie, na podstawie tekstu (wnioskowana).
Sequitur: wprowadzenie Sequitur 1 Autorzy: Nevill-Manning, Witten: 1996. 2 Reprezentacja danych: gramatyka bezkontekstowa generujaca jeden napis (bez cykli ). 3 Skad gramatyka: tworzona dynamicznie, na podstawie tekstu (wnioskowana). 4 Kompresja: gramatyka wykorzystuje powtarzalność na wielu poziomach (słów, zdań, etc.) gramatykę trzeba sprytnie zakodować.
Sequitur: wprowadzenie Sequitur 1 Autorzy: Nevill-Manning, Witten: 1996. 2 Reprezentacja danych: gramatyka bezkontekstowa generujaca jeden napis (bez cykli ). 3 Skad gramatyka: tworzona dynamicznie, na podstawie tekstu (wnioskowana). 4 Kompresja: gramatyka wykorzystuje powtarzalność na wielu poziomach (słów, zdań, etc.) gramatykę trzeba sprytnie zakodować. 5 Dodatkowe korzyści: odkrywamy strukturę dokumentu.
Gramatyki bezkontekstowe Poczatki i motywacje Pojęcia Chomsky 1959: narzędzie opisu gramatyki języków naturalnych. Backus 1959: generowanie i parsowania programów w Fortranie. nieterminale N (oznaczamy dużymi literami); terminale T (oznaczamy małymi literami); symbol startowy (nieterminal): S. produkcje: X Y 1...Y p, gdzie X to nieterminal, Y 1,...,Y p to symbole z N T.
CFL: przykład Przykład: poprawne nawiasowania S S + S S ε S (S) S 0 1 nieterminale: S; terminale: +, 0, 1 Kiedy język skończony? nie istnieje cykl prowadzacy od X do X dla nieterminala X. dla każdego X: tylko jedna produkcja z X po lewej stronie.
Schemat kompresji gramatykowej RYSUNEK
Sequitur: niezmienniki Warunki utrzymywane w sequitur Unikalność digramów: żadna para sasiednich symboli (digram) nie występuje w gramatyce więcej niż jednokrotnie. Użyteczność produkcji: każda produkcja użyta więcej niż jeden raz. Sequitur: zasada zaczynamy od gramatyki generujacej słowo puste; po i-tym kroku gramatyka generuje prefiks tekstu o długości i; po każdym kroku modyfikujemy gramatykę, dopóki niespełnione reguły: unikaność digramów i użyteczność produkcji.
Sequitur: algorytm kodowania Sequitur: kodowanie Dane: tekst x 1...x n Algorytm: Utwórz gramatykę S ε Dla i = 1,...,n: Dodaj kolejny symbol (operacje wejściowe): S Y zamień na S Yx i Dopóki nie sa spełnione zasady unikalności digramów i użyteczności produkcji: poprawiaj gramatykę. (operacje modyfikujace).
Zachowywanie niezmienników Poprawianie gramatyki Powtórzenie digramu: gdy powtórzony digram jest prawa strona reguły: A...XY... A...B... B XY B XY gdy powtórzony digram nie jest prawa strona reguły: A...XY... B...XY... A...C... C XY B...C...
Zachowywanie niezmienników Poprawianie gramatyki c.d. Bezużyteczność produkcji: nieterminal B użyty tylko raz: A...B... A...X 1...X k... B X 1...X k
Sequitur: przykład Przykład (1) bbebeebebebbebee S b
Sequitur: przykład Przykład (2) bbebeebebebbebee S bb
Sequitur: przykład Przykład (3) bbebeebebebbebee S bbe
Sequitur: przykład Przykład (4) bbebeebebebbebee S bbeb
Sequitur: przykład Przykład (5) bbebeebebebbebee S bbebe naruszenie unikalności digramów: be występuje dwa razy. tworzymy regułę A be
Sequitur: przykład Przykład (6) bbebeebebebbebee S baa A be
Sequitur: przykład Przykład (7) bbebeebebebbebee S baae A be
Sequitur: przykład Przykład (8) bbebeebebebbebee S baaeb A be
Sequitur: przykład Przykład (9) bbebeebebebbebee S baaebe A be be występuje dwa razy; wykorzystujemy istniejac a produkcję A be.
Sequitur: przykład Przykład (10) bbebeebebebbebee S baaea A be
Sequitur: przykład Przykład (11) bbebeebebebbebee S baaeab A be
Sequitur: przykład Przykład (12) bbebeebebebbebee S baaeabe A be be występuje dwa razy; wykorzystujemy istniejac a produkcję A be.
Sequitur: przykład Przykład (13) bbebeebebebbebee S baaeaa A be AA występuje dwa razy; tworzymy nowa produkcję
Sequitur: przykład Przykład (14) bbebeebebebbebee S bbeb A be B AA
Sequitur: przykład Przykład (15) bbebeebebebbebee S bbebb A be B AA
Sequitur: przykład Przykład (16) bbebeebebebbebee S bbebbb A be B AA
Sequitur: przykład Przykład (17) bbebeebebebbebee S bbebbbe A be B AA be występuje dwa razy; wykorzystujemy istniejac a produkcję A be.
Sequitur: przykład Przykład (18) bbebeebebebbebee S bbebba A be B AA
Sequitur: przykład Przykład (19) bbebeebebebbebee S bbebbab A be B AA
Sequitur: przykład Przykład (20) bbebeebebebbebee S bbebbabe A be B AA be występuje dwa razy; wykorzystujemy istniejac a produkcję A be.
Sequitur: przykład Przykład (21) bbebeebebebbebee S bbebbaa A be B AA AA występuje dwa razy; wykorzystujemy istniejac a produkcję B AA.
Sequitur: przykład Przykład (22) bbebeebebebbebee S bbebbb A be B AA b B występuje dwa razy; tworzymy nowa produkcję C bb.
Sequitur: przykład Przykład (23) bbebeebebebbebee S CeBC A be B AA C bb
Sequitur: przykład Przykład (24) bbebeebebebbebee S CeBCe A be B AA C bb b B występuje dwa razy; tworzymy nowa produkcję D Ce.
Sequitur: przykład Przykład (25) bbebeebebebbebee S DBD A be B AA C bb D Ce nieterminal C użyty tylko raz; możemy usunać produkcję C bb
Sequitur: przykład Przykład (26) bbebeebebebbebee S DBD A be B AA D bbe
Co daje Sequitur Korzyści? struktura: gramatyka odkrywa wielomopoziomowa stukturę, o ile istnieje (porównaj z LZ); kompresja: jeśli dane z duża powtarzalnościa i hierarchiczna struktura: o.k. można też kompresować wynikowa gramatykę... Wydajność? Sequitur można zaimplementować w czasie liniowym!
Sequitur: implementacja Struktura danych każda produkcja to jeden element tablicy; każda produkcja jako lista dwukierunkowa; każdej produkcja ma licznik wystapień (nieterminala, który ta produkcja definiuje); każdy nieterminal po prawej stronie produkcji wskazuje na definiujac a go produkcję; wszystkie digramy w tablicy (haszujacej, gdy mało pamięci); każdy element tej tablicy wskazuje na wystapienie digramu w gramatyce (może być tylko jedno!)
Sequitur: implementacja Przykład Struktura dla gramatyki: S CeBCe A be B AA C bb... na tablicy
Sequitur: implementacja c.d. Fakt Każda z operacji wykonywanych w Sequitur, czyli: dodanie nowego symbolu; usunięcie 2 wystapień digramu poprzez zastosowanie lub dodanie odpowiedniej produkcji; usunięcie produkcji bezużytecznej (jej lewa strona użyta tylko raz). może być wykonana w stałym czasie (korzystajac z podanej struktury danych). Ile operacji w czasie działania algorytmu?
Sequitur: czas działania Liczba operacji utrzymujacych niezmienniki Sequitur Niech n: długość danych; m: liczba operacji innych niż dodanie kolejnego symbolu. Pokażemy: m 2n Metoda: analiza kosztu zamortyzowanego.
Sequitur: czas działania Niech: s: suma długości prawych stron wszystkich produkcji; r: liczba produkcji; 2s r: potencjał. Wówczas: 2s r = 0 bezpośrednio po dodaniu pierwszej litery; 2s r 0 w każdym kroku po dodaniu pierwszej litery: każda produkcja ma co najmniej jeden symbol po prawej stronie; każda operacja wejściowa zwiększa 2s r o 2; każda operacja modyfikujaca zmniejsza 2s r o 1 lub 2.
Sequitur: czas działania Każda operacja modyfikujaca zmniejsza 2s r. Zastosowanie istniejacej produkcji: A...XY...,B XY zamiana na A...B...,B XY Zmiana 2s r: -2. Utworzenie nowej produkcji: Zmiana 2s r: -1. Usunięcie produkcji: A...XY...,B...XY... zamiana na A...C...,B...C...,C XY A...B...,B X 1...X k zamiana na A...X 1...X k... Zmiana 2s r: -1.
Sequitur: czas... Co z tego wynika 2s t na końcu działania nie mniejsze niż na poczatku; operacje wejściowe zwiększaja 2s t o 2n; więc operacje modyfikujace moga zmniejszyć o 2n każda zmniejsza 2s t o co najmniej 1, więc operacji tych jest co najwyżej 2n. Wniosek Sequitur koduje dane w czasie O(n), gdzie n jest długościa tekstu.
Sequitur: kodowanie gramatyki Kodowanie podstawowe terminalom i nieterminalom przydzielamy kody stałe o długości log( N + T + 1), gdzie N,T to zbiory terminali i nieterminali; dodatkowy kod stały dla symbolu separujacego ; kodujemy prawe strony kolejnych produkcji, oddzielajac symbolem separujacym.
Sequitur: kodowanie gramatyki Kodowanie NMW zapisujemy prawa stronę symbolu startowego; przy pierwszym pojawieniu się każdego nieterminala: wstawiamy jego prawa stronę zamiast niego (z zagłębieniami!); przy drugim pojawieniu się nieterminala: kodujemy go jako trójkę (i,j,d), gdzie j to pozycja na której zaczyna się prawa strona tej reguły w prawej stronie reguły i, długość dopasowania to d po drugim wystapieniu nieterminala (de)koder dodaje jego produkcję do gramatyki; każde następne wystapienie nieterminala: kodowane poprzez jego numer;
Seqential... Sequential: Kieffer-Yang zachowujemy zasady unikalnośći digramów i użyteczności produkcji, jak w Sequitur; modyfikacja: dla gramatyki kodujacej x 1...x i : szukamy najdłuższego prefiksu x i+1...x n, który odpowiada słowu definiowanemu przez jakiś nieterminal i dołaczamy ten nieterminal do produkcji startowej; jeśli brak prefiksu x i+1...x n dopasowujacego się do którejkolwiek z produckji: dołacz x i+1 do produkcji startowej. Sequential: czas działania czy można zaimplementować liniowo?
Sequitur i warianty: podsumowanie Własności Sequitur liniowy czas działania; nie działa on-line; kompresja konkurencyjna wobec LZ??, ppm (dla tekstów w języku naturalnym); odkrywa/buduje hierarchiczna strukturę danych.
Jak mierzyć jakość kompresji gramatykowej? Rozmiar gramatyki: suma długości prawych stron wszystkich produkcji. Problem optymalnej gramatyki Dane: tekst w Wynik: najmniejsza gramatyka CF G =OPT(w), taka że L(G) = w. Zła wiadomość Problem optymalnej gramatyki jest NP-zupełny.
Optymalność gramatyki Czy warto szukać optymalnej gramatyki? Przykład (troche sztuczny...): dla tekstu w = a n b n mamy: P(a) = P(b) = 1/2, H(1/2,1/2) = 1. czyli kodujac jako ciag wartości niezależnych w kodujemy na 2n bitach; dla w i n = 2 k możemy zbudować gramatykę S A k B k,a 1 a,b 1 B,A i A i 1 A i 1,B i B i 1 B i 1 gdzie i [2,k].
Czy Sequitur jest optymalny? Sequitur a optymalna gramatyka Sequitur daje (w najgorszym przypadku) gramatykę o rozmiarze OPT (w) Ω(n 1/3 ), gdzie n = w. Dowód: analiza konkretnego przypadku, skomplikowany...
LZ78 jako kodowanie gramatykowe LZ78 z nieograniczonym rozmiarem słownika Słownik: {(i,w i )} p i=1, gdzie i to pozycja w słowniku, w i to słowo na pozycji i; zakodowana postać: (i 1,a 1 )...(i p,a p ) dla i 1,...,i p N, a 1,...,a p Σ.
LZ78 jako kodowanie gramatykowe LZ78: gramatyka dla słowa x na poczatku: w k-tym kroku LZ78: (1,x[1]) Gramatyka: A 1 w[1],s A 1 LZ78: koduje (i k,a k ) i dodaje do słownika (i max+1,w k a k ) Gramatyka: dodajemy A max+1 A k a k i zmianas α na S αa max+1
LZ78 jako kodowanie gramatykowe Wynik LZ78: p par (liczba,litera) gramatyka: reguła S α, gdzie α ma długość p; p reguł postaci X Ya, gdzie X,Y to nieterminale, a Σ Wniosek Kodowanie LZ78 można przekształcić w kodowanie gramatykowe co najwyżej 3-krotnie dłuższe. W praktyce: kodujac gramatykę uzyskujemy mniejsze różnice.
LZ78 jako kodowanie gramatykowe Przykład Tekst: a ab b aba ba abb abaa LZ78: (0,a) (1,b) (0,b) (2,a) (3,a) (2,b) (4,a) Gramatyka: S X 1 X 2 X 3 X 4 X 5 X 6 X 7 gdzie X 1 a, X 2 X 1 b, X 3 b, X 4 X 2 a, X 5 X 3 a, X 6 X 2 b, X 7 X 4 a.
LZ78 a optymalna gramatyka Fakt Kompresja LZ78 daje (w najgorszym przypadku) gramatykę o rozmiarze OPT (w) Ω(n 2/3 /logn), gdzie n = w. Wystarczy rozważyć inputy σ k = a k(k+1)/2 (ba k ) (k+1)2 Fakt Kompresja LZ78 daje (w najgorszym przypadku) gramatykę o rozmiarze OPT (w) O((n/logn) 2/3 ), gdzie n = w. Dowód: brak czasu...
LZ77 jako kompresja gramatykowa Rozważamy LZ77 (właściwie LZSS) przy założeniach nieograniczony rozmiar bufora słownikowego; dopasowanie nie może wybiegać poza bufor słownikowy; zamiast przesunięcia podajemy pozycję dopasowania w całym tekście (przy nieograniczonym buforze nie zmnienia zakresu); zamiast standardowej zachłannej metody wyboru dopasowań po zakodowaniu x 1...x i wybierz najdłuższe dopasowanie x i+1...x n wybieramy takie dopasowania, aby było jak najmniej elementów w zakodowanym tekście (można to zrobić w czasie O(n Σ )). (czy metoda zachłanna daje najmniejsza liczbę elementów?) Rozmiar LZ 77(w) Liczba elementów (par z dopasowaniem i pojedynczych liter) w powyższym kodowaniu.
LZ77 a optymalna gramatyka Fakt Rozmiar optymalnej gramatyki OPT (w) jest nie mniejszy niż LZ 77(w). Dowód Przekształcimy dowolna gramatykę G taka, że L(G) = w do kodowania LZ77 o tym samym rozmiarze: niech S α to produkcja startowa G; dopóki w α występuja nieterminale: wybierz nieterminal A o najdłuższym rozwinięciu; zamień pierwsze wystapienie A w α na jego prawa stronę ; zamień każde następne wystapienie A na parę (i,j), gdzie i,j wskazuja poczatek pierwszego wystapienia A w tekście i długość rozwinięcia A.
LZ77 a optymalna gramatyka Wynik uzyskujemy kodowanie LZ77 (LZSS) czyli ciag elementów w postaci opisu dopasowania lub pojedynczej litery; liczba elementów wynikowego kodowania nie większa niż rozmiar gramatyki. Przykład Gramatyka: Kodowanie LZ: S ABtAu A vbbw B xyz S A B t A u v B B w B t (1,8) u v x y z (2,3) w (2,3) t (1,8) u
Od LZ77 do (prawie) optymalnej gramatyki Idea Konstruujemy kodowanie LZ77, jego rozmiar jest nie większy od optymalnej gramatyki. Kod LZ77(w) przekształcamy (w czasie wielomianowym) w gramatykę G generujac a słowo w, tak aby rozmiar gramatyki był co najwyżej k krotnie większy od LZ 77(w) w efekcie gramatyka G jest rozmiaru k OPT (w), k nazywamy współczynnikiem aproksymacji. Algorytm Ryttera (p. też alg. Lehmana i in.) stosuje powyższa strategię; działa w czasie O(n logn), gdzie n = w ; osiaga współczynnik aproksymacji (log n)/ OPT (w), gdzie n = w ; pokażemy prostszy wariant, ze współczynnikiem log 2 n.
Konstrukcja gramatyki Idea gramatyka Chomsky ego drzewo wyprowadzenia binarne! budowa przyrostowa: gramatykę kodujac a tekst odpowiadajacy pierwszym i elementom LZ77 rozszerzamy do i + 1 elementów; zachowujemy niezmniennik: drzewo wyprowadzenia w jest drzewem AVL. Oznaczenia Gramatyka AVL: gramatyka Chomsky ego, której drzewo wyprowadzenia jest AVL. T (G): drzewo wyprowadzenia gramatyki G. height(t ): głębokość drzewa T ; height(v): głębokość drzewa o korzeniu w wierzchołku v.
Konstrukcja gramatyki Algorytm(w) Dane: słowo w o długości n. Wynik: gramatyka G taka, że L(G) = w Oblicz f 1...f k = LZ 77(w) G = {S f 1 } Dla i = 2,3,...,k: wyznacz S 1,...,S t : dekompozycja f i w gramatyce G; H Concat(S 1,...,S t ) G Concat(G,H)
Dekompozycja Dekompozycja f i w gramatyce G Fakt f i opisuje podsłowo słowa generowanego przez G (pomijamy przypadek, gdy f i jest pojedyncza litera); podsłowo x możemy reprezentować przez najmniejszy zbiór poddrzew T 1,...,T t drzewa wyprowadzenia, który odpowiada x (RYSUNEK); każdemu poddrzewu odpowiada nieterminal. Niech G będzie gramatyka AVL, L(G) = w, n = w. Wtedy dekompozycja każdego podsłowa w składa się z O(log n) elementów. Wynika ze zbalansowania drzew AVL,...
Konkatenacja Concat(G 1,G 2 ) Dane: G 1,G 2, gramatyki AVL. Wynik: G, gramatyka AVL taka, że L(G) = L(G 1 )L(G 2 ). Założenie: height(t (G 1 )) height(t (G 2 )). Na skrajnie prawej ścieżce T (G 1 ) znajdź wierzchołek v taki, że height(v) height(t (G 2 )) [0,1] (istnieje wskutek zbalansowania drzew) dodaj wierzchołek v pomiędzy v i rodzic(v) oraz przebuduj drzewo: v lewy(v ); korzen(t (G 2 )) prawy(v ) popraw zbalansowanie na ścieżce od v do korzenia T (G 1 ).
Konkatenacja Poprawianie zbalansowania zbalansowanie v jest poprawne: height(v) height(t (G 2 )) 1; zbalansowanie w może wynieść co najwyżej 2, jeśli depth(left(w)) < depth(v) a zatem wystarczy wykonać standardowe rotacje: tak jak przy standardowym wstawianiu/usuwaniu wierzchołka z drzewa AVL; Rotacje wymagaja nowych nieterminali: rotacja powoduje zmiane poddrzew dla 2 lub 3 wierzchołków; więc zmieniaja się słowa im odpowiadajace; ale nie możemy zmienić definicji odpowiadajacych im nieterminali (moga wystapić gdzie indziej); więc wprowadzamy nowe nieterminale.
Algorytm Ryttera a optymalność Wnioski każda operacja Concat wprowadza O(log n) nieterminali; dodanie każdego elementu kodowania LZ77 wprowadza O(log 2 n) nieterminali; algorytm generuje gramatykę Chomsky ego, więc liczba nieterminali to połowa rozmiaru gramatyki. Twierdzenie Algorytm Ryttera tworzy w czasie O(n log 2 n) gramatykę o rozmiarze O( OPT (w) log 2 n), gdzie n = w. Uwaga Dokładniej czas to O( OPT (w) log 2 n), ponieważ algorytm potrzebuje O(log 2 n) czasu przy każdym elemencie LZ77. A LZ 77(w) OPT (w).
Kodowanie gramatykowe: podsumowanie Podsumowanie Sequitur: praktyczny algorytm działajacy w czasie liniowym. Konstrukcja optymalnej gramatyki: problem NP-zupełny. LZ78 szczególnym przypadkiem kompresji gramatykowej (daleki od optimum). LZ77: nie gorszy od kompresji gramatykowej. w oparciu o LZ77: wielomianowy algorytm konstrukcji gramatyki log 2 n razy większej od optymalnej.