algoritmi za sažimanje podataka bez gubitka informacije

29
FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA ZAVOD ZA PRIMIJENJENO RAČUNARSTVO SEMINARSKI RAD: ALGORITMI ZA SAŽIMANJE PODATAKA BEZ GUBITKA INFORMACIJE Predmet: Strukture podataka i algoritmi Nastavnik: prof. dr. sc. Vedran Mornar Student: Miroslav Štampar, dipl. ing. MB: R-10/2008 Datum: 22.7.2010.

Upload: miroslav-stampar

Post on 15-Dec-2014

93 views

Category:

Documents


8 download

DESCRIPTION

Seminarski rad

TRANSCRIPT

Page 1: Algoritmi za sažimanje podataka bez gubitka informacije

FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA

ZAVOD ZA PRIMIJENJENO RAČUNARSTVO

SEMINARSKI RAD:

ALGORITMI ZA SAŽIMANJE PODATAKA BEZ GUBITKA INFORMACIJE

Predmet: Strukture podataka i algoritmi

Nastavnik: prof. dr. sc. Vedran Mornar

Student: Miroslav Štampar, dipl. ing.

MB: R-10/2008

Datum: 22.7.2010.

Page 2: Algoritmi za sažimanje podataka bez gubitka informacije
Page 3: Algoritmi za sažimanje podataka bez gubitka informacije

Sadržaj1. Uvod...................................................................................................................................1

2. Algoritmi.............................................................................................................................2

2.1. RLE.............................................................................................................................2

2.2. Shannon-Fano............................................................................................................3

2.3. Huffman......................................................................................................................6

2.4. Lempel-Ziv-Welch.......................................................................................................8

3. Praktični uradak...............................................................................................................13

4. Zaključak..........................................................................................................................15

5. Literatura..........................................................................................................................16

Dodatak A: Programski kod.................................................................................................17

A.1. RLE.py......................................................................................................................17

A.2. Shannon-Fano.py.....................................................................................................18

A.3. Huffman.py...............................................................................................................20

A.4. LZW.py.....................................................................................................................22

A.5. Utils.py......................................................................................................................24

Dodatak B: Dijagrami rezultata............................................................................................25

B.1. Koeficijenti sažimanja...............................................................................................25

B.2. Vremena izvođenja...................................................................................................26

Page 4: Algoritmi za sažimanje podataka bez gubitka informacije

1.Uvod

1. Uvod

U računarnoj znanosti i teoriji informacije (engl. information theory) sažimanje podataka (engl. data compression), odnosno, kodiranje podataka (engl. source coding) skupni je naziv za procese u kojima se kao rezultat informacije prikazuju korištenjem manjeg broja bitova (ili druge jedinice informacije) od onoga u izvornom obliku [1].

Sažimanje podataka podrazumijeva primjenu algoritama koji određene ponavljajuće nizove bitova čine suvišnima. Konačni rezultat može se zamisliti kao stenogram koji u sebi sadrži sve potrebne informacije kako bi se pri inverznom procesu ekpanzije (engl. decompression) rekonstruirali svi nedostajući bitovi.

Korisnost sažimanja podataka očituje se u tome što se njegovom primjenom smanjuje potrošnja skupih resursa kao što su prostor na čvrstom disku ili brzina prijenosnog kanala (engl. transmission bandwidth). Sažimanje se može koristiti nad svim vrstama datoteka, od tekstualnih, preko grafičkih i pokretačkih, pa sve do multimedijalnih, pri čemu se neke vrste datoteka sažimaju bolje od drugih.

Algoritmi za sažimanje podataka prema odnosu originalnih i rekonstruiranih podataka mogu se podijeliti u dvije skupine: algoritme bez gubitka informacije (engl. lossless data compression) te na algoritme s gubitkom informacije (engl. lossy data compression). U prvu skupinu spadaju oni algoritmi koji osiguravaju identičnu rekonstrukciju originalnog sadržaja iz sažetog oblika, dok u drugu skupinu spadaju oni koji omogućuju aproksimativnu rekonstrukciju originalnog sadržaja u zamjenu za bolju mjeru sažimanja (engl. compression ratio).

Kako bi algoritam za sažimanje pripadao klasi algoritama bez gubitka infomacije, mora postojati obrnuti proces preslikavanja iz sažetog bitovnog niza u originalni, odnosno, sama metoda sažimanja mora predstavljati bijekciju između originalnog i sažetog oblika. Većina takvih algoritama izvodi se u dva koraka: u prvom se koraku generira statistički model nad ulaznim podacima dok se u drugom koraku koristi isti taj model kako bi se mapirali ulazni podaci na izlazne bitovne nizove, i to na taj način da vjerojatniji (češći) podaci rezultiraju izlazom manje duljine od onih manje vjerojatnih.

U ovom će se uratku prezentirati teoretska i praktična obrada osnovnih algoritama za sažimanje bez gubitka infomacije čije razumijevanje predstavlja solidno polazište za daljnje istraživanje ove teme.

1

Page 5: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

2. Algoritmi

2.1. RLE

RLE (engl. krat. za Run-length encoding) naziv je za poprilično jednostavan i vrlo popularan algoritam namijenjen sažimanju podataka. Temelji se na ideji zamjene duljeg niza jednog te istog simbola sa sažetim kraćim nizom i to najčešće u obliku para vrijednosti simbola te broja ponavljanja istog.

Postoji više varijanti ovog algoritma, no osnovni postupak vidljiv je na slici 1. S trenutne pozicije uzima se vrijednost znaka te se prebrojava koliko znakova u nastavku ima jednaku vrijednost. Kao izlazna vrijednost zapisuje se dvostruka vrijednost trenutnog znaka te broj prebrojanih naknadnih ponavljanja tog istog znaka. Algoritam iterativno nastavlja s daljnjim radom pri čemu se kao nova trenutna pozicija uzima mjesto prvog znaka čija se vrijednost razlikuje od vrijednosti prethodno obrađenog.

Dobiveni broj ponavljanja najčešće se zapisuje u obliku vrijednosti znaka što u ASCII formatu predstavlja brojčanu vrijednost u rasponu 0-255. U slučaju da trenutni broj ponavljanja doseže zadanu gornju vrijednost prebrojavanje se prekida te postupa isto kao i u slučaju da smo naišli na znak različit od trenutno obrađivanog.

U osnovnoj se varijanti zapisuju svi ovako dobiveni parovi, tzv. „sažimajući kodovi” (engl. compression codes), redom jedan za drugim, što pri radu sa stvarnim „neprikladnim” podacima vrlo često rezultira drastičnim povećanjem veličine izlazne datoteke. U najgorem slučaju, kada je vrijednost svakog znaka različita od vrijednosti prethodnoga, odnosno, kada se u obrađivanim podacima ne može pronaći niti jedan istoznačni par znakova, tada se kao rezultat dobiva dvostruko veća veličina izlazne datoteke.

Kod svih naprednijih varijanti glavnu okosnicu čini način signaliziranja kodiranog oblika izlaznog para vrijednosti i broja ponavljanja među nepromijenjenim znakovima iz nesažetog oblika. Slijedi opis dviju takvih varijanti.

2

Slika 1: Primjer sažimanja podataka korištenjem RLE algoritma

Korak 1Korak 1

AA AA AA BB BB BB BB AA CC CC DD DD

AA 22

Korak 2Korak 2 BB 33

Korak 3Korak 3 AA 00

Korak 4Korak 4 CC 11

Korak 5Korak 5 DD 11

UlazUlaz

IzlazIzlaz AA 22 BB 33 AA 00 CC 11 DD 11

