24.01.2014 Views

kodowanie arytmetyczne

kodowanie arytmetyczne

kodowanie arytmetyczne

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Podstawy i własności<br />

Implementacja<br />

Kodowanie informacji<br />

Tomasz Jurdziński<br />

Wykład 4: <strong>kodowanie</strong> <strong>arytmetyczne</strong><br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Motywacja<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Motywacje<br />

1<br />

średnia długość kodu Huffmana może odbiegać o p max + 0.086<br />

od entropii, gdzie p max = max i=1,...,n {p i } - może to powodować<br />

duże odchylenia od wartości entropii<br />

2<br />

efekt ten można zniwelować poprzez zastosowanie kodów<br />

Huffmana, w którym alfabet stanowia˛<br />

ciagi ˛ symboli określonej<br />

długości - ale wtedy rośnie gwałtownie rozmiar alfabetu.<br />

Kodowanie <strong>arytmetyczne</strong>:<br />

zastosowanie podejścia z punktu 2. bez konieczności tworzenia słów<br />

kodowych dla wszystkich ciagów ˛ symboli.<br />

Uogólnienie kodowania Shannona.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Ogólnie<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Pierwsze spojrzenie<br />

tekst zostaje odwzorowany na liczbę z przedziału [0,1)<br />

nazywana˛<br />

ZNACZNIKiem.<br />

zakodowana˛<br />

postać tekstu tworzy ZNACZNIK, reprezentowany z<br />

odpowiednio dobrana˛<br />

dokładnościa˛<br />

oraz n - długość<br />

kodowanego tekstu.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Jedna litera<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Znacznik dla jednej litery alfabetu:<br />

elementy alfabetu numerujemy a 1 ,a 2 ,...,a n ; oznaczmy ich<br />

prawdopodobieństwa przez p 1 ,p 2 ,...,p n ;<br />

literze a i przyporzadkowujemy ˛<br />

dowolna˛<br />

liczbę z przedziału<br />

[F(i),F (i + 1)), gdzie F (i) = ∑ i−1<br />

j=1 p i<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Znacznik dla ciagu<br />

˛<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Kodowanie ciagu ˛ x 1 ...x n nad alfabetem a 1 ,...,a m :<br />

1<br />

z = [0,1); l = 0; p = 1;<br />

2<br />

Dla i = 1,2,...,n:<br />

1 niech x i = a j<br />

2 l = l + F (j)(p − l)<br />

3 p = l + F (j + 1)(p − l)<br />

3<br />

znacznik = (l + p)/2 (lub dowolna liczba z przedziału [l,p))<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Przykład<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

P(a) = 0.7, P(b) = 0.1, P(c) = 0.2. Kodujemy tekst abc.<br />

Tekst Lewy Prawy Znacznik<br />

0 1 0.5<br />

a 0 0.7 0.35<br />

b 0.49 0.56 0.53<br />

c 0.546 0.560 0.553<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Jednoznaczność<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Lemat<br />

Dla ustalonej długości tekstu n, każdy ciag ˛ jest odwzorowany na<br />

przedział rozłaczny ˛ z przedziałami odpowiadajacymi ˛ innym ciagom.<br />

˛<br />

Gwarantuje to jednoznaczność kodowania.<br />

Dowód<br />

Indukcja ze względu na długość kodowanego tekstu.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


De<strong>kodowanie</strong><br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

De<strong>kodowanie</strong> ciagu ˛ o długości n ze znacznika z:<br />

1<br />

l = 0; p = 1;<br />

2<br />

Dla i = 1,2,...,n:<br />

1 wybierz j takie, że l + F (j)(p − l) ≤ z < l + F (j + 1)(p − l)<br />

2 przyjmij, że x i = a j<br />

3 l = l + F (j)(p − l);<br />

4 p = l + F (j + 1)(p − l).<br />

3<br />

Ciag ˛ oryginalny to x 1 ...x n .<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Przykład<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Niech z = 0.55 dla P(a) = 0.7, P(b) = 0.1, P(c) = 0.2 i n = 3.<br />

Tekst Lewy Prawy Znacznik<br />

