30
CODAREA ARITMETICǍ traducere partialǎ dupǎ Arithmetic Coding revealed A guided tour from theory to praxis Sable Technical Report No. 2007-5 Eric Bodden – Sable Research Group, McGill University, Montréal, Québec, Canada Malte Clasen – Zuse Institut Berlin, Berlin, Germany Joachim Kneis - Computer Science Department, RWTH Aachen University, Aachen, Germany May 25, 2007 w w w . s a b l e . m c g i l l . c a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3. Codarea prin numere reale Codarea Huffman a fost consideratǎ multǎ vreme ca aproape optimǎ pânǎ când în anii ’70 ai secolului trecut a apǎrut codarea aritmeticǎ. Codul rezultat este uzual foarte apropiat de entropie si chiar o egaleazǎ în cazuri speciale. Dezavantajele codǎrii Huffman constau în relativ complicata generare a arborelui asociat si în limitarea la a coda simbolurile sau grupele de simboluri ca atare. Codul Huffman binar este examinat într-un arbore binar echilibrat care aproximeazǎ probabilitǎtile simbolurilor: se porneste din rǎdǎcinǎ si se cautǎ nodul asociat unui anumit simbol. Ramurile sunt etichetate binar, astfel încât cuvântul de cod este o secventǎ de ramuri parcurse. Deoarece numǎrul de ramuri parcurse într-o trecere este totdeauna un numǎr întreg, fiecare simbol este codat totdeauna de o secventǎ de biti intreagǎ. Se va vedea cǎ aceastǎ restrictie nu este necesarǎ. Codarea aritmeticǎ utilizeazǎ un tabel de probabilitǎti unidimensional în loc de un arbore. Acest gen de codare cuprinde dintr-o datǎ de întregul mesaj. În acest mod devine posibilǎ codarea simbolurilor folosind fragmente de biti. Dar nu se poate accesa cuvântul de cod la întâmplare: utilizând codarea Huffman se pot specifica marcaje care sǎ permitǎ decodarea pornind din interiorul secventei de biti. Desigur, se pot diviza mesajele si în codarea artimeticǎ, dar aceasta limiteazǎ eficienta deoarece utilizarea fragmentelor de biti la limite este imposibilǎ. Ce se urmǎreste aici este cǎutarea unei modalitǎti de a coda un mesaj fǎrǎ a atribui un cod binar fix fiecǎrui simbol. Examinarea probabilitǎtilor asociate cu simbolurile aratǎ cǎ toate probabilitǎtile sunt numere în intervalul [0, 1) care însumate dau totdeauna unitatea. Acest interval contine extrem de multe

Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

CODAREA ARITMETICǍ

traducere partialǎ dupǎ

Arithmetic Coding revealedA guided tour from theory to praxisSable Technical Report No. 2007-5

Eric Bodden – Sable Research Group, McGill University, Montréal, Québec, Canada

Malte Clasen – Zuse Institut Berlin, Berlin, GermanyJoachim Kneis - Computer Science Department, RWTH Aachen University,

Aachen, GermanyMay 25, 2007

w w w . s a b l e . m c g i l l . c a

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3. Codarea prin numere reale

Codarea Huffman a fost consideratǎ multǎ vreme ca aproape optimǎ pânǎ când în anii ’70 ai secolului trecut a apǎrut codarea aritmeticǎ. Codul rezultat este uzual foarte apropiat de entropie si chiar o egaleazǎ în cazuri speciale. Dezavantajele codǎrii Huffman constau în relativ complicata generare a arborelui asociat si în limitarea la a coda simbolurile sau grupele de simboluri ca atare. Codul Huffman binar este examinat într-un arbore binar echilibrat care aproximeazǎ probabilitǎtile simbolurilor: se porneste din rǎdǎcinǎ si se cautǎ nodul asociat unui anumit simbol. Ramurile sunt etichetate binar, astfel încât cuvântul de cod este o secventǎ de ramuri parcurse. Deoarece numǎrul de ramuri parcurse într-o trecere este totdeauna un numǎr întreg, fiecare simbol este codat totdeauna de o secventǎ de biti intreagǎ. Se va vedea cǎ aceastǎ restrictie nu este necesarǎ. Codarea aritmeticǎ utilizeazǎ un tabel de probabilitǎti unidimensional în loc de un arbore. Acest gen de codare cuprinde dintr-o datǎ de întregul mesaj. În acest mod devine posibilǎ codarea simbolurilor folosind fragmente de biti. Dar nu se poate accesa cuvântul de cod la întâmplare: utilizând codarea Huffman se pot specifica marcaje care sǎ permitǎ decodarea pornind din interiorul secventei de biti. Desigur, se pot diviza mesajele si în codarea artimeticǎ, dar aceasta limiteazǎ eficienta deoarece utilizarea fragmentelor de biti la limite este imposibilǎ.Ce se urmǎreste aici este cǎutarea unei modalitǎti de a coda un mesaj fǎrǎ a atribui un cod binar fix fiecǎrui simbol. Examinarea probabilitǎtilor asociate cu simbolurile aratǎ cǎ toate probabilitǎtile sunt numere în intervalul [0, 1) care însumate dau totdeauna unitatea. Acest interval contine extrem de multe

Page 2: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

numere reale, astfel cǎ este posibil a coda orice secventǎ posibilǎ printr-un numǎr din intervalul [0, 1).Se partitioneazǎ intervalul potrivit probabilitǎtilor asociate simbolurilor. Prin iterarea acestui pas pentru fiecare simbol din mesaj, se rafineazǎ intervalul la un rezultat unic care reprezintǎ mesajul.Orice numǎr din acest interval este un cod valid.Fie M un model care atribuie o probabilitate PM(ai) fiecǎrui simbol ai care apare în mesaj.Se poate acum diviza intervalul [0,1) utilizând aceste valori deoarece suma este totdeauna egalǎ cu 1. Întinderea subintervalului i corespunde exact probabilitǎtii simbolului ai.

3.1. Exemplu: crearea intervalelor

Fie M un model care utilizeazǎ alfabetul A ={a, b, c, d}. Fie probabilitǎtile simbolurilor în mesaj

PM(a) = 0,5 PM(b) = 0,25 PM(c) = 0,125 PM(d) = 0,125 Intervalul [0, 1) este divizat ca în figurǎ

3.2. Limite superioare si inferioare

De aici înainte limitele superioarǎ si inferioarǎ ale intervalului curent se vor numi high si low. Limitele subintervalelor sunt calculate din probabilitǎti cumulate:

K(ak) = ∑=

k

iiM aP