Page 6: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

U prvoj se varijanti početak sažimajućeg koda signalizira specijalnim znakom i/ili parom znakova koji se ne mogu pronaći u ulaznoj datoteci. U slučaju da se algoritmom procijeni da se zapisivanjem trenutnog sažimajućeg koda može dobiti na smanjenju duljine izlaznog oblika, tada se prvo zapisuje signalizirajuća vrijednost te nakon toga dobiveni sažimajući kod. U suprotnom se zapisuje vrijednost trenutnog znaka, nakon čega se u oba slučaja nastavlja s daljnjom obradom.

U drugoj se varijanti (slika 2) kao signal za sažimajući kod koristi par vrijednosti ponavljajućeg znaka (npr. AA) nakon kojeg slijedi broj prebrojanih daljnjih ponavljanja. Razlika između ove i prethodne varijante leži u tome što se kod ove mora kodirati i najmanji ponavljajući niz (par istovjetnih znakova, npr. CC), a može dovesti do neželjenog povećanja veličine izlaznog oblika, dok kod prethodne varijante to nije slučaj. Ovaj algoritam je najefikasnije koristiti nad podacima koji u sebi sadrže brojne nizove uzastopnih znakova (engl. runs) kao na primjer kod relativno jednostavnih grafičkih formata: ikona, vektorskih crteža i animacija. U protivnom, ukoliko datoteka ne sadrži dovoljan broj ovakvih nizova, sam proces sažimanja vrlo često može rezultirati povećanjem krajnje veličine datoteke.

U praktičnoj se primjeni algoritam RLE može pronaći u faks uređajima u kombinaciji s Huffman algoritmom (2.2.) pri čemu je vrlo pogodan stoga što većina faksiranih dokumenata u sebi sadrži vrlo velik broj praznina s povremenim znakovnim prekidom.

2.2. Shannon-Fano

Oko 1960. godine dvojica znanstvenika, Claude E. Shannon (MIT) i Robert M. Fano (Bell Laboratories), razvili su algoritam za sažimanje baziran na binarnom kodnom stablu, koji je strukturiran na temelju ulaznog skupa simbola te pripadnim vjerojatnostima pojavljivanja (izračunata ili procijenjena).

U polju podatkovnog sažimanja rezultat Shannon-Fano algoritma spada u grupu tzv. „prefiks kodiranja” (engl. prefix code). Za ovu je grupu algoritama značajno to da ni jedna generirana kodna riječ nije prefiks neke druge riječi, odnosno, ne postoji druga kodna riječ koja bi mogla nastati dodavanjem novih znakova na kraj promatrane

3

Slika 2: Primjer sažimanja podataka korištenjem varijante RLE algoritma

Korak 1Korak 1

AA AA AA BB BB BB BB AA CC CC DD DD

AA 11

Korak 2Korak 2 BB 22

Korak 3Korak 3 AA

Korak 4Korak 4 CC 00

Korak 5Korak 5 DD 00

UlazUlaz

IzlazIzlaz

AA

BB

CC

DD

AA 11AA BB 22BB AA CC 00CC DD 00DD

Page 7: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

riječi. Na primjer kod sa skupom riječi {2,12,11} spada u ovu vrstu kodova, dok kod sa skupom riječi {2,1,12,11} ne spada jer je kodna riječ 1 također i prefiks za kodne riječi 12 i 11. Vrlo bitna činjenica je ta da se na ovaj način otklanja potreba za korištenjem specijalnih signalizacijskih znakova na početku kodne riječi kao što je to bio slučaj kod prethodno opisanih varijanti RLE algoritma (2.1.).

Na početku obrade podataka stvara se tzv. „vjerojatnosna tablica” (engl. probability table). U nju se zapisuje broj pojavljivanja svakog pojedinačnog znaka iz ulaznog skupa znakova te izračunata vjerojatnost dobivena kao rezultat dijeljenja tog istog broja pojavljivanja s ukupnom duljinom ulaznog niza. Znakovi se u tablici drže poredano silazno po vjerojatnostima pojavljivanja kako bi se olakšalo daljnje izvođenje algoritma.

Proces izgradnje stabla započinje početnom podjelom skupa znakova na dva podskupa i to na način da se vodi računa da razlika ukupnog zbroja vjerojatnosti članova jedne i druge strane bude minimalna. Postupak se nad tako dobivenim podskupovima nastavlja iterativno sve dok se u njima može pronaći više od jednog znaka.

Nepisano je pravilo da se lijevi ogranci u tako dobivenom binarnom stablu označuju s binarnom brojkom 0, dok se desni označuju s brojkom 1. Završni binarni kod za traženi znak predstavlja put dobiven spuštanjem po stablu sve od početnog čvora, odnosno, vrha do pripadnog lista pri čemu se na izlazu zapisuju binarne oznake prođenih grana. Na kraju se pomoću tako dobivenih binarnih kodova vrši translacija iz ulaznog u izlazni niz znakova. Svaki se ulazni znak obrađuje po redu pojavljivanja te se pripadni binarni kod slijedno zapisuje dodavanjem na kraj izlaznog niza.

Da bi se omogućio povratak originalnog sadržaja iz sažetog binarnog, najčešće se sažetom obliku dodaje sadržaj vjerojatnosne tablice kako bi se pomoću njega u inverznom procesu ekspanzije ponovno moglo rekonstruirati binarno kodno stablo. Obrnuti postupak dekodiranja, odnosno, ekspanzije poprilično je jednostavan. Sažeti binarni niz predstavlja put do listova čije znakovne vrijednosti predstavljaju sadržaj originalne poruke. Postupak počinje obilaskom stabla iz početnog čvora pa sve do lista nakon čega se postupak iterativno nastavlja dalje s prvim sljedećim neobrađenim bitom.

Na slici 3 može se pronaći primjer korištenja ovog algoritma nad ulaznim nizom znakova AAAAAAABBBBBCCCCDDDDEEE. Kao što se može vidjeti, u prvom koraku se stvara vjerojatnosna tablica u kojoj je sadržan broj pojavljivanja svakog pojedinačnog znaka iz ulaznog skupa znakova te izračunata vjerojatnost pojavljivanja istih. Nakon toga se u drugom koraku stvara binarno kodno stablo korištenjem podataka iz vjerojatnosne tablice.

U prvom se nivou stabla skup simbola dijeli na dvije podskupine, i to u ovom slučaju na {A,B} s jedne strane te {C,D,E} s druge. Vidljivo je da je ukupan zbroj vrijednosti vjerojatnosti lijeve strane (0.521) približno jednak zbroju s desne strane što pokazuje da se vodilo računa da njihova razlika bude što manja.

4

Page 8: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

Nadalje se u drugom nivou lijeva strana jednostavno podijeli na dva lista s vrijednostima dvaju preostalih znakova, dok se desna strana opet dijeli na dva podskupa i to na list s vrijednošću C s jedne strane te čvor {D,E} s druge. Na kraju se preostali podskup {D,E} dijeli na dva lista s pripadnim vrijednostima znakova.

U trećem se koraku vrši samo kodiranje, odnosno pretvorba iz ulaznog znakovnog oblika u izlazni sažeti binarni. Početni simbol A pretvara se u binarni kod 00 dobiven prolaskom kroz stablo od početnog čvora stabla do odgovarajućeg istoimenog lista. Kao što se na slici može jasno primjetiti, do pripadnog lista došlo se spuštanjem dva puta ulijevo od početnog čvora, a to u binarnom obliku predstavlja niz 00. Postupak se nastavlja iterativno dalje sve do kraja ulaznog niza znakova.