0 1<br />

a 0 0.7<br />

b 0.49 0.56<br />

c 0.546 0.560<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Własności kodowania <strong>arytmetyczne</strong>go<br />

1<br />

Wygenerowanie znacznika dla konkretnego ciagu ˛ nie wymaga<br />

wyznaczania badź ˛ pamiętania znaczników innych ciagów<br />

˛<br />

2<br />

Problem! Komputerowa reprezentacja znacznika może wymagać<br />

dużej pamięci - jak dobrać wartość znacznika aby<br />

zminimalizować potrzebna˛<br />

pamięć?<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Długość znacznika<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Twierdzenie<br />

Niech x = x 1 ...x n będzie ciagiem ˛ danych o prawdopodobieństwie<br />

wystapienia ˛ P(x) = ∏ n i=1 P(x i). Zaokraglenie ˛ z ′ znacznika z dla ciagu<br />

˛<br />

x do m(x) = ⌈log1/P(x)⌉ + 1 bitów (polegajace ˛ na usunięciu<br />

dalszych bitów) gwarantuje jednoznaczność kodowania.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Dowód<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Oznaczenia:<br />

z = (l + p)/2 - znacznik;<br />

z ′ - zaokraglenie ˛ do m = m(x) bitów.<br />

Wystarczy pokazać, że<br />

l ≤ z ′ < p<br />

dla l i p wyznaczonych przy omawianiu algorytmu.<br />

Jest to równoważne warunkowi:<br />

|z − z ′ | < (p − l)/2.<br />

Zauważmy, że z ′ ≤ z < p oraz 0


Dowód c.d.<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Zauważmy:<br />

z ′ ≤ z < p;<br />

p − l = P(x) (dla ciagów ˛ jednoliterowych z definicji, dla dłuższych<br />

dowód indukcyjny)<br />

z(x) − l = P(x)/2,<br />

z ′ (x) > z(x) − 1/2 m(x) ≥ z(x) − 1/2 log(1/P(x))+1<br />

> z(x) − 1/(2 ∗ 1/P(x)) = z(x) − P(x)/2<br />

= (p + l)/2 − (p − l)/2 = l.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Jednoznaczność kodowania z zaokragleniem<br />

˛<br />

Ostatecznie, jednoznaczność wynika z:<br />

rozłaczności ˛ przedziałów.<br />

faktu, że z ′ należy do przedziału odpowiadajacego ˛ danemu<br />

tekstowi.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Kod prefiksowy<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Twierdzenie<br />

Kod arytmetyczny jest (dla ustalonej długości kodowanego tekstu)<br />

przy zaokraglaniu ˛ do ⌈log1/P(x)⌉ + 1 bitów jest kodem prefiksowym.<br />

Dowód<br />

Wynika z następujacych ˛ faktów:<br />

przybliżenie z ′ znacznika z do ⌈log1/P(x)⌉ + 1 bitów znajduje<br />

się w przedziale przypisanym ciagowi ˛ x,<br />

przedziały różnych ciagów ˛ sa˛<br />

rozłaczne.<br />

˛<br />

każde słowo (liczba) o prefiksie z ′ też mieści się w przedziale<br />

przypisanym ciagowi ˛ x.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Przykład<br />

Podstawy i własności<br />

Implementacja<br />

Liczby rzeczywiste<br />

Znacznik dla P(a)=0.7, P(b)=0.1, P(c)=0.2 i tekstu abc to 0.553,<br />

binarnie 0.100011011. Liczba “potrzebnych” bitów to<br />

⌈(log1/0.014)⌉ + 1 = 8. Czyli zakodowana postać tekstu to 10001101.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kod arytmetyczny a entropia<br />

Liczby rzeczywiste<br />

Kod a entropia<br />

Średnia liczba bitów na jeden symbol kodu <strong>arytmetyczne</strong>go (z<br />

zaokragleniem) ˛ dla ciagów ˛ o długości n jest ≤ H(P) + 2/n, gdzie P to<br />

rozkład prawdopodobieństwa dla alfabetu wejściowego.<br />

Dowód<br />