١

)(

Valorile high si low se schimbǎ în timpul procesului de codare în timp ce probabilitǎtile cumulate rǎmân constante (pentru cǎ s-a ales un model constant). Acestea sut utilizate pentru a actualiza cele douǎ valori high si low. Pentru cazul exemplificat valorile sunt conform tabelului

Cum se va vedea, divizarea aceasta depinde de model. Aici, pentru moment se presupune cǎ diviziunea este datǎ de un tabel constant de probabilitǎti cumulate K(ai). Tipul acesta de model existǎ în realitate si este denumit static.

Page 3: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

3.3. Codarea

Primul pas al codǎrii este initializarea intervalului I = [low, high) la valorile low = 0 si high = 1. Când este citit primul simbol s1, intervalul I poate fi redimensionat în acord cu simbolul. Cum sunt calculate aceste limite? Fie s1 = ak. Atunci, limita inferioarǎ este

)()( ١

١

١−

=

== ∑ k

k

iiM aKaPlow

si limita superioarǎ este

)()(١

k

k

iiM aKaPhigh == ∑

=

Noul interval I’ este pus a fi [low, high). Calculul acesta nu este o noutate: el corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel mai relevant al acestei metode este cǎ subintervalul I’ este mai larg pentru un simbol s1 mai probabil. Cu cât este mai larg intervalul cu atât mai redus este numǎrul de cifre dupǎ virgulǎ si cuvâtul de cod este mai scurt. Toate numerele care urmeazǎ a fi generate în iteratiile viitoare vor fi localizate în intervalul I’ deoarece acesta este utilizat ca interval de bazǎ cum a fost mai înainte intervalul I = [0, 1).Se procedeazǎ analog cu simbolul urmǎtor, s2 = aj. Apare acum o problemǎ cu modelul M care se asociazǎ cu o partitie a intervalului I = [0, 1) si nu a lui I’ abia calculat.Intervalul nou trebuie scalat si limitele deplasate pentru a se potrivi cu noul interval. Scalarea se obtine prin multiplicarea lungimii intervalului cu diferenta high – low. Deplasarea se face prin adunarea valorii low. Rezultatul este

)()()()( ١

١

١−

=

−+=−+=′ ∑ j

j

iiM aKlowhighlowaPlowhighlowwlo

)()()()(١

j

j

iiM aKlowhighlowaPlowhighlowhhig −+=−+=′ ∑

=

Aceastǎ regulǎ este valabilǎ pentru toti pasii, în particular pentru primul când low = 0 si high – low = 1. Deoarce vechile limite nu mai sunt necesare, ele se pot suprascrie: low := low’; high := high’.Calculul acesta iterativ poate pǎrea complicat, dar un exemplu va lǎmuri lucrurile.Fie S secventa abaabcda sub modelul ideal M.Se începe cu intervalul [0, 1) si cu primul simbol din S. Deoarece s1 = a noile limite calculate sunt:

low = 0high = 0 + 0,5·1 = 0,5

Intervalul rezultat este [0, 0,5). Iteratia urmǎtoare codeazǎ un b silow = 0 + 0,5·(0,5 − 0) = 0,25

high = 0 + 0,5·(0,5 − 0) + 0,25·(0,5 − 0) = 0,375Urmeazǎ un a si

Page 4: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

low = 0,25high = 0,25 + 0,5·(0,375 − 0,25) = 0,3125

apoi încǎ un alow = 0,25

high = 0,25 + 0,5·(0,3125 − 0,25) = 0,28125Al cincilea caracter este un b

low = 0,25 + 0,5·(0,28125 − 0,25) = 0,265625high = 0,25 + 0,5·(0,28125 − 0,25) + 0,25·(0,28125 − 0,25) = 0,2734375

urmat de un clow = 0,265625 + 0,5·(0,2734375 − 0,265625) + 0,25·(0,2734375 − 0,265625)

= 0,271484375high = 0,265625 + 0,5·(0,2734375 − 0,265625) + 0,25·(0,2734375 − 0,265625)

+ 0,125·0,25·(0,2734375 − 0,265625)= 0,2724609375

un dlow = 0,271484375 + (0,5 + 0,25 + 0,125)·(0,2724609375 − 0,271484375)

= 0,2723388672high = 0,2724609375

si în cele din urmǎ un alt alow = 0,2723388672

high = 0,2723388672 + 0,5·(0,2724609375 − 0,2723388672)= 0,2723999024.

Asadar intervalul rezultat este [0,2723388672 0,2723999024).Figura urmǎtoare ilustreazǎ aceste calcule.

Problema urmǎtoare este codul real. Trebuie specificat intervalul calculat. Astfel, se pot memora limitele de sus si de jos ale intervalului, dar aceasta ar fi o schemǎ ineficientǎ. Stiind cǎ intervalul în întregime este unic pentru un mesaj, se poate memora în sigurantǎ un singur numǎr din acest interval. Lema urmǎtoare contureazǎ aceastǎ tehnicǎ.Lema 1. Codurile tuturor mesajelor de aceeasi lungime formeazǎ o partitie a intervalului I = [0, 1).Acest rezultat transpare limpede din figura urmǎtoare. O concluzie a lemei constǎ în observatia cǎ fragmentele/clasele partitiei devin infinit de mici pentru mesaje infinit de lungi. În practicǎ nu existǎ mesaje infinit de lungi, dar existǎ

Page 5: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mesaje foarte lungi si partitiile mǎrunte rezultate pot crea probleme în calculatoarele obisnuite care utilizeazǎ aritmetici finite. O solutie este re-scalarea discutatǎ într-o altǎ sectiune.

În exemplul prezentat mai devreme se poate memora 0,27234 sau oricare altǎ valoare din interval. Se admite încǎ faptul cǎ se cunoaste locul finalului de mesaj, desi nu acesta este cazul în general (de pildǎ în transmiterea la distantǎ). Manipularea finalului de mesaj va fi discutatǎ mai departe. Pentru moment se dǎ un sumar al codǎrii:

low =0;high=1;do {temp = read_symbol();ival = model->get_interval(temp); \\ returns the interval containing templow = calculate_lower_bound(ival);high = calculate_upper_bound(ival);} while (!end_of_sequence());return(value_in_interval(low,high));

3.4. Decodarea

Pentru a decoda o secventǎ, trebuie parcursǎ cumva codarea în sens invers. Este datǎ valoarea V = Code(S) si trebuie recuperatǎ secventa originarǎ S. Se presupune cǎ lungimea mesajului este cunoscutǎ: l. La prima iteratie se comparǎ V cu fiecare interval I = [K(ak–1), K(ak)) pentru a-l gǎsi pe acela care corespunde primului simbol s1 din secventa S.Pentru a calcula simbolul urmǎtor, trebuie modificatǎ partitia probabilisticǎ în acelasi mod în care s-a procedat la codare:

low′ := low + K(ai−1)·(high − low)high′ := low + K(ai)·(high − low)

cu i îndeplinind conditialow ≤V ≤ high

Page 6: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

si cu ai simbolul urmǎtor în secventa de decodificat. Si de data aceasta cazul de pornire este caz special în formula generalǎ. Iteratia este foarte asemănǎtoare celei de la codare asa încât implementarea n-ar trebui sǎ ridice probleme.

3.5. Exemplu de decodare

Pe acelasi exemplu de mai sus, codul rezultat era V = 0,27234 si se presupume cunoscutǎ lungimea secventei codate l = 8. Se porneste cu low = 0 si high = 1 si se observǎ cǎ V se situeazǎ în primul interval [0, 0,5). Simbolul corespunzǎtor este a si se pun

low = 0high = 0,5

În iteratia urmǎtoare se observǎ cǎ 0,27234 se plaseazǎ între limitelelow = 0 + 0,5·(0,5 − 0) = 0,25

high = 0 + 0,75·(0,5 − 0) = 0,3125si se decodeazǎ un b. Limitele de interes sunt subliniate.La iteratia urmǎtoare

low = 0,25 + 0·(0,3125 − 0,25) = 0,25high = 0,25 + 0,5·(0,3125 − 0,25) = 0,28125

evidentiazǎ un a.Iteratiile urmǎtoare sunt foarte asemǎnǎtoare. De aceea sunt sǎrite cu trecere imediatǎ la ultima:

low = 0,2723388672 + 0·(0,2724609375 − 0,2723388672) = 0,2723388672high = 0,2723388672 + 0,5·(0,2724609375 − 0,2723388672) = 0,2723999024

Aici se identificǎ a-ul final din secventa codatǎ abaabcda.Din motive se similitudine, se poate folosi si aici figura cu partitiile succesive de mai sus.Algoritmul de decodare poate fi sumarizat astfel:

seq = ’’;low = 0;high = 1;do {low’ = model->lower_bound(Value,low,high);high’ = model->upper_bound (Value,low,high);low = low’;high = high’;seq .= model->symbol_in_interval(low,high);} while ( !end_of_sequence() );return(seq);

Pentru a calcula limitele, s-a utilizat aritmetica în virgulǎ mobilǎ. Fǎrǎ metode aditionale, se poate ajunge la numere cu foarte multe cifre dupǎ virgulǎ, chiar infinit de multe (cum este cazul cu 1/3). Prevenirea acestor situatii va fi subiectul sectiunii urmǎtoare.

Page 7: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

De observat cǎ se poate lucra la fel de bine si cu simboluri si cu secvente de simboluri.

3.6. Unicitatea reprezentǎrii

Fie pentru ai codul C(ai) definit ca

)(٢١)()( ١ iMii aPaKaC += −

C(ai) este centrul intervalului ai. Codul C(ai) poate fi scurtat la lungimea

١)(

١)( +

=

iMi aP

ldal

Se defineste )()(ialiaC ca fiind codul pentru ai scurtat la l(ai) digiti.

3.6.1. Exemplu

Fie S = s1s2s3s4 o secventǎ pe alfabetul A = {a1, … , a4}. Fie probabilitǎtile calculate pe baza modelului M

PM(a1) = 1/2, PM(a2) = 1/4, PM(a3) = 1/8, PM(a4) = 1/8Tabelul urmǎtor aratǎ o codare binarǎ posibilǎ pentru secventa propusǎ.

Reprezentarea binarǎ pentru C(ai), dupǎ scurtare la lungimile ١)(

١ +

iM aPld , a

produs codul din tabel1.

3.6.2. Demonstratie

Se demonstreazǎ acum unicitatea codului generat în modul arǎtat. Mai întâi se alege codul C(ai) ca reprezentant al simbolului ai. Dar si orice altǎ valoare din intervalul [K(ai−1), K(ai)) poate fi definitǎ ca un cod unic pentru ai.Pentru a arǎta cǎ )()(

ialiaC este si el un cod unic pentru ai este suficient a arǎta că acest cod apartine intervalului [K(ai−1), K(ai)). Deoarece pentru a obtine )()(

ialiaC s-a trunchiat reprezentarea binarǎ a lui C(ai), este satisfǎcutǎ inegalitatea urmǎtoare:

)()(ialiaC ≤ C(ai)

1 ld – notatie pentru logartimul în baza 2 (uneori lb)

Page 8: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

sau mai în detaliu

0 ≤ C(ai) – )()(ialiaC ≤ )(٢

١ial

Deoarece C(ai) este prin definitie mai mic decât K(ai) rezultǎ cǎ )()(

ialiaC < K(ai)Pe de altǎ parte

٢)(

)(١٢

١

٢٢

١

٢

١

٢

١٢

١

)(١١

)(١

١)(

١)(iM

iM

aPld

aPld

aPld

alaP

aPiMiMiM

i==

⋅=≤=

++

Dar prin definitie

)()(٢

)(١−−= ii

iM aKaCaP

de unde

)(١ ٢١)()(

ialii aKaC ≥− −

si )()(

ialiaC ≥ K(ai–1)cu concluzia finalǎ

K(ai–1) ≤ )()(ialiaC < K(ai)

S-a dovedit astfel cǎ )()(ialiaC este o reprezentare pentru C(ai) lipsitǎ de

ambiguitǎti. Pentru a arǎta cǎ nici la decodare nu apar ambiguitǎti, trebuie dovedit cǎ acest cod îndeplineste conditia de prefix.Fe un numǎr x din intervalul [0, 1) si reprezentarea lui binarǎ x1x2…xn. Este evident cǎ orice alt numǎr y care în reprezentare binarǎ are prefixul x1x2…xn se situeazǎ în intervalul [x, x + 1/2n). Este stiut cǎ dacǎ simbolurile ai si aj sunt diferite, atunci valorile asociate )()(

ialiaC si )()(

jaljaC apartin unor intervale disjuncte [K(ai−1), K(ai)), respectiv [K(aj−1), K(aj)).Ar trebui arǎtat cǎ pentru orice simbol ai, intervalul

+ )()()( ٢

١)(,)(iii alaliali aCaC

este continut în intervalul [K(ai−1), K(ai)), ceea ce ar face imposibil ca simbolul ai sǎ aibǎ un cod care sǎ fie prefix pentru codul unui alt simbol aj, diferit.O inegalitate stabilitǎ mai devreme

)()(ialiaC ≥ K(ai–1)

sprijinǎ demonstratia pentru limita inferioarǎ. Este acum suficient a arǎta cǎ

K(ai) – )()( ٢١)(

ii alaliaC >

Inegalitatea aceasta este evidentǎ deoarece

Page 9: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

)()( ٢١

٢)()()()()(

ii aliM

iialiiaPaCaKaCaK ≥=−>−

Asadar, codul este liber de prefix. În particular, scurtarea lui C(ai) la l(ai) biti produce un cod decodabil fǎrǎ ambiguitǎti. S-a rezolvat astfel problema utilizǎrii aritmeticii finite în cazul codurilor în virgulǎ mobilǎ.

4. Codarea ca o secventǎ de biti

4.1. Motivatie

Pentru a implementa eficient codarea aritmeticǎ, trebuie tinut seamǎ de unele restrictii: nu existǎ numere reale infinit de lungi si implementǎrile cu întregi pure sunt un mod mai rapid de calcul pentru procesoarele de genul celor din faxuri (care utilizeazǎ codarea aritmeticǎ sub protocolul G3).Capitolul curent se ocupǎ de o implementare care consumǎ foarte putinǎ memorie (numai un regisru pentru limite, pe 32 de biti în exemplele prezentate) si numai câteva instructiuni simple în numere întregi. Iesirea este o secventǎ de biti fǎrǎ ambiguitǎti, care poate fi memoratǎ sau expediatǎ din mers.

4.2. Abstractiuni din model

Probabilitǎtile nu pot fi exprimate ca întregi. Deoarece probabilitǎtile simbolurilor se leagǎ în modelele simple de frecventele lor de aparitie, ele se pot normaliza la numǎrul total de simboluri. Limita inferioarǎ este suma frecventelor asociate tuturor simbolurilor inferioare (în ordinea canonicǎ), limita superioarǎ este aceastǎ sumǎ la care se adaugǎ frecventa simbolului curent:

∑−

=

٠

][_symbol

iiCumCountcountlow

][__ symbolCumCountcountlowcounthigh +=unde CumCount reprezintǎ frecventele cumulate. Acestea sunt deosebite de probabilitǎtile din sectiunea precedentǎ prin aceea cǎ nu sunt fractii, frecvenţe relative, ci frecvenţe absolute. În aceastǎ idee rezultǎ cǎ

low_count = low∙totalhigh_count = high∙total

cu total suma tuturor frecvenţelor absolute.

4.3. Codarea

Codorul constǎ într-o functie si variabilele statice care stocheazǎ starea curentǎ:• mLow retine limita inferioarǎ curentǎ care se initializeazǎ la 0• mHigh retine limita superioarǎ curentǎ care se initializeazǎ la 0x7FFFFFFF,

valoarea maximǎ pe 31 de biti

Page 10: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

• mStep care retine dimensiunea unui pas si care se introduce în fazele urmǎtoare.

Prefixul m pentru cele trei variabile indicǎ faptul cǎ sunt statice (ca la programarea orientatǎ pe obiecte) fapt nenecesar la codare dar important la decodare.De observat cǎ se utilizeazǎ numai 31 din cei 32 de biti pentru a preveni depǎsirile. Se va reveni asupra acetui detaliu.Declaratia de functie aratǎ astfel

void Encoder( unsigned int low_count,unsigned int high_count,unsigned int total );

Probabilitǎtile cumulate (calculate din model) pentru simbolul curent ai si pentru simbolul ai–1 situat imediat mai jos sunt pasate codorului. Codorul calculeazǎ din acestea noile limite de sus si de jos.La început, intervalul de la mLow la mHigh este divizat în total pasi, ceea ce face dimensiunea pasului

mStep = ( mHigh - mLow + 1 ) / total;La diferenta dintre mHigh si mLow trebuie adǎugatǎ o unitate deoarece mHigh reprezintǎ limita superioarǎ deschisǎ. Asadar intervalul este extins cu o unitate. O analogie în sistemul zecimal obisnuit ar fi cu un interval de la 0 la 99,(9) pentru care limita superioarǎ este memoratǎ ca 99. Cifrele din partea fractionarǎ fac intervalul mai mare cu o unitate fatǎ de 99 – 0 = 99.Este si acesta un motiv pentru care se face limitarea reprezentǎrii la 31 de biti: limita mHigh este initializatǎ la valoarea maximǎ posibilǎ. Dacǎ s-ar fi ales reprezentarea pe 32 de biti, la evaluarea mHigh - mLow + 1 ar fi rezultat o depǎsire. Depǎsirea ar fi generat în cel mai fericit caz o exceptie dar si erori de codare sporadice, inacceptabile.Astfel limita superioarǎ se actualizeazǎ de aici încolo la

mHigh = mLow + mStep * high_count - 1;si limita inferioarǎ la

mLow = mLow + mStep * low_count;Ambele evaluǎri pleacǎ de la valoarea anterioarǎ mLow, asadar suprascrierea trebuie sǎ fie ultimul pas. Deoarece se lucreazǎ cu un interval (semi)deschis, limita de sus mHigh trebuie diminuatǎ cu 1.

4.4. Exemplu de codare

Se va lucra cu acelasi exemplu de mai devreme, dar limitat la primele douǎ simboluri din secventǎ, ab. Se initializeazǎ mai întâi codorul:

mBuffer = 0;mLow = 0;

Page 11: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mHigh = 0x7FFFFFFF;

Apoi se codeazǎ simbolurile din secventǎ. De observat cǎ modelul este static, asa încât total rǎmâne constant.

1. ’a’mStep = ( mHigh - mLow + 1 ) / total;

= ( 0x7FFFFFFF - 0 + 1) / 8= 0x80000000 / 8= 0x10000000

mHigh = mLow + mStep * high_count - 1;= 0 + 0x10000000 * 4 - 1= 0x40000000 - 1= 0x3FFFFFFF

mLow = mLow + mStep * low_count;= 0 + 0x10000000 * 0= 0

2. ’b’mStep = ( mHigh - mLow + 1 ) / total;

= ( 0x3FFFFFFF - 0 + 1 ) / 8= 0x40000000 / 8= 0x08000000

mHigh = mLow + mStep * high_count - 1;= 0 + 0x08000000 * 6 - 1= 0x30000000 - 1= 0x2FFFFFFF

mLow = mLow + mStep * low_count;= 0 + 0x08000000 * 4= 0x20000000

Dupǎ aceste douǎ simboluri se poate memora orice valoare din intervalul 0x20000000 la 0x2FFFFFFF.

4.5. Decodarea

Sarcina decodorului este de a urma unul câte unul pasii codorului. Trebuie asadar sǎ se determine primul simbol si sǎ se actualizeze limitele în consecintǎ. Acest aspect împarte functionalitatea decodorului în douǎ:

unsigned int Decode_Target( unsigned int total );

Page 12: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

void Decode( unsigned int low_count, unsigned int high_count );

Decode_Target() determinǎ intervalul care contine simbolul. Aceasta se face prin calcularea valorii codului asociat simbolului:

mStep = ( mHigh - mLow + 1 ) / total;value = ( mBuffer - mLow ) / mStep;

mBuffer este variabila care contine secventa codatǎ. Modelul poate utiliza valoarea returnatǎ pentru a determina simbolul codat prin compararea ei cu intervalele cumulative. Imediat ce intervalul a fost localizat, limitele pot fi actualizate cum au fost la momentul codǎrii:

mHigh = mLow + mStep * high_count - 1;mLow = mLow + mStep * low_count;

De observat cǎ mStep este reutilizat. Aceasta deoarece a fost declarat static de la bun început.

4.6. Exemplu de decodare

Se decodeazǎ acum secventa de biti care a fost generatǎ mai devreme la codare.Fie 0x2800000 valoarea depusǎ de codor. Se initializeazǎ decodorul cu urmǎtoarele valori:

mBuffer = 0x28000000;mLow = 0;mHigh = 0x7FFFFFFF;

1. ‘a’Se calculeazǎ mai întâi o valoare compatibilǎ cu modelul utilizând Decode_Target():

mStep = ( mHigh - mLow + 1 ) / total;= ( 0x7FFFFFFF - 0 + 1 ) / 8= 0x80000000 / 8= 0x10000000

value = ( mBuffer - mLow ) / mStep;= ( 0x28000000 - 0 ) / 0x10000000= 0x28000000 / 0x10000000= 2

Acest 2 este comparat acum cu tabelul de mai sus care reprezintǎ modelul. El se situeazǎ în intervalul [0, 4), prin urmare simbolul codat este un a. Se actualizeazǎ limitele apelând Decode():

Page 13: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mHigh = mLow + mStep * high_count - 1;= 0 + 0x10000000 * 4 - 1= 0x40000000 – 1= 0x3FFFFFFF

mLow = mLow + mStep * low_count;= 0 + 0x10000000 * 0= 0

2. ’b’

Decode_Target():

mStep = ( mHigh - mLow + 1 ) / total;= ( 0x3FFFFFFF - 0 + 1 ) / 8= 0x40000000 / 8= 0x08000000

value = ( mBuffer - mLow ) / mStep;= ( 0x28000000 - 0 ) / 0x08000000= 0x28000000 / 0x08000000= 5

Decode():

mHigh = mLow + mStep * high_count - 1;= 0 + 0x08000000 * 6 - 1= 0x30000000 - 1= 0x2FFFFFFF

mLow = mLow + mStep * low_count;= 0 + 0x08000000 * 4= 0x20000000

Acest 5 este situat în intervalul corespunzǎtor lui b. S-a decodat cu succes secventa ab.

5. Scalarea în domenii limitate

5.1. Motivatie

Când se utilizeazǎ metodele prezentate pentru a coda mai multe simboluri, apare o problemǎ nouǎ: limitele mLow si mHigh converg una cǎtre alta si, la un moment dat, când ele coincid, codarea în continuare devine imposibilǎ. Totusi o continuare existǎ si este bazatǎ pe urmǎtoarea observatie:

5.2. Scalarea E1 si E2

Page 14: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

Când limitele mLow si mHigh ajung în aceeasi jumǎtate a gamei de numere (în acest caz < sau ≥ 0x40000000), este sigur cǎ nu vor mai pǎrǎsi aceastǎ gamǎ deoarece simbolurile urmǎtoare vor comprima intervalul. Asadar, informatia despre jumǎtatea aceea este irelevantǎ pentru urmǎtorii pasi si poate fi stocatǎ si eliminatǎ din discutie.În implementarea prezentatǎ bitii cei mai semnificativi (MSB – most significant bits) pentru mLow si mHigh vor coincide. 0 corespunde jumǎtǎtii inferioare, 1 jumǎtǎtii superioare. De îndatǎ ce bitii cei mai semnificativi se suprapun, ei pot fi stocati în secventa de iesire si pot fi deplasati în afarǎ. Aceastǎ procedurǎ este denumitǎ scalarea E1, respectiv scalarea E2.

while( ( mHigh < g_Half ) || ( mLow >= g_Half ) ) {if( mHigh < g_Half ) // E1{SetBit( 0 );mLow = mLow * 2;mHigh = mHigh * 2 + 1;}else if(mLow >= g_Half ) // E2{SetBit( 1 );mLow = 2 * ( mLow - g_Half );mHigh = 2 * ( mHigh - g_Half ) + 1;}}

g_Half este constanta globalǎ 0x40000000 care marcheazǎ centrul domeniului. Multiplicarea cu 2 lǎrgeste intervalul. Adunarea unei unitǎti fixeazǎ limita superioarǎ de interval deschis.Operatia este echivalentǎ cu o solutie mai intuitivǎ: ori de câte ori un calcul implicǎ o limitǎ deschisǎ, se adunǎ 1 înainte si se scade 1 dupǎ. Adunarea unitǎtii dupǎ multiplicarea cu 2 are acelasi efect.SetBit() adaugǎ un bit la secventa de iesire, functia complementarǎ la decodare numitǎ GetBit(). Ambele functii lucreazǎ secvential si pot fi interpretate ca o coadǎ, un fir de asteptare FIFO (First-In-First-Out).Cǎutarea în secventa codatǎ nu este nici posibilǎ nici necesarǎ deoarece algoritmul însusi lucreazǎ secvential.

5.3. Scalarea E3

Desi scalǎrile E1 si E2 sunt un pas în directia cea bunǎ, ele nu sunt suficiente prin ele însesi. Nu vor lucra dacǎ mLow si mHigh converg cǎtre centrul intervalului: ambele stau în jumǎtatea lor, iar intervalul devine curând prea îngust. Cazul extrem ar fi o valoare de 0x3FFFFFFF pentru mLow si de

Page 15: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

0x40000000 pentru mHigh. Ele diferǎ prin fiecare bit (exceptie cel rezervat pentru depǎsiri), dar codarea în continuare este imposibilǎ.Aici intervine scalarea E3: imediat ce mLow pǎrǎseste sfertul inferior (valoarea maximǎ a primului sfert este g_FirstQuarter) si mHigh iese din sfertul superior (valoarea maximǎ a sfertului al treilea este g_ThirdQuarter), intervalul total devine mai mic decât jumǎtatea intervalului initial si este cert cǎ el nu va mai fi pǎrǎsit din cauza contractiei care urmeazǎ. Jumǎtatea care va contine rezultatul nu este imediat determinabilǎ, dar la urmǎtoarea scalare E1 sau E2 este posibil a fi determinatǎ: se cunosc valorile care au fost stocate mai devreme si se poate prevedea acea jumǎtate. Poate suna ciudat, dar acesta este modul în care lucreazǎ scalarea E3: se lǎrgeste intervalul ca si la scalǎrile E1 sau E2, dar în loc de a stoca un bit în secventa de iesire, se reaminteste cǎ s-a efectuat o sclare E3 folosind variabila helper mScale:

while( ( g_FirstQuarter <= mLow ) && ( mHigh < g_ThirdQuarter )) {mScale++;mLow = 2 * ( mLow - g_FirstQuarter );mHigh = 2 * ( mHigh - g_FirstQuarter ) + 1;}

La urmǎtoarea scalare E1 sau E2, se adunǎ la secventa de iesire bitul corect pentru fiecare scalare E3. Utilizând scalarea E3 urmatǎ de scalarea E1 înseamnǎ cǎ intervalul a fost potrivit în gama dintre g_FirstQuarter si g_Half. Aceasta echivaleazǎ cu o scalare E1 urmatǎ de o scalare E2. Secventa E3-E2 poate fi interpretatǎ analog, la fel merge si pentru scalǎri E3 iterate. Asadar, trebuie memorate scalǎrile E3 dupǎ urmǎtoarea scalare E1/E2, utilizând bitul invers al acelei scalǎri:

while( ( mHigh < g_Half ) || ( mLow >= g_Half ) ) {if( mHigh < g_Half ) // E1{SetBit( 0 );mLow = mLow * 2;mHigh = mHigh * 2 + 1;// E3for(; mScale > 0; mScale-- )SetBit( 1 );}else if(mLow >= g_Half ) // E2{SetBit( 1 );mLow = 2 * ( mLow - g_Half );mHigh = 2 * ( mHigh - g_Half ) + 1;// E3for(; mScale > 0; mScale-- )SetBit( 0 );

Page 16: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

}}

Aceastǎ coerentǎ este ilustratǎ de figurile urmǎtoare. Fie A = {a, b, c, d, e} cu simboluri echiprobabile. Prima figurǎ se referǎ la o secventǎ cu c ca prim caracter. Intervalul corspunzǎtor este (0,4 0,6) care se întinde în sferturile doi si

Aplicarea scalǎrii E3

Pentru comparatie, fǎrǎ scalarea E3

trei. În aceastǎ împrejurare se poate aplica scalarea E3 si intervalul rezultat acoperǎ din nou sferturile doi si trei.

Page 17: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

Dupǎ scalarea E3 urmǎtoare, intervalul acoperǎ mai mult de douǎ sferturi si se poate continua cu simbolul urmǎtor b. Intervalul rezultat este [0,375 0,5) care este continut complet în jumǎtatea inferioarǎ. Scalarea E1 depune un 0 în secventa de iesire urmat de doi biti 1 pentru scalǎrile E3. Figura a doua ilustreazǎ de ce depunerea 011 este corectǎ. Începând cu intervalul [0, 1) se aplicǎ scalǎrile E1 si E2 potrivit bitilor depusi, care înseamnǎ o scalare E1 si douǎ scalǎri E2. Intervalul rezultat este acelasi ca în prima figurǎ care aratǎ rezultatul a douǎ scalǎri E3 urmate de o scalare E1.Procedeul este valid în general. Fie f si g douǎ functii si g◦f aplicarea consecutivǎ a lui f si a lui g. Metoda se poate exprima astfel:Lemǎ: Ecuatiile urmǎtoare, aplicate la orice secventǎ sunt valide:

E1◦(E3)n = (E2)n◦E1E2◦(E3)n = (E1)n◦E2

Demonstratie:Fie l = low, h = high si I = [0, 1) intervalul de lucru. Functiile de scalare pot fi exprimate astfel:

=

hl

hlE ٢

٢١

−−=

١٢١٢٢ h

lhlE

−=

٢١٢٢١٢

٣h

lhlE

Iteratia a n-a produce

=

hl

hlE n

nn

٢٢١

+−+−=

١٢٢١٢٢٢ nn

nnn

hl

hlE

+−

+−=

٢١٢٢٢١٢٢

٣١

١

nn

nn

n

h

lhlE

Demonstratia se poate face cu usurintǎ prin inductie. Dacǎ se scriu

+−+−=

+−

+−=

+

+

١٢٢١٢٢

٢١٢٢٢١٢٢

١)٣((١( ١

١

١

١

nn

nn

nn

nn

n

hl

h

lEh

lEE

si

+−+−=

=

+

+

١٢٢١٢٢

٢٢(١()٢(٢(( ١

١

nn

nnnn

hl

hlEh

lEE

ecuatiile acestea conduc la

Page 18: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

١)٣()٢(١ EEEE nn =Identitatea a doua se poate dovedi prin mijloace similare.

5.4. Exemplu de codare

Pentru ilustrarea suplimentarǎ a scalǎrii E3, se propune spre codare secventa abccedac din multimea de simboluri A = {a, b, c, d, e}. Modelul sursei este dat în tabelul urmǎtor:

Simbol Frecventǎ low_count high_counta 2 0 2b 1 2 3c 3 3 6d 1 6 7e 1 7 8

Exemplul este prezentat în detaliu în tabelul urmǎtor (fragmentat):

Simb l_c h_c t mStep mLow mHigh Bitia 0 2 8 16 0000000[0] 0011111[31] 00b 2 3 8 16 0100000[32] 0101111[47] 010c 3 6 8 16 0110000[48] 1011111[95]c 3 6 8 12 1000100[68] 1100111[103] 10e 7 8 8 9 1001111[71] 10011111[79] 100d 6 7 8 9 1101110[110] 1110110[118] 11a 0 2 8 9 0110000[48] 1000001[65]c 3 6 8 9 0011011[27] 0110101[53] 0111

rest 1

Simb E1/2-mLow E1/2-mHigh mScale E3-mLow E3-mHigha 0000000[0] 1111111[127] 0b 0000000[0] 1111111[127] 0c 1 0100000[32] 1111111[127]c 0e 0111000[56] 1111111[127] 0d 0111000[56] 1011011[91] 1 0110000[48] 1110111[119]a 3 0000000[0] 1000111[71]c 0110110[54] 1101011[107] 0

rest

Prima coloanǎ contine simbolul urmǎtor care trebuie codat. Urmǎtoarele trei colane contin parametrii care sunt serviti functiei Encode(). Acestea sunt urmate de limitele mLow si mHigh calculate. Apoi sunt date scalǎrile E1 si E2 si bitii rezultati la iesire. Bitii subliniati reprezintǎ efectul scalǎrilor E3. Coloanele urmǎtoare aratǎ scalǎrile E3 consecutive si limitele actualizate, urmate de bitii

Page 19: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

necesari pentru a alege valoarea dintre aceste limite. Tabelul care urmeazǎ contine aceleasi explicatii într-o manierǎ mai sistematicǎ.Exemplul acesta este limitat la întregi de 7 biti. Este suficient pentru a face din secventa codatǎ o lecturǎ mult mai usoarǎ decât una pe 31 de biti.

Simb simbolul curentl_c low_count, limita inferioarǎ a frecventelor cumulate ale simboluluih_c high_count, limita superioarǎ a frecventelor cumulate ale simboluluit total, frecventa totalǎmStep pasulmLow limita inferioarǎ a noului intervalmHigh limita superioarǎ a noului intervalBiti biti care sunt depusi si eliminati prin scalǎrile E1/E2E1/2-mLow limita inferioarǎ dupǎ scalǎri E1/E2E1/2-mHigh limita superioarǎ dupǎ scalǎri E1/E2mScale Suma scalǎrilor E3 noi si remanenteE3-mLow limita inferioarǎ dupǎ scalarea E3E3-mHigh limita superioarǎ dupǎ scalerea E3

5.5. Decodarea

Deoarece decodarea urmeazǎ pasii de la codare, scalǎrile lucreazǎ la fel. Totusi este de observat cǎ trebuie actualizat si bufferul mBuffer. Actualizarea aceasta se face în acelasi mod în care se actualizeazǎ limitele, numai cǎ nu se genereazǎ bitii urmǎtori ci se iau din secventa codatǎ.

// E1 scalingmLow = mLow * 2;mHigh = mHigh * 2 + 1;mBuffer = 2 * mBuffer + GetBit();

// E2 scalingmLow = 2 * ( mLow - g_Half );mHigh = 2 * ( mHigh - g_Half ) + 1;mBuffer = 2 * ( mBuffer - g_Half ) + GetBit();

// E3 scalingmLow = 2 * ( mLow - g_FirstQuarter );mHigh = 2 * ( mHigh - g_FirstQuarter ) + 1;mBuffer = 2 * ( mBuffer - g_FirstQuarter ) + GetBit();

5.6. Exemplu de decodare

În exemplul urmǎtor se decodeazǎ secventa codatǎ anterior. Intrarea decodorului este 00010101001101111. Primii 7 biti ai secventei sunt încǎrcati în mBuffer. Bitii urmǎtori sunt omisi în tabelul explicativ urmǎtor (fragmentat)

Page 20: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

pentru a facilita lectura. De observat cǎ pânǎ si pentru scalǎrile E3 bufferul este actualizat cu toate cǎ nici un bit nu va fi trimis codorului la aceastǎ etapǎ. Unele rubrici au fost prescurtate: St este pentru mStep, Si este pentru simbol, Sc este pentru mScale.

St mBuffer l_c h_c Si mLow mHigh Biti16 0001010[10] 0 2 a 0000000[0] 0011111[31] 0016 0101010[42] 2 3 b 0100000[32] 0101111[47] 01016 1010011[83] 3 6 c 0110000[48] 1011111[95]12 0100110[38] 3 6 c 1000100[68] 1100111[103] 109 1001101[77] 7 8 e 1001111[71] 10011111[79] 1009 1101111[111] 6 7 d 1101110[110] 1110110[118] 119 1110000[112] 0 2 a 0110000[48] 1000001[65]9 1000000[64] 3 6 c 0011011[27] 0110101[53] 0111

Biti E1/2-mLow E1/2-mHigh Sc E3-mLow E3-mHigh00 0000000[0] 1111111[127] 0010 0000000[0] 1111111[127] 0

1 0100000[32] 1111111[127]10 0100 0111000[56] 1111111[127] 011 0111000[56] 1011011[91] 1 0110000[48] 1110111[119]

3 0000000[0] 1000111[71]0111 0110110[54] 1101011[107] 0

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

10. Concluzii

Dupǎ toate aceste consideratii, este utilǎ o recapitulare si o revedere a scopului expunerii. Lucrarea descrie o metodǎ de codare potrivitǎ pentru compresia de date. S-a dovedit cǎ cerintele de biunivocitate ale unui sistem de codare sunt îndeplinite. Implementarea poate utiliza la fel de bine si aritmetica cu întregi ca si aritmetica în virgulǎ mobilǎ. S-a dovedit posibila secventialitate a codǎrii aritmetice, codarea simbol cu simbol si abilitatea de a transmite o parte a unui mesaj deja codatǎ, înainte ca el sǎ fie cunoscut integral. Aceastǎ proprietate poate fi exploatatǎ când se aplicǎ cele trei functii de scalare care lǎrgesc intervalul de lucru în asa mod încât nu apar depǎsiri si devine suficientǎ chiar o aritmeticǎ finitǎ. S-au evidentiat limitele de eficientǎ ale codǎrii în general si s-a observat cǎ lungimea medie a codului pentru orice simbol dintr-o secventǎ de intrare se apropie din ce în ce mai mult de entropia (dependentǎ de model) cu cresterea lungimii secventei de intrare. S-a arǎtat în care cazuri codarea aritmeticǎ este eficientǎ în mod deosebit si în care cazuri este apropiatǎ de eficienta codurilor Huffman. S-a observat cum rata compresiei care poate fi atinsǎ de un codor oarecare în conditiile unui model dat se plafoneazǎ în raport cu calitatea acelui model. S-a subliniat aici un alt avantaj al codǎrii aritmetice,

Page 21: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

deoarece permite în mod simplu schimbarea modelului statistic, care poate fi optimizat pentru anumite date de intrare.Concluzia: scopul lucrǎrii a fost atins. Urmeazǎ câteva consideratii asupra posibilitǎtilor de ameliorare a tehnicilor aplicative.

10.1. Important de retinut: compresia are limitele sale

Desi codarea aritmeticǎ a fost pusǎ la punct si optimizatǎ pe durata a cca. 10-20 de ani în urmǎ, apar din când în când variatiuni, versiuni noi. Dacǎ doresc, cititorii interesati pot sǎ observe tehnici noi si vederi noi, mai profunde în domeniu, în grupul de discutii comp.compression. Totusi, atentie! Uneori oamenii cred cǎ au inventat un algoritm deosebit care se comportǎ de nu-stiu-câte-ori mai bine decât orice s-a produs pânǎ la acel moment. Frecvent ei exagereazǎ, ignorând uneori pur si simplu calitatea codǎrii aritmetice de a fi o codare aproape fǎrǎ pierderi (lossless). Se cunoaste cu sigurantǎ faptul cǎ teorema lui Shannon garanteazǎ imposibilitatea compresiei sub entropia sursei de informatie. Se poate consuma oricât de mult din redundanta datelor, dar entropia se dovedeste o limitǎ decisivǎ.

10.1. Metode de optimizare

Cu toate acestea un algoritm poate fi optimizat în cel putin douǎ directii: memoria utilizatǎ si viteza de actiune.

10.2.1. Utilizarea memoriei

Codarea aritmeticǎ este aproape optimǎ în termeni de utilizare a memoriei. Ea utilizeazǎ numai un spatiu de memorare constant pentru modelele simple (modelele mai elaborate pot consuma ceva mai mult, dar de obicei mai putin decât liniar). Mai mult, ea genereazǎ un cod care nu poate fi comprimat suplimentar. De retinut cǎ acest cod depinde de model: H(S) ≤ HM(S) ≤ |cod(S)|. Trebuie fǎcutǎ distinctie între entropia naturalǎ a secventei generate de sursǎ, H(S), care reprezintǎ limita inferioarǎ matematic si limita care este datǎ de model, HM(S). Codarea aritmeticǎ atinge HM(S), dar poate fi departe de perfectiune dacǎ modelul stabilit este incapabil a reprezenta foarte bine datele de intrare.Deoarece datele de intrare nu sunt predictibile într-o manierǎ cuprinzǎtoare va trebui gǎsit un model care lucreazǎ pentru un context aparte aplicativ. Codarea aritmeticǎ permite o proiectare modularǎ astfel încât codorul sǎ poatǎ interactiona cu modele diferite, chiar schimbându-le unul cu altul în timpul codǎrii. Au fost dezvoltate foarte multe modele si una din familiile cele mai populare este cea cunoscutǎ sub sigla PPM (Prediction with Partial Match – predictie cu adecvare patialǎ). Aceste modele sunt destul de eficiente datoritǎ lungimii contextuale variabile, dar cea mai mare parte din cele avansate nu au un fundament matematic solid.

Page 22: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

10.2.2. Viteza

Viteza codoarelor care fac codarea aritmeticǎ a tot crescut de-a lungul anilor. Obisnuite sunt implementǎrile în numere întregi, dar odatǎ cu cresterea puterii de calcul în virgulǎ mobilǎ a procesoarelor moderne implementarea în acest mod ar putea deveni o alternativǎ demnǎ de luat în seamǎ. În sectiunea 3.6 s-a arǎtat cǎ implementarea bazatǎ pe aritmetica în virgulǎ mobilǎ este posibilǎ.O implementare în întregi foarte eficientǎ este cea cunoscutǎ sub numele Range Coder. Ea executǎ scalarea bit-cu-bit, eliminând astfel bunǎ parte din jocul de biti (bit-fiddling) care este o mare problemǎ de performantǎ pe procesoarele curente. Sunt raportate sporuri de vitezǎ de pânǎ la 50% la cresteri ale dimensiunii codului de numai 0,01%. Aceste numere trebuie privite cu prudentǎ deoarece ele reflectǎ numai performantele codorului, nu ale modelului. Strangularea implementǎrilor contemporane ale codǎrii aritmetice este datoratǎ aproape totdeauna modelului.Cum se poate vedea, cel mai interesant câmp de cercetare legat de codarea aritmeticǎ îl constituie modelele. Dimensiunea codului, utilizarea de memorie si viteza depind toate mai ales de modele în timp ce realizarea unui codor bine implementat poate fi consideratǎ o sarcinǎ minorǎ, în special când codarea aritmeticǎ însǎsi este foarte bine documentatǎ.

Anexe. O implementare de referintǎ în C++

Aceastǎ implementare ar trebui sǎ prezinte întregul algoritm într-un mod lipsit de ambibuitǎti pentru a rǎspunde oricǎror întrebǎri deschise relativ la detaliile implementǎrii. S-a utilizat un model simplu de ordinul 0 adaptiv. În consecintǎ, rata de compresie este destul de scǎzutǎ, dar modelul poate fi oricând schimbat prin dezvoltarea unuia nou din modelul de bazǎ.

A.1 Codor aritmetic (header)

#ifndef __ARITHMETICCODERC_H__#define __ARITHMETICCODERC_H__#include <fstream>using namespace std;class ArithmeticCoderC{public:ArithmeticCoderC();void SetFile( fstream *file );void Encode( const unsigned int low_count,const unsigned int high_count,const unsigned int total );void EncodeFinish();void DecodeStart();unsigned int DecodeTarget( const unsigned int total );

Page 23: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

void Decode( const unsigned int low_count,const unsigned int high_count );protected:// bit operationsvoid SetBit( const unsigned char bit );void SetBitFlush();unsigned char GetBit();unsigned char mBitBuffer;unsigned char mBitCount;// in-/output streamfstream *mFile;// encoder & decoderunsigned int mLow;unsigned int mHigh;unsigned int mStep;unsigned int mScale;// decoderunsigned int mBuffer;};#endif

A.2 Codor aritmetic

#include "ArithmeticCoderC.h"#include "tools.h"// constants to split the number space of 32 bit integers// most significant bit kept free to prevent overflowsconst unsigned int g_FirstQuarter = 0x20000000;const unsigned int g_ThirdQuarter = 0x60000000;const unsigned int g_Half = 0x40000000;ArithmeticCoderC::ArithmeticCoderC(){mBitCount = 0;mBitBuffer = 0;mLow = 0;mHigh = 0x7FFFFFFF; // just work with least significant 31 bitsmScale = 0;mBuffer = 0;mStep = 0;}void ArithmeticCoderC::SetFile( fstream *file ){mFile = file;}void ArithmeticCoderC::SetBit( const unsigned char bit ){// add bit to the buffermBitBuffer = (mBitBuffer << 1) | bit;mBitCount++;if(mBitCount == 8) // buffer full{// writemFile->write(reinterpret_cast<char*>(&mBitBuffer),sizeof(mBitBuffer));

Page 24: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mBitCount = 0;}}void ArithmeticCoderC::SetBitFlush(){// fill buffer with 0 up to the next bytewhile( mBitCount != 0 )SetBit( 0 );}unsigned char ArithmeticCoderC::GetBit(){if(mBitCount == 0) // buffer empty{if( !( mFile->eof() ) ) // file read completely?mFile->read(reinterpret_cast<char*>(&mBitBuffer),sizeof(mBitBuffer));elsemBitBuffer = 0; // append zerosmBitCount = 8;}// extract bit from bufferunsigned char bit = mBitBuffer >> 7;mBitBuffer <<= 1;mBitCount--;return bit;}void ArithmeticCoderC::Encode( const unsigned int low_count,const unsigned int high_count,const unsigned int total )// total < 2ˆ29{// partition number space into single stepsmStep = ( mHigh - mLow + 1 ) / total; // interval open at the top => +1// update upper boundmHigh = mLow + mStep * high_count - 1; // interval open at the top => -1// update lower boundmLow = mLow + mStep * low_count;// apply e1/e2 scalingwhile( ( mHigh < g_Half ) || ( mLow >= g_Half ) ){if( mHigh < g_Half ){SetBit( 0 );mLow = mLow * 2;mHigh = mHigh * 2 + 1;// perform e3 scalingsfor(; mScale > 0; mScale-- )SetBit( 1 );}else if( mLow >= g_Half ){SetBit( 1 );

Page 25: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mLow = 2 * ( mLow - g_Half );mHigh = 2 * ( mHigh - g_Half ) + 1;// perform e3 scalingsfor(; mScale > 0; mScale-- )SetBit( 0 );}}// e3while( ( g_FirstQuarter <= mLow ) && ( mHigh < g_ThirdQuarter ) ){// keep necessary e3 scalings in mindmScale++;mLow = 2 * ( mLow - g_FirstQuarter );mHigh = 2 * ( mHigh - g_FirstQuarter ) + 1;}}void ArithmeticCoderC::EncodeFinish(){// There are two possibilities of how mLow and mHigh can be distributed,// which means that two bits are enough to distinguish them.if( mLow < g_FirstQuarter ) // mLow < FirstQuarter < Half <= mHigh{SetBit( 0 );for( int i=0; i<mScale+1; i++ ) // perform e3-scalingSetBit(1);}else // mLow < Half < ThirdQuarter <= mHigh{SetBit( 1 ); // zeros added automatically by the decoder; no need to send them}// empty the output bufferSetBitFlush();}void ArithmeticCoderC::DecodeStart(){// Fill buffer with bits from the input streamfor( int i=0; i<31; i++ ) // just use the 31 least significant bitsmBuffer = ( mBuffer << 1 ) | GetBit();}unsigned int ArithmeticCoderC::DecodeTarget( const unsigned int total )// total < 2ˆ29{// split number space into single stepsmStep = ( mHigh - mLow + 1 ) / total; // interval open at the top => +1// return current valuereturn ( mBuffer - mLow ) / mStep;}

Page 26: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

void ArithmeticCoderC::Decode( const unsigned int low_count,const unsigned int high_count ){// update upper boundmHigh = mLow + mStep * high_count - 1; // interval open at the top => -1// update lower boundmLow = mLow + mStep * low_count;// e1/e2 scalingwhile( ( mHigh < g_Half ) || ( mLow >= g_Half ) ){if( mHigh < g_Half ){mLow = mLow * 2;mHigh = mHigh * 2 + 1;mBuffer = 2 * mBuffer + GetBit();}else if( mLow >= g_Half ){mLow = 2 * ( mLow - g_Half );mHigh = 2 * ( mHigh - g_Half ) + 1;mBuffer = 2 * ( mBuffer - g_Half ) + GetBit();}mScale = 0;}// e3 scalingwhile( ( g_FirstQuarter <= mLow ) && ( mHigh < g_ThirdQuarter ) ){mScale++;mLow = 2 * ( mLow - g_FirstQuarter );mHigh = 2 * ( mHigh - g_FirstQuarter ) + 1;mBuffer = 2 * ( mBuffer - g_FirstQuarter ) + GetBit();}}

A.3 Model Base Class (header)

#ifndef __MODELI_H__#define __MODELI_H__#include "ArithmeticCoderC.h"enum ModeE{MODE_ENCODE = 0,MODE_DECODE};class ModelI{public:void Process( fstream *source, fstream *target, ModeE mode );protected:virtual void Encode() = 0;virtual void Decode() = 0;ArithmeticCoderC mAC;

Page 27: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

fstream *mSource;fstream *mTarget;};#endif

A.4 Model Base Class

#include "ModelI.h"void ModelI::Process( fstream *source, fstream *target, ModeE mode ){mSource = source;mTarget = target;if( mode == MODE_ENCODE ){mAC.SetFile( mTarget );// encodeEncode();mAC.EncodeFinish();}else // MODE_DECODE{mAC.SetFile( mSource );mAC.DecodeStart();// decodeDecode();}};

A.5 Model Order 0 (Header)

#ifndef __MODELORDER0C_H__#define __MODELORDER0C_H__#include "ModelI.h"class ModelOrder0C : public ModelI{public:ModelOrder0C();protected:void Encode();void Decode();unsigned int mCumCount[ 257 ];unsigned int mTotal;};#endif

A.6 Model Order 0

#include "ModelOrder0C.h"ModelOrder0C::ModelOrder0C(){// initialize probabilities with 1

Page 28: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

mTotal = 257; // 256 + escape symbol for terminationfor( unsigned int i=0; i<257; i++ )mCumCount[i] = 1;}void ModelOrder0C::Encode(){while( !mSource->eof() ){unsigned char symbol;// read symbolmSource->read( reinterpret_cast<char*>(&symbol), sizeof( symbol ) );if( !mSource->eof() ){// cumulate frequenciesunsigned int low_count = 0;for( unsigned char j=0; j<symbol; j++ )low_count += mCumCount[j];// encode symbolmAC.Encode( low_count, low_count + mCumCount[j], mTotal );// update modelmCumCount[ symbol ]++;mTotal++;}}// write escape symbol for terminationmAC.Encode( mTotal-1, mTotal, mTotal );}void ModelOrder0C::Decode(){unsigned int symbol;do{unsigned int value;// read valuevalue = mAC.DecodeTarget( mTotal );unsigned int low_count = 0;// determine symbolfor( symbol=0; low_count + mCumCount[symbol] <= value; symbol++ )low_count += mCumCount[symbol];// write symbolif( symbol < 256 )mTarget->write( reinterpret_cast<char*>(&symbol), sizeof( char ) );// adapt decodermAC.Decode( low_count, low_count + mCumCount[ symbol ] );// update modelmCumCount[ symbol ]++;mTotal++;}while( symbol != 256 ); // until termination symbol read}

Page 29: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

A.7 Tools

#ifndef __TOOLS_H__#define __TOOLS_H__int inline min( int a, int b ){return a<b?a:b;};#endif

A.8 Main

#include <iostream>#include <fstream>using namespace std;#include "ModelOrder0C.h"// signature: "ACMC" (0x434D4341, intel byte order)// (magic number for recognition of encoded files)const int g_Signature = 0x434D4341;int __cdecl main(int argc, char *argv[]){cout << "Arithmetic Coding" << endl;if( argc != 3 ){cout << "Syntax: AC source target" << endl;return 1;}fstream source, target;ModelI* model;// choose model, here just order-0model = new ModelOrder0C;source.open( argv[1], ios::in | ios::binary );target.open( argv[2], ios::out | ios::binary );if( !source.is_open() ){cout << "Cannot open input stream";return 2;}if( !target.is_open() ){cout << "Cannot open output stream";return 3;}unsigned int signature;source.read(reinterpret_cast<char*>(&signature),sizeof(signature));if( signature == g_Signature ){cout << "Decoding " << argv[1] << " to " << argv[2] << endl;model->Process( &source, &target, MODE_DECODE );}else{

Page 30: Eric Bodden Malte Clasen Joachim Kneisac.upg-ploiesti.ro/gpanaitescu/codarea_aritmetica.pdf · corespunde metodei matematice folosite la constructia figurii de mai sus. Aspectul cel

cout << "Encoding " << argv[1] << " to " << argv[2] << endl;source.seekg( 0, ios::beg );target.write( reinterpret_cast<const char*>(&g_Signature),sizeof(g_Signature) );model->Process( &source, &target, MODE_ENCODE );}source.close();target.close();return 0;}