Kaže se da je ovaj algoritam podoptimalan u smislu da se njime ne postižu kodne riječi najmanje moguće duljine kao što je to slučaj kod Huffman algoritma (2.2.), no za razliku od istog, garantirano je da će dobivene kodne riječi biti duljine unutar jednog bita od teoretskog optimuma – logP x [2].

5

Slika 3: Primjer sažimanja podataka korištenjem Shannon-Fano algoritma

AA BB CC DD EE

Korak 1Korak 1

UlazUlaz AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

Znak A B C D E

Učestalost 7 5 4 4 3

Vjerojatnost 0.304 0.217 0.174 0.174 0.130

AA BB CC DD EE

AA BB CC DD EE

AA BB CC

DD EE

Korak 2Korak 2 a)a)

b)b)

c)c)

d)d)

Korak 3Korak 3

00 11

00 11

00 11 0011

00 11

00 11 00 11

00 11

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00

a)a)

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00

00 00

00 00

b)b)

......

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00 11

h)h)

......

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

11

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

11

u)u)

v)v)

11

11 11

11

IzlazIzlaz 0000000000000001010101011010101011011011011011111111100000000000000010101010110101010110110110110111111111 22

Page 9: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

U usporedbi s ostalim metodama, Shannon-Fano algoritam poprilično je jednostavan za implementaciju, no njegova praktična vrijednost i nije od neke pretjerane važnosti. To je prvenstveno uzrokovano manjom efikasnošću dobivenog sažetog koda u usporedbi s vrlo sličnim Huffman algoritmom.

Korištenje ove metode sažimanja ima smisla samo ukoliko želimo upotrijebiti jednostavan algoritam sa zamjetnim performansama i minimalnim zahtjevima za implementacijom. Kao primjer praktične uporabe ovog algoritma može se uzeti metoda IMPLODE opisana u specifikaciji datotečnog formata ZIP [3].

Bitno je napomenuti da kod ovog i sličnih algoritama ulazna jedinica ne mora nužno biti jedan znak, odnosno, simbol, no izlazna je vrijednost uvijek u binarnom obliku. Danas se u praktičnoj primjeni mogu pronaći tzv. „hibridi” ove vrste kodiranja i algoritama sažimanja čiji se princip bazira na primjeni rječnika (npr. Lempel-Ziv-Welch 2.4). Na taj se način naglašavaju prednosti i otklanjanju mane pojedinačnih metoda za sažimanje.

2.3. Huffman

Korištenjem Shannon-Fano algoritma, opisanog u prethodnom odjeljku, ne dobiva se teoretski optimalan kod. Kao odgovor 1952. godine David A. Huffman objavljuje rad [2] u kojem opisuje algoritam koji uvijek rezultira optimalnim, binarnim, kodnim stablom za date vjerojatnosti ulaznog skupa znakova. Dok se u slučaju Shannon-Fano algoritma (2.2.) stablo stvara od vrha prema dnu, Huffman algoritam ga stvara od listova prema korijenu stabla, odnosno, u obrnutom smjeru.

David A. Huffman, student doktorskog studija na sveučilištu MIT, 1951. godine dobiva na izbor seminarski rad ili završni ispit na kolegiju profesora Robert M. Fanoa. Kao zadatak seminarskog rada zadan je problem pronalaska najefikasnijeg binarnog koda. Huffman, u nemogućnosti dokazivanja efikasnosti ijednog algoritma kodiranja, umalo odustaje i započinje s učenjem za završni ispit, dok mu najednom nije sinula ideja o metodi u kojoj bi koristio vjerojatnosno sortirano binarno stablo. Vrlo je brzo dokazano da je ta metoda najefikasnija.

Time je student doslovno nadmašio profesora, koji je zajedno s osnivačem „teorije informacije” (engl. information theory) Claude Shannonom radio na razvoju slične metode kodiranja koja je opisana u prethodnom poglavlju (2.2.). Glavni doprinos Huffmana je u njegovu ukazivanju na glavni propust sad već podoptimalnog Shannon-Fano algoritma, a to je da se binarno kodno stablo gradilo od vrha prema dnu, umjesto u obrnutom smjeru.

Algoritam započinje, kao i u slučaju Shannon-Fano algoritma, stvaranjem vjerojatnosne tablice s podacima o broju pojavljivanja svakog pojedinog znaka u ulaznom nizu znakova te izračunatom vjerojatnošću svakog od njih pojedinačno.

U drugom se koraku koristi sortirana lista strukturiranih elemenata u kojima se nalazi vrijednost simbola te pripadne vjerojatnosti. Na početku se uzimaju prva dva elementa s najnižim vjerojatnostima kako bi se iz njih napravio ogranak stabla pri čemu se obično s lijeve strane stavlja onaj element s većom vjerojatnošću, dok se s desne strane stavlja element s manjom vjerojatnošću. Vrh novodobivenog ogranka

6

Page 10: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

stavlja se natrag u sortiranu listu na pripadno mjesto, a u nastavku se obrađuje zajedno s ostalim elementima, dok se zadnja dva obrađena elementa uklanjaju.

Postupak se nastavlja iterativno sve dok ne ostane samo jedan element u sortiranoj listi. Taj završni element ne predstavlja ništa drugo doli binarno kodno stablo koje će se u nastavku koristi za kodiranje ulaznog niza podataka u sažeti kodirani oblik. Binarni kod za svaki pojedinačni element predstavlja, kao i u slučaju Shannon-Fano algoritma, put od vrha stabla do lista s vrijednosti pripadnog znaka pri čemu su pojedine grane ponovno označene s binarnim brojkama 0 (lijevo) i 1 (desno).U danom primjeru (slika 4) je kao ulaz uzet niz znakova: AAAAAAABBBBBCCCCDDDDEEE. Na početku rada algoritma stvara se vjerojatnosna tablica koja u sebi sadrži broj pojavljivanja i izračunatu vjerojatnost svakog pojedinog znaka iz ulaznog skupa znakova. U drugom se koraku koristi sortirana lista elemenata s vrijednostima znakova i pripadnim vjerojatnostima iz vjerojatnosne tablice od najučestalijeg A prema najrjeđem E. Na početku se stvara ogranak sa zadnja dva elementa D (lijevo) i

E (desno), stavlja se na pripadno mjesto u sortiranu listu, dok se obrađeni elementi s vrijednostima D i E brišu iz liste. U nastavku se analogno obrađuju elementi s vrijednostima B i C i tako dalje sve dok kao zadnji element sortirane liste ne ostane element koji predstavlja završno binarno kodno stablo.

7

Slika 4: Primjer sažimanja podataka korištenjem Huffman algoritma

Korak 1Korak 1

UlazUlaz AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

Znak A B C D E

Učestalost 7 5 4 4 3

Vjerojatnost 0.304 0.217 0.174 0.174 0.130

Korak 2Korak 2 a)a)

b)b)

c)c)

d)d)

Korak 3Korak 3 AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00

a)a)

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00

00 00

00 00

b)b)

......

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

11 00

h)h)

......

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

00

AAAAAAABBBBBCCCCDDDDEEEAAAAAAABBBBBCCCCDDDDEEE

11

u)u)

v)v)

11

00 11

11

IzlazIzlaz 0000000000000010101010101111111101001001001101101100000000000000101010101011111111010010010011011011 22

DD EE00

77

11

AA

77

BB

55

CC

44

DD

44

EE

33

AA

77

BB

55

CC

44

DD EE00

77

11

AA

77

BB CC00

99

11

DD EE00

77

11

AA00

1414

11

BB CC00

99

11

e)e)

