Kodowanie arytmetyczne

Ten artykuł od 2021-02 zawiera treści, przy których brakuje odnośników do źródeł.
Należy dodać przypisy do treści niemających odnośników do źródeł. Dodanie listy źródeł bibliograficznych jest problematyczne, ponieważ nie wiadomo, które treści one uźródławiają.
Sprawdź w źródłach: Encyklopedia PWN • Google Books • Google Scholar • Federacja Bibliotek Cyfrowych • BazHum • BazTech • RCIN • Internet Archive (texts / inlibrary)
Dokładniejsze informacje o tym, co należy poprawić, być może znajdują się w dyskusji tego artykułu.
Po wyeliminowaniu niedoskonałości należy usunąć szablon {{Dopracować}} z tego artykułu.

Kodowanie arytmetyczne – metoda kodowania źródłowego dyskretnych źródeł sygnałów, stosowana jako jeden z systemów w bezstratnej kompresji danych. Została wynaleziona przez Petera Eliasa około 1960 roku. Od roku 2014 było zastępowane kodowaniem Asymmetric Numeral Systems, które pozwala na szybsze implementacje przy podobnym stopniu kompresji.

Ideą tego kodu jest przedstawienie ciągu wiadomości jako podprzedziału przedziału jednostkowego [ 0 , 1 ) {\displaystyle [0,1)} wyznaczonego rekursywnie na podstawie prawdopodobieństw wystąpienia tychże wiadomości generowanych przez źródło. Ciąg kodowy reprezentujący kodowane wiadomości jest binarnym zapisem wartości z wyznaczonego w ten sposób przedziału.

Można udowodnić, że przy wyborze odpowiednio długiego ciągu wiadomości do zakodowania, średnia liczba symboli na wiadomość jest mniejsza od H ( X ) + 2 , {\displaystyle H(X)+2,} gdzie H ( X ) {\displaystyle H(X)} jest entropią źródła, lecz co najmniej równa samej entropii.

Algorytm kodowania

Dany jest zbiór symboli S = { x 1 , x 2 , } {\displaystyle S=\{x_{1},x_{2},\dots \}} oraz stowarzyszony z nim zbiór prawdopodobieństw p = { p 1 , p 2 , } . {\displaystyle p=\{p_{1},p_{2},\dots \}.} Jeden z symboli jest wyróżniony – jego wystąpienie oznacza koniec komunikatu, co zapobiega wystąpieniu niejednoznaczności; ewentualnie zamiast wprowadzenia dodatkowego symbolu można przesyłać długość kodowanego ciągu.

Na początku dany jest przedział P = [ 0 , 1 ) , {\displaystyle P=[0,1),} który dzielony jest na podprzedziały o szerokościach równych kolejnym prawdopodobieństwom p i , {\displaystyle p_{i},} czyli otrzymywany jest ciąg podprzedziałów [ 0 , p 1 ) , [ p 1 , p 1 + p 2 ) , [ p 1 + p 2 , p 1 + p 2 + p 3 ) , [ p 1 + p 2 + p 3 , p 1 + p 2 + p 3 + p 4 ) , {\displaystyle [0,p_{1}),[p_{1},p_{1}+p_{2}),[p_{1}+p_{2},p_{1}+p_{2}+p_{3}),[p_{1}+p_{2}+p_{3},p_{1}+p_{2}+p_{3}+p_{4}),\dots } Kolejnym podprzedziałom (ozn. R i {\displaystyle R_{i}} ) odpowiadają symbole ze zbioru S . {\displaystyle S.}

Algorytm kodowania:

  • Dla kolejnych symboli c:
    • Określ, który podprzedział bieżącego przedziału P {\displaystyle P} odpowiada literze c – wynikiem jest R i . {\displaystyle R_{i}.}
    • Weź nowy przedział P := R i {\displaystyle P:=R_{i}} – następuje zawężenie przedziału
    • Podziel ten przedział P {\displaystyle P} na podprzedziały w sposób analogiczny do tego, jak to miało miejsce na samym początku (chodzi o zachowanie proporcji szerokości podprzedziałów).
  • Zwróć liczbę jednoznacznie wskazującą przedział P {\displaystyle P} (najczęściej dolne ograniczenie, albo średnia dolnego i górnego ograniczenia).

Przykład 1

Na rysunku pokazano, jak zmienia się aktualny przedział P {\displaystyle P} w trzech pierwszych krokach kodowania. Kodowane są trzy symbole z czteroelementowego zbioru o prawdopodobieństwach p = { 0 , 6 ; 0 , 2 ; 0 , 1 ; 0 , 1 } , {\displaystyle p=\{0{,}6;0{,}2;0{,}1;0{,}1\},} w kolejności: pierwszy, trzeci, czwarty.

Przykład 2