∑ {x ||x|=n} P(x)m(x) = ∑ {x ||x|=n} P(x)(⌈log1/P(x)⌉ + 1)<br />

≤ ∑ {x ||x|=n} P(x)(log(1/P(x)) + 1 + 1)<br />

= −∑ {x ||x|=n} P(x)logP(x) + 2∑ {x ||x|=n} P(x)<br />

= H(P n ) + 2<br />

A zatem, liczba bitów na symbol jest nie większa niż<br />

H(P) + 2/n.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Problemy z implementacja˛<br />

wraz ze wzrostem długości ciagu ˛ potrzebna coraz większa<br />

precyzja reprezentacji liczb; a czas operacji arytmetycznych jest<br />

proporcjonalny do długości liczb...<br />

dla efektywności transmisji danych - potrzebny przyrostowy<br />

algorytm kodowania (znacznik powstaje wraz z wydłużaniem się<br />

ciagu, ˛ nie dopiero po przeczytaniu całego ciagu).<br />

˛<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Przeskalowanie<br />

Podstawy i własności<br />

Implementacja<br />

E 1 (x) = 2x:<br />

[l,p) ⊆ [0,0.5) ⇒ l = 0.0l ′ ,p = 0.0p ′ ⇒ 2 · p = 0.p ′ ,2 · p = 0.p ′<br />

E 2 (x) = 2(x − 0.5):<br />

[l,p) ⊆ [0.5,1) ⇒ l = 0.1l ′ ,p = 0.1p ′ ⇒ 2(l − 1/2) =<br />

0.l ′ ,2(p − 1/2) = 0.p ′<br />

E 3 (x) = 2(x − 0.25):<br />

l ∈ [0.25,0.5), p ∈ [0.5,0.75) ⇒ l = 0.01l ′ , p = 0.10p ′<br />

⇒ 2(l − 1/4) = 0.0l ′ , 2(p − 1/4) = 0.1p ′<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kodowanie z przeskalowaniem<br />

Na poczatku: ˛ licznik := 0, l = 0, p = 1, kod jest słowem pustym.<br />

Po zakodowaniu każdej litery:<br />

Dopóki [l,p) ⊆ [0,0.5) lub [l,p) ⊆ [0.5,1) lub [l,p) ⊆ [0.25,0.75):<br />

1<br />

Jeśli [l,p) ⊆ [0,0.5):<br />

1 zamień [l,p) na [E 1 (l),E 1 (p)), gdzie E 1 (x) = 2x.<br />

2 dołacz ˛ do kodu słowo 01 licznik<br />

3 licznik := 0<br />

2<br />

Jeśli [l,p) ⊆ [0.5,1):<br />

1 zamień [l,p) na [E 2 (l),E 2 (p)), gdzie E 2 (x) = 2(x − 0.5).<br />

2 dołacz ˛ do kodu słowo 10 licznik<br />

3 licznik := 0<br />

3<br />

l < 0.5 < p oraz [l,p) ⊆ [0.25,0.75):<br />

1 zamień [l,p) na [E 3 (l),E 3 (p)), gdzie E 3 (x) = 2(x − 0.25)<br />

2 licznik := licznik + 1;<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Przeskalowanie: poprawność<br />

Lemat<br />

1<br />

(E 1 ) 2 · num(0.0x) = num(0.x)<br />

2<br />

(E 2 ) num(0.1x) − 1/2 = num(0.0x);<br />

3<br />

(E 3 ) Ciag ˛ przeskalowań E 1 E2 i jest równoważny E 3 i E 1.<br />

4<br />

(E 3 ) ciag ˛ przeskalowań E 2 E1 i jest równoważny E 3 i E 2<br />

gdzie num(y) oznacza wartość liczby zapisanej binarnie jako słowo y.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

De<strong>kodowanie</strong> z przeskalowaniem<br />

Wejście: znacznik, czyli ciag ˛ binarny będacy ˛ zakodowana˛<br />

postacia˛<br />

tekstu; n – długość tekstu.<br />

Inicjalizacja:<br />

1<br />