DD EE00

77

11

AA00

1414

11

BB CC00

99

11

00

2323

11

Page 11: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

Završni korak algoritma čini samo kodiranje. Početni znak A zamjenjuje se binarnim kodom 00 koji predstavlja put obilaska stabla od vrha, odnosno početka stabla pa sve do dna, odnosno, lista koji u sebi sadrži vrijednost traženog znaka. Postupak se iterativno nastavlja sve do završnog znaka ulaznog niza.

Inverzni postupak ekspanzije (dekodiranja) identičan je onom kod Shannon-Fano algoritma. Za njegov uspješan rad također je potrebno spremanje tablice vjerojatnosti zajedno s izlaznim kodiranim binarnim nizom. Sam format spremanja nije zadan te varira od implementacije do implementacije.

Valja napomenuti da postoje varijante u kojima se pokušalo izbjeći moguće nedostatke vezane uz korištenje vjerojatnosne tablice opisane u izvornom postupku. U nastavku bit će spomenute dvije značajnije i ujedno najčešće korištene kojima se prvenstveno može izbjeći problem transporta sadržaja vjerojatnosne tablice.

Prva i najjednostavnija varijanta je ona u kojoj se koristi predefinirano binarno kodno stablo ovisno o sadržaju ulaznog niza podataka. U slučaju da je riječ o tekstu iz engleskog govornog područja uzima se vjerojatnosna tablica nastala na temelju poznate distribucije znakova u općem slučaju [4] i pripadno binarno stablo. Isto tako mogu se koristiti vjerojatnosne tablice za bilo koju vrstu podataka ukoliko se njihov sadržaj dobije na temelju distribucije simbola na dovoljno velikom uzorku.

Druga varijanta je tzv. „adaptivna” (engl. adaptive) ili „dinamična” (engl. dynamic). U njoj se stablo gradi, odnosno, prilagođava sa svakim novim znakom čime se izbjegava potreba za prethodnim prebrojavanjem učestalosti svih znakova ulaznog niza te sam prijenos završne tablice s izlaznim kodiranim podacima. Njezin detaljan opis može se pronaći u sadržaju radova [5] navedenih na kraju ovog uratka.

Huffman algoritam sažimanja, odnosno kodiranja, jedan je od najčešće korištenih i najviše referenciranih algoritama u svom području. Rjeđe se koristi pojedinačno u svom izvornom obliku, dok se najčešće koristi u završnoj fazi nekog drugog algoritma za sažimanje (npr. Lempel-Ziv-Welch 2.4). U praktičnoj primjeni se može pronaći u metodi DEFLATE datotečnog formata ZIP [3] te u multimedijalnim formatima kao što su JPEG i MP3.

2.4. Lempel-Ziv-Welch

Dvojica izraelskih znanstvenika Abraham Lempel i Jakob Ziv u nizu publikacija opisuju niz algoritama za sažimanje. U najznačajnije spadaju tzv. „adaptivni algoritmi bazirani na rječnicima” (engl. adaptive dictionary-based): LZ77 i LZ78. Do dana današnjeg stvoreno je mnoštvo naprednih varijanti baziranih upravo na ova dva algoritma: LZMA, LZJB, LZAP, LZMW, LZW... U ovom će se poglavlju dati poseban osvrt na najpoznatiju i najčešće korištenu varijantu – LZW (engl. krat. za Lempel–Ziv–Welch).

Lempel i Ziv su prvi algoritam objavili 1977. godine [6] od kuda i samo ime LZ77. Za ovaj je algoritam karakteristično da evidenciju o korištenom rječniku sadržava unutar samih izlaznih podataka. Recimo da želimo sažeti sljedeći niz znakova: the quick brown fox jumps over the lazy dog. Riječ the pojavljuje se dva puta u navedenom nizu znakova te se podaci mogu sažeti na sljedeći način: the quick brown for jumps

8

Page 12: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

over << lazy dog, pri čemu << u ovom slučaju predstavlja pokazivač (engl. pointer) na prva 4 znaka u nizu.

Isti dvojac 1978. godine objavljuje drugi u nizu uradaka [7] u kojem se opisuje sličan algoritam nazvan LZ78. Bitna razlika naspram prethodne inačice leži u činjenici da ovaj algoritam čuva rječnik kao zasebnu strukturu.

Recimo da želimo sažeti prethodni pokazni niz znakova (the quick brown fox jumps over the lazy dog) koristeći ovaj algoritam. Riječ the pojavljuje se dva puta u navedenom nizu te se na njezino mjesto stavlja indeks na pridjeljenu poziciju u internom rječniku što je u ovom slučaju naznačeno znakom *: * quick brown fox jumps over * lazy dog.

1984. godine Terry Welch radi na algoritmu za sažimanje namijenjenom za uporabu u diskovnim kontrolerima s visokim performansama. Osmislio je poprilično jednostavan algoritam nazvan LZW koji je zasnovan na algoritmu LZ78.

Algoritam LZW vrši zamjenu nizova znakova varijabilne veličine s jednim kodom predefinirane veličine, pri čemu nije potrebna prethodna analiza na ulaznom nizu znakova. Umjesto analize, tijekom obrade, dodaje se svaki novi niz znakova u tzv. „rječnik” (engl. dictionary).

Kod koji producira LZW algoritam može biti bilo koje predefinirane veličine, no mora biti veće veličine od broja bitova jednog znaka. Prvih 256 kodova (ukoliko se koriste 8-bitni znakovi) obično se dodjeljuje standardnim znakovima. Ostatak se slobodnih kodova dodjeljuje nizovima kako algoritam napreduje. Najčešće se kao veličina izlaznog koda uzima 12 bita što znači da su kodovi u rasponu 0-255 rezervirani za pojedinačne bajtove dok oni u rasponu 256-4095 predstavljaju „zamijećene” nizove.

U danom je primjeru (slika 5) kao ulaz uzet niz znakova: ABBABABAC. Pretpostavimo da se naša abeceda sastoji samo od znakova {A,B,C}. U tom je slučaju sadržaj rječnika na početku rada algoritma popunjen samo s tim znakovima što se može vidjeti na slici. U prvom se koraku iz rječnika uzima najveći prepoznati niz znakova od trenutne pozicije, što u ovom slučaju predstavlja znak A, te se na izlaz zapisuje pripadajući indeks (odnosno kod): 1. Trenutno najveći prepoznati niz znakova A zajedno s prvim sljedećim znakom B tvori novi niz znakova AB što se sukladno dodaje na kraj rječnika kao nova riječ. U sljedećem se koraku kao trenutni uzima prvi sljedeći znak (B), koji se na kraju prethodnog koraka već koristio pri stvaranju nove riječi (AB), te algoritam iterativno nastavlja dalje s radom sve do posljednjeg znaka u ulaznom nizu znakova.

Rječnik se gradi na identičan način neovisno je li riječ o sažimanju ili ekspanziji. U oba slučaja čim algoritam zamijeti novi niz znakova zapisuje ga u interni rječnik te mu pridodjeljuje pripadni kod. No, ukoliko se kod postupka sažimanja nova riječ upotrijebila odmah nakon dodavanja u rječnik, kod ekspanzije sam indeks, odnosno riječ u rječniku, nije moguće prepoznati. U tom se slučaju nepoznata riječ rekonstruira tako da se uzme prethodno korištena riječ te joj se na kraj doda prvo slovo te iste riječi (korak 5 na slici 6).

9

Page 13: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