Niech S = { a , b , c , # } {\displaystyle S=\{a,b,c,\#\}} ( # {\displaystyle \#} – koniec komunikatu), prawdopodobieństwa p = { 0 , 45 ; 0 , 3 ; 0 , 2 ; 0 , 05 } . {\displaystyle p=\{0{,}45;0{,}3;0{,}2;0{,}05\}.}

Zakodowany zostanie ciąg c a b a # . {\displaystyle caba\#.}

  • Początkowo przedział P = [ 0 , 1 ) , {\displaystyle P=[0,1),} jest on dzielony na podprzedziały [ 0 , 0 , 45 ) , [ 0 , 45 , 0 , 75 ) , [ 0 , 75 , 0 , 95 ) , [ 0 , 95 , 1 ) . {\displaystyle [0,0{,}45),[0{,}45,0{,}75),[0{,}75,0{,}95),[0{,}95,1).}
  • Pierwszym kodowanym symbolem jest c , {\displaystyle c,} któremu odpowiada 3. podprzedział, zatem P := R 3 = [ 0 , 75 , 0 , 95 ) . {\displaystyle P:=R_{3}=[0{,}75,0{,}95).} Nowy przedział znów jest dzielony: [ 0 , 75 , 0 , 84 ) , [ 0 , 84 , 0 , 9 ) , [ 0 , 9 , 0 , 94 ) , [ 0 , 94 , 0 , 95 ) . {\displaystyle [0{,}75,0{,}84),[0{,}84,0{,}9),[0{,}9,0{,}94),[0{,}94,0{,}95).}
  • Kolejnym kodowanym symbolem jest a , {\displaystyle a,} któremu odpowiada 1. podprzedział, zatem P := R 1 = [ 0 , 75 , 0 , 84 ) . {\displaystyle P:=R_{1}=[0{,}75,0{,}84).} Nowy przedział znów jest dzielony: [ 0 , 75 , 0,790 5 ) , [ 0,790 5 , 0,817 5 ) , [ 0,817 5 , 0,835 5 ) , [ 0,835 5 , 0 , 84 ) . {\displaystyle [0{,}75,0{,}7905),[0{,}7905,0{,}8175),[0{,}8175,0{,}8355),[0{,}8355,0{,}84).}
  • Kolejnym kodowanym symbolem jest b , {\displaystyle b,} któremu odpowiada 2. podprzedział, zatem P := R 2 = [ 0,790 5 , 0,817 5 ) . {\displaystyle P:=R_{2}=[0{,}7905,0{,}8175).} Nowy przedział znów jest dzielony: [ 0,790 5 , 0,802 65 ) , [ 0,802 65 , 0,810 75 ) , [ 0,810 75 , 0,816 15 ) , [ 0,816 15 , 0,817 5 ) . {\displaystyle [0{,}7905,0{,}80265),[0{,}80265,0{,}81075),[0{,}81075,0{,}81615),[0{,}81615,0{,}8175).}
  • Kolejnym kodowanym symbolem jest (ponownie) a , {\displaystyle a,} któremu odpowiada 1. podprzedział, zatem P := R 1 = [ 0,790 5 , 0,802 65 ) . {\displaystyle P:=R_{1}=[0{,}7905,0{,}80265).} Nowy przedział znów jest dzielony: [ 0,790 5 , 0,795 968 ) , [ 0,795 968 , 0,799 612 ) , [ 0,799 612 , 0,802 042 ) , [ 0,802 042 , 0,802 65 ) . {\displaystyle [0{,}7905,0{,}795968),[0{,}795968,0{,}799612),[0{,}799612,0{,}802042),[0{,}802042,0{,}80265).}
  • Kolejnym kodowanym symbolem jest # , {\displaystyle \#,} kończący kodowanie, któremu odpowiada 4. podprzedział, zatem P := R 4 = [ 0,802 042 , 0,802 65 ) . {\displaystyle P:=R_{4}=[0{,}802042,0{,}80265).}
  • Na wyjście zostaje zapisana liczba identyfikująca ten przedział – może to być, jak wspomniano, jego dolne ograniczenie, czyli 0,802042.

Dekodowanie

Dekodowanie przebiega prawie tak samo. Różnica polega na tym, że przy kodowaniu kolejne litery jednoznacznie określały podprzedziały, przy dekodowaniu natomiast wybierany jest ten podprzedział, do którego należy kodująca liczba. Wybranie podprzedziału powoduje wypisanie powiązanego z nim symbolu.

Formalnie algorytm przebiega następująco:

  • x {\displaystyle x} – liczba (kod)
  • P = [ 0 , 1 ) {\displaystyle P=[0,1)}
  • Wykonuj w pętli:
    • Podziel P {\displaystyle P} na podprzedziały R i {\displaystyle R_{i}}
    • Znajdź podprzedział R i , {\displaystyle R_{i},} do którego należy x . {\displaystyle x.}
    • P := R i {\displaystyle P:=R_{i}}
    • Wypisz i-ty symbol na wyjście
    • Jeśli i-ty symbol był symbolem końcowym, zakończ pętlę

Przykład

Na rysunku poniżej pokazano pierwsze trzy kroki dekodowania liczby 0,538 (zaznaczonej kropką na osi liczbowej); prawdopodobieństwa symboli: p = { 0 , 6 , 0 , 2 , 0 , 1 , 0 , 1 } . {\displaystyle p=\{0{,}6,0{,}2,0{,}1,0{,}1\}.} W pierwszej iteracji P = [ 0 , 1 ) {\displaystyle P=[0,1)} – liczba 0,538 znajduje się w pierwszym przedziale, a zatem wypisany zostanie pierwszy symbol, a P := R 1 = [ 0 , 0 , 6 ] . {\displaystyle P:=R_{1}=[0,0{,}6].} Teraz 0,538 znajduje się w przedziale 3., wypisany zostanie symbol 3., a P = R 3 = [ 0 , 48 , 0 , 54 ] {\displaystyle P=R_{3}=[0{,}48,0{,}54]} itd.

Zobacz też

Bibliografia

  • Adam Drozdek, Wprowadzenie do kompresji danych, WNT 1999.

Linki zewnętrzne

  • Przetwarzanie sygnałów cyfrowych. dsp.agh.edu.pl. [zarchiwizowane z tego adresu (2016-08-19)]. (materiały dydaktyczne AGH)