Niech m = max ai ⌈log(1/P(a i ))⌉ + 3. Odczytujemy pierwsze m<br />

bitów znacznika i ustalamy pierwsze przybliżenie znacznika z ′ i<br />

pierwszy symbol w tekście, a j .<br />

2<br />

l := F (j); p := F(j + 1);<br />

3<br />

licznik := 0;<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

De<strong>kodowanie</strong> z przeskalowaniem<br />

Kontynuacja (powtarzaj aż do odkodowania n liter):<br />

1<br />

jeśli [l,p) spełnia warunki dla przeskalowania E 1 lub E 2 :<br />

1 przeskaluj [l,p) przy pomocy E 1 lub E 2 ,<br />

2 usuń 1 + licznik najbardziej znaczacych ˛ bitów z ′ i dołacz ˛ kolejne<br />

1 + licznik bitów jako najmniej znaczace ˛ bity z ′<br />

3 licznik := 0<br />

2<br />

jeśli [l,p) spełnia warunek dla E 3 : przeskalowanie E 3 dla [l,p) i z ′<br />

i zwiększenie licznik o 1;<br />

3<br />

jeśli przedział nie spełnia żadnego z warunków dla E 1 , E 2 , E 3 :<br />

odczytujemy kolejne bity z ′ tak aby było ich co najmniej m; na<br />

podstawie z ′ wyznaczamy kolejna˛<br />

literę tekstu i kolejny przedział.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Co daje skalowanie<br />

wielkość przedziału (p − l) pozostaje nie mniejsza niż p min /4,<br />

gdzie p min to najmniejsze prawdopodobieństwo pojedynczego<br />

symbolu;<br />

Uwaga: mały przedział wymaga dużej dokładności (aby wartości<br />

l i p nie zrównały się).<br />

<strong>kodowanie</strong> progresywne: kod powstaje w trakcie kodowania, nie<br />

dopiero na końcu;<br />

de<strong>kodowanie</strong>: operacje na znaczniku długości ≈ log(1/p min ), nie<br />

na „pełnym” znaczniku;<br />

de<strong>kodowanie</strong> bardziej skomplikowane<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Implementacja całkowitoliczbowa<br />

Problem<br />

Arytmetyka zmiennoprzecinkowa:<br />

Cel<br />

generuje błędy zaokragleń, ˛ więc<br />

konieczna dokładna implementacja (komplikacje...);<br />

przeskalować przedział [0,1) na zbiór naturalnych liczb m-bitowych,<br />

czyli [0,2 m − 1], binarnie [0 m ,1 m ].<br />

Pytanie<br />

jak dobrać parametr m aby zachować jednoznaczność kodowania<br />

(nie możemy uzyskać przedziału o wielkości 0).<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Implementacja całkowitoliczbowa c.d.<br />

Założenia<br />

prawdopodobieństwa wyliczone na podstawie częstości<br />

występowania...<br />

niech c i to liczba wystapień ˛ symbolu a i , C = ∑ n i=1 c i<br />

wówczas p i = c i /C<br />

niech f i = ∑ i−1<br />

j=1 c i<br />

Dobór parametru m<br />

dla jednego symbolu: 2 m > C (najmniejszy przedział to 1/C)<br />