Primjer za ekspanziju može se pronaći na slici 6 pri čemu je kao ulaz uzet izlaz iz prethodnog primjera za sažimanje (slika 5). Kao i u prethodnom primjeru, sadržaj rječnika je u početku popunjen samo sa znakovima pretpostavljene abecede: {A,B,C}. U prvom koraku nije moguće odrediti novu riječ tako da se u njemu izvodi samo pogled u rječnik i zapisivanje indeksom zadane riječi A na kraj izlaznog niza. U drugom se koraku indeksirana riječ B zapisuje na izlaz te se pomoću kompletnog sadržaja prethodne riječi A i prvog slova trenutne riječi B dobiva nova riječ AB koja se dodaje u rječnik. U narednim koracima postupak ostaje isti kao i u drugom koraku, osim u slučaju petog koraka koji je opisan u prethodnom dijelu teksta.

10

Slika 5: Primjer sažimanja podataka korištenjem LZW algoritma

UlazUlaz ABBABABACABBABABAC

IzlazIzlaz

Korak 1Korak 1 ABBABABACABBABABAC

11

AA 11

BB 22

CC 33

ABAB 44

Korak 2Korak 2 ABBABABACABBABABAC

22

AA 11

BB 22

CC 33

BBBB 55

ABAB 44

Korak 3Korak 3 ABBABABACABBABABAC

22

AA 11

BB 22

CC 33

BABA 66

ABAB 44

BBBB 55

Korak 4Korak 4 ABBABABACABBABABAC

44

AA 11

BB 22

CC 33

ABAABA 77

ABAB 44

BBBB 55

BABA 66

Korak 5Korak 5 ABBABABACABBABABAC

77

AA 11

BB 22

CC 33

ABACABAC 88

ABAB 44

BBBB 55

BABA 66

ABAABA 77

Korak 6Korak 6 ABBABABACABBABABAC

33

AA 11

BB 22

CC 33

ABAB 44

BBBB 55

BABA 66

ABAABA 77

11 22 22 44 77 33

Pogled u rječnikPogled u rječnik

Povratni indeksPovratni indeks

Nova riječNova riječ

ABAABA 88

Page 14: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

U slučaju da se rječnik popuni, kod sažimanja i ekspanzije, vrši se primjereno „čišćenje” pri čemu su najpopularnije sljedeće varijante:

1) Sadržaj rječnika u potpunosti se briše od svih riječi, osim predefiniranih kodova za pojedinačne znakove

2) Najmanje korištena riječ briše se iz rječnika dok se na njeno mjesto postavlja nova, ovisno o sadržaju pomoćne tablice evidencije korištenja pojedinih kodnih riječi

3) Najstarija riječ briše se iz rječnika dok se na njeno mjesto postavlja nova (engl. krat. LIFO – „Last-In-First-Out”)

S ovim se algoritmom sažimanja postižu najbolji rezultati u slučaju velikog broja ponavljanja pojedinih nizova u ulaznom nizu znakova, a to je vrlo često slučaj kod tekstualnih datoteka i monokromatskih slika. Datoteke nad kojima se vrši sažimanje,

11

Slika 6: Primjer ekspanzije podataka sažetih LZW algoritmom

UlazUlaz

ABBABABACABBABABACIzlazIzlaz

11 22 22 44 77 33

Pogled u rječnikPogled u rječnik

Povratna riječPovratna riječ

Nova riječNova riječ

Korak 1Korak 1

AA

11 22 22 44 77 33 AA 11

BB 22

CC 33

Korak 2Korak 2

BB

11 22 22 44 77 33 AA 11

BB 22

CC 33

ABAB 44

Korak 3Korak 3

BB

11 22 22 44 77 33 AA 11

BB 22

CC 33

ABAB 44

BBBB 55

Korak 6Korak 6

CC

11 22 22 44 77 33 AA 11

BB 22

CC 33

ABACABAC 88

ABAB 44

BBBB 55

BABA 66

ABAABA 77

Korak 4Korak 4

ABAB

11 22 22 44 77 33 AA 11

BB 22

CC 33

ABAB 44

BBBB 55

BABA 66

Korak 5Korak 5

ABAABA

11 22 22 44 77 33 AA 11

BB 22

CC 33

AABB 44

BBBB 55

BABA 66

ABAABA 77

Posebni slučajPosebni slučaj

Page 15: Algoritmi za sažimanje podataka bez gubitka informacije

2.Algoritmi

a u sadržaju ne sadrže ponavljajuće nizove, mogu kao posljedicu imati rast krajnje veličine.

Veliki nedostatak LZW algoritma leži u činjenici da je donedavno bio zaštićen s nekoliko patenata [8]. Tvrtka vlasnik „Unisys” polagala je sva prava na njegovo korištenje do prije par godina te je s tim u skladu zahtijevala licencnu naplatu od strane drugih programerskih tvrtki koje su ga koristile u svojim proizvodima. Krajnji se korisnici nisu morali pretjerano zabrinjavati, no na kraju su svejedno sudjelovali u naplati prava kroz završnu cijenu kupljenog proizvoda. Bitno je napomenuti da se naplaćivala samo primjena postupka sažimanja LZW algoritma, no ne i ekspanzije.

U doba predstavljanja, pružao je najbolji koeficijent sažimanja između svih dotad poznatih metoda te je postao prvi široko upotrebljavani univerzalni računarni algoritam za sažimanje podataka. Samo za primjer, velika tekstualna datoteka na engleskom jeziku može se sažeti na veličinu otprilike pola originalne vrijednosti.

Ovaj se algoritam koristi u brojnim poznatim datotečnim formatima i to između ostalih: TIFF, GIF, PDF i ZIP. Prilikom donošenja odredbe naplate licencnih prava najveći je problem nastao oko datotečnog formata GIF, i to zato što se u to doba, kada je internet još bio u fazi nastajanja, on najviše koristio za spremanje slika. No, kako bi se riješio novonastali problem, vrlo su brzo osmišljeni „zamjenski” formati: PNG i JPEG. Uz to što su daleko nadmašili mogućnosti prethodnika, ponuđeni su besplatno na korištenje bez ikakvih ograničenja.

12

Page 16: Algoritmi za sažimanje podataka bez gubitka informacije

3.Praktični uradak

3. Praktični uradak

Za potrebe praktičnog dijela ovog uratka u programskom jeziku Python implementirana su te izvršena testiranja teoretski obrađenih algoritama za sažimanje: RLE (2.1.), Shannon-Fano (2.2.), Huffman (2.3.) i LZW (2.4.). Programski jezik Python prije svega je izabran zbog svoje jednostavnosti, fleksibilnosti i preglednosti napisanog koda. Svaki je algoritam implementiran kao zasebni istoimeni modul (Dodatak A) u kojem se mogu naći pripadne metode za sažimanje i ekspanziju compress() i decompress() te glavna metoda main() namijenjena za potrebe pokretanja i prikazivanja rezultata testiranja. Kao konačan rezultat testiranja uzeti su koeficijenti sažimanja te pripadna vremena izvođenja ovisno o datoteci i primijenjenom algoritmu.

Algoritami su testirani nad sadržajem dviju de-facto standardnih zbirki datoteka namijenjenih upravo za ovakve vrste testiranja: Calgary Corpus [9] i Canterbury Corpus [10].

Znanstvenici Ian Witten, Timothy Bell i John Cleary sa Svečilišta Calgary u Kanadi 1987. godine su za potrebe ovakve vrste testiranja prikupili datoteke različitih formata i praktične namjene. Kao rezultat svega toga nastaje Calgary Corpus (bib, book1, book2, geo, news, obj1, obj2, paper1, paper2, paper3, paper4, paper5, paper6, pic, progc, progl, progp, trans) koji se intenzivno koristi tijekom 90-ih godina prošlog stoljeća.

