Bezstratová kompresia súborov archivácia Maroš Gajdošík, 4.A, 2003/2004 Archiváciu pozná takmer každý, kto má doma počítač. Ide o celkom častú rutinu, ktorá šetrí miesto na disku alebo naše peniaze. Taktiež poskytuje dobrú ochranu proti krádeži údajov. Myšlienku kompresie údajov zaviedol v roku 1800 pán Samuel Morse. Ten častejším znakom priradil kratšie kódy a zriedkavejším znakom dlhšie kódy. Vznikla tak Morseova abeceda a telegrafické zariadenie. Existujú mnohé programy poskytujúce rôzne formáty archívov. Dnes je už normálne, že sa navzájom dobre poznajú a vedia spolupracovať síce si navzájom konkurujú. Napr. prostredníctvom programu WinRAR môžete manipulovať s archívom *.ace alebo naopak. Dneska sú na čele tieto formáty: ZIP, RAR, ACE, LHA, LZH, ARJ, CAB, TAR, UUE, GZIP atď. Huffmanovo kódovanie Huffmanov algoritmus tvorby kódu generuje binárne stromy, kde cesty z počiatočného do koncového uzlu umožňujú vytvoriť kódové slová. Majme vstupnú abecedu danú iba znakmi A, B, C, D a E s danou pravdepodobnosťou výskytu 0,4; 0,1; 0,1; 0,1 a 0,3. Súčet pravdepodobností je rovný 1 a teda dané znaky tvoria celú abecedu. Jednotlivé znaky si zoradíme vzostupne podľa stúpajúcich pravdepodobností výskytu. Vyberieme dva znaky s najnižšou pravdepodobnosťou a sčítame ich pravdepodobnosti, pričom pod súčet podpíšeme znaky z ktorých súčtom vznikol. Ak je viac znakov s rovnakou pravdepodobnosťou, môžeme do súčtu vziať ľubovolný z nich. Vzniknutý súčet 0,2 tvorí uzol stromu. V bodoch 2. a 4. postupujeme obdobným spôsobom ako v 1. V bode 5. sme dospeli až k vrcholu stromu, ktorý musí mať vždy hodnotu rovnú jednej a tvorba stromu sa skončila. Všimnite si, že všetky znaky (A, B, C, D a E) ležia v listoch stromu. 1. 0,1 0,1 0,1 0,3 0,4 B C D E A 2. 0,1 0,2 0,3 0,4 D / \ E A B C 3. 0,3 0,3 0,4 / \ E A D 0,2 / \ B C 4. 0,4 0,6 A / \ 0,3 E / \ D 0,2 / \ B C 5. 1 alebo 1 alebo 1... A 0,6 0,6 A 0,6 A E 0,3 0,3 E E 0,3 D 0,2 0,2 D D 0,2 B C C B B C
Jednotlivé vetvy stromu si označíme binárnymi hodnotami 0 a 1 (označené sú modrou farbou) a môžeme začať z binárneho stromu odčítavať kódy prislúchajúce daným znakom. Začíname od vrcholu stromu a ľavou vetvou sa dostaneme k znaku A. Vetve ktorou sme išli prislúcha hodnota 0 a teda Huffmanov kód pre znak A bude 0. Analogickým spôsobom pri pohybe po vetvách stromu až k daným znakom získame ostatné Huffmanové kódy. Získané Huffmanové kódy pre znaky A, B, C, D a E sú v tabuľke v treťom stĺpci. Povšimnite si, že rôznym otáčaním vetiev v binárnom strome (druhý a tretí strom v bode 5.) a následnej konštrukcii Huffmanových kódov, získame pre danú abecedu rôzne kódy. Všetky riešenia sú správne. Dôležité je, že takto získaný kód má niektoré významné vlastnosti. - Huffmanovým algoritmom vytvoríme kódy s minimálnou dĺžkou - Huffmanové kódy sú prefixové a teda sú jednoznačne dekódovateľné. Prefixové kódy musia spĺňať tzv. podmienku prefixu, ktorá hovorí, že žiadne kódové slovo nesmie byť prefixom (počiatkom) reťazca iného kódového slova. Prefixový kód je jednoznačne dekódovateľný. Každý prefixový kód môžeme zobraziť pomocou binárneho stromu. V praxi to znamená asi toľko, že ak kóder vyšle napríklad kódy (podľa tretieho stĺpca tabuľky) 1111100 odpovedajúce znakom C E A, dekóder ich bude vedieť jednoznačne dekódovať bez toho, aby sme jednotlivé kódy oddeľovali pomocou nejakých oddeľovacích značiek. Prirodzene, že dekóder musí disponovať rovnakou tabuľkou Huffmanových kódov (musí poznať strom ktorý vytvoril kóder) ktoré použil kóder pri kódovaní znakov. Jednoducho musí vedieť že 110 odpovedá znaku D atď. Postup: dekóder príjme prvú hodnotu 1 a žačne sa pohybovať od vrcholu stromu až k jednotlivým listom. Po štyroch vetvách s hodnotami 1 sa dostane k listu, ktorému odpovedá znak C (1111). Z listu sa už ďalej nemôže pohnúť a vie, že ak sa dostal do listu, nasledujúca hodnota ktorú bude dekódovať, bude počiatkom kódového slova ďalšieho znaku (začne postupovať znova od vrcholu stromu). Toto je nesmierne dôležité, pretože takto môžeme kód jednoznačne dekódovať. Aritmetické kódovanie Aritmetické kódovanie predstavuje ďalšiu efektívnu kompresnú metódu a je kandidátom na nahradenie Huffmanovho kódovania v rôznych aplikáciách, pretože dáva lepšie kompresné výsledky o 5 až 10%, aj keď za cenu náročných aritmetických operácií s veľkými reálnymi číslami. Je veľmi náročné na pamäť a výkon procesora. Aritmetické kódovanie nepracuje na princípe nahradzovania vstupného znaku špecifickým kódom. Namiesto toho, kódovaný vstupný tok znakov nahradí jedným reálnym číslom z intervalu <0,1). Na začiatku uvažujeme celý tento interval. Ako sa správa predlžuje, spresňuje sa i výsledný interval a jeho horná a dolná hranica sa k sebe približujú. Čím je kódovaný znak pravdepodobnejší, tím sa interval zúži menej a k zápisu dlhšieho intervalu stačí menej bitov. Spôsob aritmetického kódovania si ukážeme na príklade správy baca. Znak Pravdepodobnosť a 0.5 b 0.25 c 0.25 Pravdepodobnosti výskytu znakov sú nám známe a potrebujeme prideliť každému znaku určitý interval z rozsahu <0,1) na základe pravdepodobnosti jeho výskytu. Pritom nieje jedno, ktorému intervalu bude pridelený daný znak. Naše 3 znaky budú zaradené do jednotlivých intervalov nasledovne. Znak Pravdepodobnosť Interval a 0.5 0.00 0.50 b 0.25 0.50 0.75 c 0.25 0.75 1.00
Nakoľko, každý interval je vľavo uzavretý a vpravo otvorený tak napr. c bude v intervale 0.75-0.9999.... Dôležitý význam pri aritmetickom kódovaní má prvý kódovaný znak. Keď kódujeme správu baca, prvý znak je b. Začiatočný znak nám určuje, že správa bude zakódovaná ako číslo, ktoré sa nachádza v intervale odpovedajúceho prvému znaku. V našom prípade môžeme očakávať číslo v rozsahu 0.5-0.75. Takto sme zakódovali prvý znak. Rozsah sa nám zmenšil na 0.5-0.75. Ďalší znak je a a prináleží mu interval 0.0-0.5. V rozsahu 0.5-0.75 bude časť 0% - 50% (interval pre a je 0.0-0.5) z tohto rozsahu reprezentovať znak a. Tím sa nám rozsah zase zmenšil na rozmer 0.5-0.625. Analogickým spôsobom pokračujeme v delení intervalu ďalej. Trasovacia tabuľka pre Aritmetické kódovanie by mala vyzerať takto: Znak Dno Strop 0.0 1.0 a 0.5 0.75 b 0.59375 0.625 c 0.59375 0.609375 Výsledkom procesu kódovania je hodnota 0.59375, ktorá teraz reprezentuje správu baca. Proces dekódovania je nasledovný: Zakódovaná hodnota 0.59375 patrí do intervalu 0.5-0.75 a ten odpovedá znaku b. Prvý znak sme teda dekódovali. Teraz potrebujeme zmazať znak b zo zakódovanej hodnoty. Toto urobíme tak,že od zakódovanej hodnoty 0.59375 odpočítame krajnú hodnotu intervalu pre znak b 0.59375-0.5 = 0.09375 takto získanú hodnotu vydelíme rozsahom intervalu znaku b, teda číslom 0.75-0.5 0.09375 / 0.25 = 0.375 Zopakujeme predchádzajúce kroky pre všetky znaky. Pre náš príklad bude proces dekódovania prebiehať nasledovne: Číslo Znak Dno Strop Rozsah 0.59375 0.5 0.75 0.25 0.375 a 0.0 0.5 0.5 0.75 b 0.75 1.0 0.25 0 c 0.0 0.5 0.5
LZW (Lempel-Ziv-Welch) kompresia Komprimačný algoritmus označovaný ako LZW je pomenovaný podľa svojich objaviteľov pánov A.Lempela, J.Ziva a Terryho A.Welcha, ktorý pôvodný algoritmus LZ77 modifikovali. Jedná sa o bezstratovú komprimačnú metódu vhodnú na kompresiu grafických, bilineárnych a textových súborov. Rôzne modifikácie metódy LZW sa používajú v bežných komprimačných programov PKARC, PAK, PKZIP, v UNIX-e príkaz "compress" ako aj pri formátoch počítačovej grafiky GIF, TIFF, PostScript a pod. Rôzne metódy tejto kompresie sú patentované firmami IBM, Unisys a Compuserve. Základným princípom kompresného algoritmu LZW je vyhľadávanie rovnakých, opakujúcich sa reťazcov v spracovávanom vstupnom súbore a priraďovať im kódy. Nasledujúci príklad ukazuje veľmi zjednodušene (v samotnom algoritme LZW je to zložitejšie) kompresiu pomocou slovníka. Predpokladáme, že slovník má kapacitu 4096 položiek. Z toho vyplýva, že jednotlivé kódy budú reprezentované pomocou 12 bitov. Kódy 0-255 v slovníku sú vyhradené a predstavujú jednotlivé byty (napr. ASCII znaky) vstupného súboru. Kompresia sa dosahuje použitím kódov 256 až 4095, ktoré reprezentujú reťazce. Napr. kód 256 reprezentuje sekvenciu 3 bytov: 145, 201, 4. Vždy keď kompresný algoritmus narazí na tento reťazec vo vstupnom súbore umiestni kód 256 do výstupného kódovaného súboru. Pri dekompresii je kód 256 preložený pomocou slovníka do pôvodnej sekvencie bytov 145 201 4. Dlhé reťazce pripadajúce jednotlivým kódom a ich častý výskyt vo vstupnom súbore vedie k vysokej kompresii. Príklad slovníka s 4096 položkami: kód reťazce 0000 0 0001 1 : : 0254 254 0255 255 0256 145 201 4 0257 243 245 : : 4096 XXX XXX XXX Algoritmus LZW pracuje so slovníkom, ktorý sa adaptívne prispôsobuje kódovaným dátam. Táto adaptívna metóda vytvára dynamický substitučný slovník. Slovník nieje potrebné prenášať pre potreby dekompresie, pretože dekompresor si vie z prijímaných dát vytvoriť vlastný duplicitný slovník.
CHAR STRING +CHAR Je v sl.? VýstupPridaj do slovníku Nový Komentár STRING 1 t t nie t prvý znak prečítaný - nič sa nedeje 2 h th nie t 256=th h 3 e he nie h 257=he e 4 / e/ nie e 258=e/ / 5 r /r nie / 259=/r r 6 a ra nie r 260=ra a 7 i ai nie a 261=ai i 8 n in nie i 262=in n 9 / n/ nie n 263=n/ / 10 i /i nie / 264=/i i 11 n in áno(262) in prvý opakujúci sa reťazec nájdený 12 / in/ nie 262 265=in/ / 13 S /S nie / 266=/S S 14 p Sp nie S 267=Sp p 15 a pa nie p 268=pa a 16 i ai áno(261) ai našiel ai, ale ain ešte nieje v slovníku 17 n ain nie 261 269=ain n pridaj ain do slovníku 18 / n/ áno(263) n/ 19 f n/f nie 263 270=n/f f 20 a fa nie f 271=fa a 21 l al nie a 272=al l 22 l ll nie l 273=ll l 23 s ls nie l 274=ls s 24 / s/ nie s 275=s/ / 25 m /m nie / 276=/m m 26 a ma nie m 277=ma a 27 i ai áno(261) ai našiel ai v slovníku 28 n ain áno(269) ain našiel aj dlhší reťazec, ain 29 l ainl nie 269 278=ainl l 30 y ly nie l 279=ly y 31 / y/ nie y 280=y/ / 32 o /o nie / 281=/o o 33 n on nie o 282=on n 34 / n/ áno(263) n/ 35 t n/t nie 263 283=n/t t 36 h th áno(256) th našiel th, ale the ešte nieje v slovníku 37 e the nie 256 284=the e pridaj the do slovníku 38 / e/ áno(258) e/ 39 p e/p nie 258 285=e/p p 40 l pl nie p 286=pl l 41 a la nie l 87=la a 42 i ai áno(261) ai našiel ai v slovníku 43 n ain áno(269) ain našiel aj dlhší reťazec, ain 44 / ain/ nie 269 288=ain/ / 45 EOF / / end of file, výstup STRING