dla k symboli: 2 m > C k ... :(<br />

ale przeskalowanie gwarantuje, że po każdym kroku mamy<br />

przedział nie mniejszy niż p min /4 (czyli 1/4C)<br />

zatem wystarczy, że: 2 m > 4C.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Implementacja całkowitoliczbowa c.d.<br />

Algorytm: jak zaokraglamy<br />

˛<br />

Kodowanie ciagu ˛ x 1 ...x n nad alfabetem a 1 ,...,a r :<br />

1<br />

l = 0; p = 2 m − 1;<br />

2<br />

Dla i = 1,2,...,n:<br />

1 niech x i = a<br />

⌊ j ⌋<br />

(p−l+1)·f (j)<br />

2 l = l + C<br />

⌊ ⌋<br />

(p−l+1)·f (j+1)<br />

3 p = l + C −1<br />

3<br />

znacznik: dowolna liczba całkowita z przedziału [l,p]<br />

Uwaga<br />

Musimy też stosować przeskalowania (w przeciwnym razie potrzebne<br />

bardzo duże m i rośnie czas obliczeń).<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Implementacja całkowitoliczbowa c.d.<br />

Jak zaokraglamy<br />

˛<br />

dlaczego −1: ponieważ [l,p) reprezentujemy jako [l,p − 1];<br />

dlaczego (p − l+1) a nie (p − l): z powyższego powodu;<br />

dlaczego f (j)/C i f (j + 1)/C: ponieważ odpowiadaja˛<br />

skumulowanym prawdopodobieństwom F(j) i F(j + 1).<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kodowanie adaptacyjne<br />

Idea<br />

W każdym kroku używamy częstości (a tym samym<br />

prawdopodobieństw) wyliczonych z już odkodowanej części tekstu.<br />

Modyfikacja algorytmu<br />

(de)Kodujac ˛ k-ty symbol, dzielimy aktualny przedział zgodnie z<br />

częstościami dla pierwszych (k − 1) symboli.<br />

Problem zerowego prawdopodobieństwa<br />

Jak kodować symbol pojawiajacy ˛ się po raz pierwszy:<br />

przydzielić częstości 1: niepraktyczne przy dużym alfabecie;<br />

zarezerwować symbol specjalny o częstości (np.) 1, który<br />

poprzedza pierwsze pojawienie się symbolu; po zakodowaniu<br />

tego symbolu kodujemy nowy symbol wg rozkładu jednostajnego.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kodowanie z uwzględnieniem kontekstu<br />

Założenie<br />

Tekst nie jest ciagiem ˛ wartości niezależnych. Zależności dotycza˛<br />

sasiednich ˛ liter.<br />

Idea<br />

Dla każdego symbolu a i , badamy prawdopodobieństwo pojawienia<br />

się symboli a 1 ,...,a n bezpośrednio za a i .<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Kontekst c.d.<br />

Podstawy i własności<br />

Implementacja<br />

Przykład<br />

a b c<br />

a .4 .2 .4<br />

b .1 .8 .1<br />

c .25 .25 .5<br />

Modyfikacja algorytmu<br />

(de)kodujac ˛ k-ty symbol, dzielimy aktualny przedział zgodnie z<br />

częstościami dla wystapień ˛ symboli za symbolem (k − 1)szym.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kontekst i adaptacja a implementacje<br />

Adaptacja i kontekst a implementacja<br />

dodatkowe struktury danych i ich modyfikacje: niekonieczne!<br />

algorytm z przeskalowaniem: wystarczy znać najmniejsze<br />

prawdopodobieństwo;<br />

implementacja całkowitoliczbowa: wystarczy znać długość<br />

kodowanego tekstu.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kodowanie <strong>arytmetyczne</strong> a <strong>kodowanie</strong> Huffmana<br />

Co lepsze?<br />

gdy grupujemy m symboli:<br />

Huffman koduje ze średnia˛<br />

H(P) + 1/m, <strong>kodowanie</strong> <strong>arytmetyczne</strong><br />

H(P) + 2/m<br />

ale grupowanie dla dużych m w Huffmanie nierealistyczne<br />

kod arytmetyczny bardziej elastyczny:<br />

wersja adaptacyjna: dużo łatwiej przy kodowaniu arytmetycznym;<br />

uwzględnienie kontekstu: <strong>kodowanie</strong> <strong>arytmetyczne</strong> ma mniejsze<br />

wymagania pamięciowe.<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>


Podstawy i własności<br />

Implementacja<br />

Kodowanie <strong>arytmetyczne</strong>: zastosowania<br />

bezstratna kompresja obrazów (JBIG): wariant predykcyjny;<br />

progresywna transmisja obrazów;<br />

algorytm PPM (<strong>kodowanie</strong> <strong>arytmetyczne</strong> z kontekstem): jedna z<br />

najlepszych metod kompresji tekstów w języku naturalnym.<br />

problem: patenty!<br />

Jurdziński<br />

Kodowanie <strong>arytmetyczne</strong>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!