Deset godina poslije (1997.) znanstvenici Ross Arnold i Timothy Bell sa Sveučilišta Canterbury s Novog Zelanda stvaraju napredniju inačicu primjereno nazvanu Canterbury Corpus (alice29.txt, asyoulik.txt, cp.html, fields.c, grammar.lsp, kennedy.xls, lcet10.txt, plrabn12.txt, ptt5, sum, xargs.1). Kod prikupljanja materijala za oba korpusa glavna zadaća bila je prikupljanje što raznovrsnijih datoteka s posebnim karakterističnim svojstvima ponavljanja (redundancije) kako bi se omogućilo što temeljitije testiranje algoritama za sažimanje.

Za potrebe testiranja RLE algoritma implementirana je prethodno opisana varijanta (slika 2) u kojoj se za signaliziranje početka kodirane riječi koristi dvostruka vrijednost procesiranog znaka. Ova varijanta odabrana je zbog jednostavnosti implementacije, boljih rezultata sažimanja naspram osnovne varijante te česte primjene u stvarnim situacijama.

Algoritmi Shannon-Fano i Huffman implementirani su po standardnim naputcima, no bez uključene tablice vjerojatnosti u izlaznim podatcima. Pošto sam postupak spremanja tablice nije zadan algoritmom te ovisi od implementacije do implementacije izostavljen je iz testiranog programskog koda. U realnim situacijama mogli bi se očekivati rezultati veći za tristotinjak bajtova (sadržaj tablice se najčešće skalira na jedan bajt po znaku), no to ne bi bitno utjecalo na dobiveni rezultat.

Kod implementacije LZW algoritma bitno je napomenuti dvije stvari. Kao prvo, problem popunjenosti rječnika riješen je na način da se njegov sadržaj u potpunosti briše u slučaju da više nije moguće u nj dodati novu riječ. Kao drugo, za veličinu

13

Page 17: Algoritmi za sažimanje podataka bez gubitka informacije

3.Praktični uradak

kodne riječi uzeta je fiksna brojka 12 kao što je i navedeno u originalnom opisu algoritma [11] te zbog česte primjene u stvarnim situacijama.

Samo testiranje provedeno je pokretanjem implementacije istoimenih algoritama za sažimanje nad datotekama oba korpusa. Za svaku datoteku kao rezultat uzet je dobiveni koeficijent sažimanja te vrijeme izvođenja ovisno o korištenom algoritmu.

Unatoč primjetno boljim rezultatima, čak i u slučaju slikovne datoteke pic (Calgary Corpus), korištenjem algoritma RLE dobivamo najlošiji koeficijent sažimanja. U većini slučajeva njegov se koeficijent sažimanja kreće oko 1, osim u slučaju par datoteka s vrlo velikim brojem uzastopnih ponavljanja znakova (pic i ptt5). Što se tiče vremena izvođenja, imajući na umu kompleksnost samog algoritma s obzirom na ostale, ovaj je algoritam uvjerljivo bio najbrži u svim slučajevima.

Uspoređujući rezultate algoritama Shannon-Fano i Huffman, ako uzmemo u obzir da je potonji nastao kao poboljšana verzija prethodnog, vidljivo je da u prosjeku njihovi rezultati prevladavaju u korist Huffman algoritma. Razlika nije prevelika, no dovoljna za jasan odabir u slučaju da se moramo odlučiti između ova dva algoritma. Također, u prosjeku im se vremena izvođenja previše ne razlikuju i to prvenstveno stoga što im je proces kodiranja, odnosno, preslikavanja iz kodnog stabla u izlazni binarni niz identičan.

Kao posljednji, algoritam s (u prosjeku) najboljim dobivenim rezultatima sažimanja uvjerljivo je LZW. Ako uzmemo u obzir da se prilikom testiranja kod algoritama Shannon-Fano i Huffmana u dobivene izlazne datoteke, nisu spremale tablice vjerojatnosti ta razlika u kvaliteti postaje još očiglednija. Također, što se tiče vremena izvođenja naspram navedenih algoritama, nije bilo pretjeranih odstupanja.

Dijagrami dobivenih rezultata mogu se pronaći u Dodatku B i to za koeficijente sažimanja na slikama 7 i 8 te za vrijeme izvođenja na slikama 9 i 10. Rezultati su prikazani sumirano po stupcima pri čemu svaki stupac predstavlja pripadnu vrijednost za jedan algoritam.

U oba slučaja stupac s manjom visinom predstavlja algoritam s boljim svojstvima, ovisno o promatranoj veličini. Usporedbom dobivamo rezultate identične onima dobivenim prethodnim iščitavanjem tabličnih rezultata.

14

Tablica 4: Vrijeme izvođenja algoritama (u sekundama) za datoteke Canterbury Corpusa

DatotekaDatoteka alice29.txt alice29.txt asyoulik.txt asyoulik.txt cp.html cp.html fields.c fields.c grammar.lsp grammar.lsp kennedy.xls kennedy.xls lcet10.txt lcet10.txt plrabn12.txt plrabn12.txt ptt5 ptt5 sum sum xargs .1 xargs .1

RLERLE 0,219 0,181 0,052 0,023 0,017 1,335 0,577 0,614 0,231 0,074 0,017Shannon-FanoShannon-Fano 1,166 1,023 0,245 0,099 0,032 6,755 3,335 3,771 1,975 0,334 0,037HuffmanHuffman 1,106 0,982 0,208 0,099 0,033 6,487 3,126 3,474 1,986 0,337 0,038LZWLZW 1,344 1,233 0,249 0,090 0,035 5,051 3,919 4,463 1,377 0,398 0,045

Tablica 1: Koeficijenti sažimanja za datoteke Calgary Corpusa

bib bib book1 book1 book2 book2 news news obj1 obj1 obj2 obj2 paper1 paper1 paper2 paper2 paper3 paper3 paper4 paper4 paper5 paper5 paper6 paper6 pic pic prog1 prog1 trans trans

RLERLE 1.020 1.021 1.020 0.999 0.998 0.901 1.006 1.015 1.018 1.017 1.020 1.023 1.021 0.212 1.012 0.966 0.934 0.9870.691 0.603 0.634 0.724 0.674 0.762 0.807 0.659 0.611 0.624 0.620 0.647 0.652 0.211 0.672 0.633 0.651 0.729

HuffmanHuffman 0.654 0.570 0.603 0.709 0.653 0.746 0.786 0.627 0.579 0.586 0.592 0.622 0.630 0.208 0.654 0.600 0.612 0.696LZWLZW 0.578 0.581 0.567 0.826 0.654 0.685 0.581 0.584 0.553 0.583 0.586 0.620 0.569 0.137 0.569 0.455 0.464 0.534

DatotekaDatoteka geogeo progcprogc progpprogp

Shannon-FanoShannon-Fano

Tablica 2: Koeficijenti sažimanja za datoteke Canterbury Corpusa

DatotekaDatoteka alice29.txt alice29.txt asyoulik.txt asyoulik.txt cp.html cp.html fields.c fields.c grammar.lsp gramm ar.lsp kennedy.xls kennedy.xls lcet10.txt lcet10.txt plrabn12.txt plrabn12.txt ptt5 ptt5 sum sum xargs .1 xargs .1

RLERLE 1,020 1,024 1,040 1,016 1,018 1,153 0,991 1,017 0,212 0,935 1,019Shannon-FanoShannon-Fano 0,595 0,629 0,694 0,654 0,616 0,482 0,616 0,592 0,211 0,691 0,644HuffmanHuffman 0,569 0,606 0,658 0,630 0,583 0,449 0,582 0,565 0,208 0,671 0,616LZWLZW 0,544 0,574 0,560 0,477 0,568 0,279 0,549 0,571 0,137 0,560 0,636

Tablica 3: Vrijeme izvođenja algoritama (u sekundama) za datoteke Calgary Corpusa

bib bib book1 book1 book2 book2 news news obj1 obj1 obj2 obj2 paper1 paper1 paper2 paper2 paper3 paper3 paper4 paper4 paper5 paper5 paper6 paper6 pic pic prog1 prog1 trans trans

RLERLE 0.159 0.949 0.740 0.128 0.455 0.057 0.365 0.101 0.114 0.086 0.024 0.028 0.068 0.249 0.050 0.106 0.068 0.1400.971 6.294 4.935 0.987 3.276 0.209 2.434 0.447 0.667 0.379 0.110 0.111 0.348 1.981 0.341 0.597 0.410 0.854

HuffmanHuffman 0.921 5.758 4.711 0.980 3.213 0.211 2.369 0.484 0.622 0.359 0.111 0.102 0.319 1.940 0.344 0.550 0.408 0.830LZWLZW 1.069 7.350 5.704 1.368 4.078 0.239 2.362 0.515 0.753 0.471 0.130 0.170 0.370 1.380 0.372 0.549 0.409 0.826

DatotekaDatoteka geogeo progcprogc progpprogp

Shannon-FanoShannon-Fano

Page 18: Algoritmi za sažimanje podataka bez gubitka informacije

4.Zaključak

4. Zaključak

U ovom uratku dat je kratak uvod u osnovne algoritme za sažimanje bez gubitka informacije. Na kraju je prezentirana programska implementacija istih te rezultati dobiveni njihovim pokretanjem.

Algoritam s najbržim vremenom izvođenja, ali ujedno i s najslabijim rezultatima sažimanja, bio je RLE. U drugu ruku, algoritam s uvjerljivo najboljim rezultatima sažimanja te konkurentnim vremenom izvođenja s obzirom na ostala dva algoritma (Shannon-Fano i Huffman) bio je LZW.

Premda se obrađeni algoritmi u današnje vrijeme koriste vrlo često, za ozbiljnije rezultate postoje algoritmi s naprednijim internim mehanizmima (LZMA) i predikcijskim modelima (PPM) te efikasnijim načinom spremanja sažetog oblika (aritmetičko kodiranje), no oni izlaze izvan okvira ovog uratka.

15

Page 19: Algoritmi za sažimanje podataka bez gubitka informacije

5.Literatura

5. Literatura

[1] Wikipedia: „Data compression”, http://en.wikipedia.org/wiki/Data_compression, 2010.

[2] David A. Huffman: „A Method for the Construction of Minimum-Redundancy Codes”, http://web.mit.edu/lrv/OldFiles/www/MAS/Huffman1952.pdf, 1952.

[3] PKWARE: „.ZIP File Format Specification”, http://www.pkware.com/documents/casestudies/APPNOTE.TXT, 2007.

[4] Robert Edward Lewand: „Relative Frequencies of Letters in General English Plain text”, http://pages.central.edu/emp/lintont/classes/spring01/cryptography/letterfreq.html, 2000.

[5] Debra A. Lelewer and Daniel S. Hirschberg: „Data Compression - Adaptive Huffman Coding”, http://www.ics.uci.edu/~dan/pubs/DC-Sec4.html, 1987.

[6] Jacob Ziv, Abraham Lempel: „A Universal Algorithm for Sequential Data Compression”, IEEE, May 1977.

[7] Jacob Ziv, Abraham Lempel: „Compression of Individual Sequences Via Variable-Rate Coding”, IEEE, September 1978.

[8] Michael C. Battilana: „The GIF Controversy: A Software Developer's Perspective”, http://lzw.info/, 2004.

[9] University of Calgary: „The Calgary Corpus”, http://www.data-compression.info/Corpora/CalgaryCorpus/index.htm, 1990.

[10] University of Canterbury: „The Canterbury Corpus”, http://corpus.canterbury.ac.nz/descriptions/, 1997.

[11] Welch, T.A., „A Technique for High-Performance Data Compression”, IEEE, June 1984.

[12] Khalid Sayood: „Introduction to Data Compression”, Elsevier Science & Technology Books, 2000.

[13] David Salomon: „Data Compression: The Complete Reference”, Springer, 2007.

[14] Debra A. Lelewer, Daniel S. Hirschberg: „Data compression”, ACM Computing Surveys, Volume 19, Issue 3, 1987.

[15] David Salomon: „A guide to data compression methods”, Springer, 2002.

[16] Andy McFadden: „Hacking Data Compression”, http://www.fadden.com/techmisc/hdc/index.htm, 1992.

[17] Roger Seeck: „BinaryEssence”, http://www.binaryessence.com/index.htm, 2010.

[18] Arturo San Emeterio Campos: „Run Length Encoding”, http://www.arturocampos.com/ac_rle.html, 1999.

16

Page 20: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

Dodatak A: Programski kod

A.1. RLE.pyimport sys, os

def compress(content): retVal, count, previous = str(), -1, content[0] for i in xrange(1, len(content)): if content[i] == previous and count < 255: count+=1 else: if count >= 0: retVal+='%s%s%s' % (previous, previous, chr(count)) else: retVal+='%s' % (previous) count, previous = -1, content[i] if count >= 0: retVal+='%s%s%s' % (previous, previous, chr(count)) else: retVal+='%s' % (previous) return retVal

def decompress(content): retVal, i = str(), 1 while i < len(content): if content[i-1] == content[i]: count, char = ord(content[i+1]), content[i] retVal += char * (2 + count) i += 3 else: retVal += content[i-1] i += 1 if i == len(content) and content[-2] != content[-1]: retVal += content[-1] return retVal

def main(): if len(sys.argv) < 2: print "Usage: python %s <file>" % __file__ else: file = open(sys.argv[1], "rb") content = file.read() compressed = compress(content)

17

Page 21: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

print "File: '%s'" % os.path.basename(sys.argv[1]) print "Compression ratio: %.3f" % (1.0*len(compressed)/len(content)) file.close()

if __name__ == "__main__": main()

A.2. Shannon-Fano.pyimport sys, os

from bitarray import bitarrayfrom utils import Node

def __treeMaker(table, codes): if len(table) == 1: return leftSum, rightSum, leftPart, rightPart = 0, 0, list(), list() for i in xrange(len(table)): (count, char) = table[i][0], table[i][1] if rightSum >= leftSum: leftSum += count leftPart.append((count, char)) codes[char].append(False) else: rightSum += count rightPart.append((count, char)) codes[char].append(True) __treeMaker(leftPart, codes) __treeMaker(rightPart, codes) def compress(content): retVal, freq, table, codes = str(), dict(), list(), dict() for i in xrange(len(content)): if not freq.has_key(content[i]): freq[content[i]] = 0 freq[content[i]] += 1 for char, count in freq.items(): table.append((count, char)) codes[char] = bitarray() table.sort(reverse=True) __treeMaker(table, codes)

18

Page 22: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

count, current = 0, 0 for i in xrange(len(content)): code = codes[content[i]] for j in xrange(len(code)): current |= code[j] << (7 - count) count += 1 if count == 8: retVal += chr(current) count, current = 0, 0 retVal += chr(current) return retVal, codes def decompress(content, codes, length): retVal, headNode = str(), Node(value=None, parent=None, left=None,\ right=None) for char, code in codes.items(): currentNode = headNode for i in xrange(0, len(code)): if not code[i]: if currentNode.left is None: currentNode.left = Node(value=None, parent=currentNode,\ left=None, right=None) currentNode = currentNode.left else: if currentNode.right is None: currentNode.right = Node(value=None, parent=currentNode,\ left=None, right=None) currentNode = currentNode.right if i == len(code) - 1: currentNode.value=char currentNode = headNode for i in xrange(len(content)): for j in xrange(8): currentNode = currentNode.right if (ord(content[i]) >> (7-j)) & \ 1 else currentNode.left if currentNode.value: retVal += currentNode.value currentNode = headNode if len(retVal) == length: return retVal return retVal

19

Page 23: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

def main(): if len(sys.argv) < 2: print "Usage: python %s <file>" % __file__ else: file = open(sys.argv[1], "rb") content = file.read() compressed, _ = compress(content) print "File: '%s'" % os.path.basename(sys.argv[1]) print "Compression ratio: %.3f" % (1.0*len(compressed)/len(content)) file.close()

if __name__ == "__main__": main()

A.3. Huffman.pyimport sys, os

from bitarray import bitarrayfrom utils import Node

def __treeMaker(table, codes): if len(table) == 1: return sum, lst = 0, list() for i in (-2, -1): (count, chars) = table[i] sum += count for char in chars: codes[char].insert(0, i==-1) lst.append(char) table.pop() table[-1] = (sum, lst) table.sort(reverse=True) __treeMaker(table, codes) def compress(content): retVal, freq, table, codes = str(), dict(), list(), dict() for i in xrange(len(content)): if not freq.has_key(content[i]): freq[content[i]] = 0 freq[content[i]] += 1 for char, count in freq.items():

20

Page 24: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

table.append((count, [char])) codes[char] = bitarray() table.sort(reverse=True) __treeMaker(table, codes) count, current = 0, 0 for i in xrange(len(content)): code = codes[content[i]] for j in xrange(len(code)): current |= code[j] << (7 - count) count += 1 if count == 8: retVal += chr(current) count, current = 0, 0 retVal += chr(current) return retVal, codes

def decompress(content, codes, length): retVal, headNode = str(), Node(value=None, parent=None, left=None,\ right=None) for char, code in codes.items(): currentNode = headNode for i in xrange(0, len(code)): if not code[i]: if currentNode.left is None: currentNode.left = Node(value=None, parent=currentNode,\ left=None, right=None) currentNode = currentNode.left else: if currentNode.right is None: currentNode.right = Node(value=None, parent=currentNode,\ left=None, right=None) currentNode = currentNode.right if i == len(code) - 1: currentNode.value=char currentNode = headNode for i in xrange(len(content)): for j in xrange(8): currentNode = currentNode.right if (ord(content[i]) >> (7-j)) & 1 else currentNode.left if currentNode.value: retVal += currentNode.value currentNode = headNode

21

Page 25: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

if len(retVal) == length: return retVal return retVal

def main(): if len(sys.argv) < 2: print "Usage: python %s <file>" % __file__ else: file = open(sys.argv[1], "rb") content = file.read() compressed, _ = compress(content) print "File: '%s'" % os.path.basename(sys.argv[1]) print "Compression ratio: %.3f" % (1.0*len(compressed)/len(content)) file.close()

if __name__ == "__main__": main()

A.4. LZW.pyimport sys, os

from bitarray import bitarrayfrom utils import int2bin

def compress(content, codeLength): retVal = bitarray() maxCapacity = 2**codeLength codes = dict([(chr(i), i) for i in xrange(256)]) word = str() for char in content: newWord = word + char if newWord in codes: word = newWord else: retVal += bitarray(int2bin(codes[word], codeLength)) word = char if len(codes) < maxCapacity: codes[newWord] = len(codes) else: codes = dict([(chr(i), i) for i in xrange(256)]) retVal += bitarray(int2bin(codes[word], codeLength)) return retVal.tostring()

22

Page 26: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

def decompress(content, originalLength, codeLength): retVal = str() maxCapacity = 2**codeLength codes = dict([(i, chr(i)) for i in xrange(256)]) bitCounter = 0 code = 0 word = str() entry = None while len(retVal) < originalLength: code = (code << 1) | ((ord(content[bitCounter >> 3]) >> (7 - \ (bitCounter & 7))) & 1) bitCounter += 1 if not bitCounter % codeLength: if code not in codes: entry = word + entry[0] else: entry = codes[code] retVal += entry if len(word) > 0: if len(codes) < maxCapacity: codes[len(codes)] = word + entry[0] else: codes = dict([(i, chr(i)) for i in xrange(256)]) word = entry code = 0 return retVal

def main(): if len(sys.argv) < 2: print "Usage: python %s <file>" % __file__ else: file = open(sys.argv[1], "rb") content = file.read() codeLength = 12 compressed = compress(content, codeLength) print "File: '%s'" % os.path.basename(sys.argv[1]) print "Compression ratio: %.3f" % (1.0*len(compressed)/len(content)) file.close()

if __name__ == "__main__": main()

23

Page 27: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak A:Programski kod

A.5. Utils.pyclass Node: def __init__(self, value, parent, left, right): self.value = value self.parent = parent self.left = left self.right = right def int2bin(n, bits): return "".join([str((n >> y) & 1) for y in range(bits-1, -1, -1)])

24

Page 28: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak B:Dijagrami rezultata

Dodatak B: Dijagrami rezultata

B.1. Koeficijenti sažimanja

25

Slika 8: Grafički prikaz koeficijenata dobivenih za datoteke Canterbury Corpusa

Original RLE Shannon-Fano Huffman LZW

0.000

2.000

4.000

6.000

8.000

10.000

12.000

Canterbury Corpus

xargs .1 sum ptt5 plrabn12.txt lcet10.txt kennedy.xls grammar.lsp fields.c cp.html asyoulik.txt alice29.txt

Algoritam

Ko

efic

ijen

t sa

ž im

an

ja

Slika 7: Grafički prikaz koeficijenata dobivenih za datoteke Calgary Corpusa

Original RLE Shannon-Fano Huffman LZW

0.000

2.000

4.000

6.000

8.000

10.000

12.000

14.000

16.000

18.000

20.000

Calgary Corpus trans progp prog1 progc pic paper6 paper5 paper4 paper3 paper2 paper1 obj2 obj1 news geo book2 book1 bib

Algoritam

Ko

efic

ijen

t sa

ž im

an

ja

Page 29: Algoritmi za sažimanje podataka bez gubitka informacije

Dodatak B:Dijagrami rezultata

B.2. Vremena izvođenja

26

Slika 9: Grafički prikaz vremena izvođenja za datoteke Calgary Corpusa

RLE Shannon-Fano Huffman LZW

0.000

5.000

10.000

15.000

20.000

25.000

30.000

Calgary Corpus trans progp prog1 progc pic paper6 paper5 paper4 paper3 paper2 paper1 obj2 obj1 news geo book2 book1 bib

Algoritam

Vri

jem

e iz

vođ

en

ja (

seku

nd

e)

Slika 10: Grafički prikaz vremena izvođenja za datoteke Canterbury Corpusa

RLE Shannon-Fano Huffman LZW

0.000

2.000

4.000

6.000

8.000

10.000

12.000

14.000

16.000

18.000

20.000

Canterbury Corpus

xargs .1 sum ptt5 plrabn12.txt lcet10.txt kennedy.xls grammar.lsp fields.c cp.html asyoulik.txt alice29.txt

Algoritam

Vri

jem

e iz

vođ

en

ja (

seku

nd

e)