15
Marko Modrušan 0036399696 Tekst je namjenjen svima koji žele naučiti nešto više o Lempel-Ziv metodama LZ77, LZ78 i LZW metode Metode pomoću rječnika Sliding window metoda… SEMINARSKI RAD - PVPRM 7. veljača 2009

Lempel - Ziv Vizualizacija

Embed Size (px)

DESCRIPTION

kodocanje

Citation preview

Page 1: Lempel - Ziv Vizualizacija

Marko Modrušan 0036399696

Tekst je namjenjen svima koji žele naučiti

nešto više o Lempel-Ziv metodama

LZ77, LZ78 i LZW metode

Metode pomoću rječnika

Sliding window metoda…

SEMINARSKI RAD - PVPRM

7. veljača 2009

Page 2: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

2

Sažetak

Od pojave prvih računala susrećemo se sa problemom komprimiranja

podataka koji nas prati do danas. Do kraja 70-tih godina prošlog stoljeća istraživanja na polju kompresije podataka bila su usmjerena uglavnom na poboljšavanje Huffman algoritma kodiranja podataka. Kako se taj algoritam temelji na određivanju frekvencije ponavljanja određenih simbola bilo je potrebno te simbole predvidjeti ili unaprijed pročitati podatke. Dva Izraelska teoretičara informacije Abraham Lempel i Jacob Ziv 1977. godine predstavljaju radikalno drukčiji pristup komprimiranju podataka. Kompresiju kod koje nije potrebno predviđati frekvenciju ponavljanja simbola i bespotrebno unaprijed čitati podatke. Lempel – Ziv vizualizacija predstavlja jedinstven način kompresije podataka. U predstojećem tekstu, biti će objašnjena osnovna ideja komprimiranja podataka pomoću Lempel - Ziv kodiranja.

Sadržaj

1. UVOD............................................................................................................ 3

2. OPIS I VRSTE KODIRANJA ............................................................................... 4

3. LZ77 ............................................................................................................. 5

3.1. Primjer LZ77 kodiranja ............................................................................. 7

4. LZ78 ............................................................................................................10

4.1. Primjer LZ78 kodiranja ............................................................................11

4.2. LZW ......................................................................................................12

5. ZAKLJUČAK...................................................................................................14

6. LITERATURA..................................................................................................15

Ovaj seminarski rad je izrađen u okviru predmeta „Sustavi za praćenje i vođenje procesa“ na Zavodu za elektroničke sustave i obradbu informacija, Fakulteta elektrotehnike i računarstva, Sveučilišta u Zagrebu. Sadržaj ovog rada može se slobodno koristiti, umnožavati i distribuirati djelomično ili u cijelosti, uz uvjet da je uvijek naveden izvor dokumenta i autor, te da se time ne ostvaruje materijalna korist, a rezultirajuće djelo daje na korištenje pod istim ili sličnim ovakvim uvjetima.

Page 3: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

3

1. Uvod

Problem ograničene memorije koji nas prati od pojave prvih računala pa sve do danas je još uvijek jedna od činjenica koje korisnik računala treba uvijek imati na umu. Sa vremenom količina memorije u računalima se povećava, ali ostaje činjenica da je ona uvijek ograničena. Korisnici računala i programeri moraju omogućiti da sa tim ograničenim resursima računala obrađuju velike količine podataka. Sasvim prirodno je da su se počele javljati razne ideje kako što učinkovitije smjestiti podatke u memoriju i jedna od njih je kompresija podataka. Kompresiju podataka možemo podijeliti u dvije kategorije. Prva kategorija je ona gdje dolazi do gubitka izvornih informacija, ali je ušteda u memorijskom prostoru tolika da su ti gubici prihvatljivi. U engleskoj terminologiji to se naziva “lossy data compression”. Takvu kompresiju primjenjujemo kod podataka gdje možemo dozvoliti određeni gubitak informacija, kao zvuk, video i slike. Dio informacija mijenjamo za memorijsku uštedu koja nam je znatno važnija nego sami podaci. Naravno, postoje i podaci kod kojih gubitak informacija nije prihvatljiv i gdje nakon dekompresije moramo imati identične podatke početnima. U engleskoj terminologiji takva vrsta kompresije se naziva “lossless data compression”. Razvijanjem učinkovitih vrsta kompresije zadovoljavamo rastuće potrebe za memorijskim prostorom bez potrebe za razvijanjem novih tehnologija za izradu same memorije. Razvoj industrija kao što su filmska ili glazbena bio bi nezamisliv bez upotrebe neke vrste kompresije. Potreba za memorijskim kapacitetima uvijek će postojati, a kompresija podataka je tu potrebu učinila znatno manjom.

Page 4: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

4

2. Opis i vrste kodiranja

Osnovna ideja Lempel-Ziv kodiranja podataka je kreirati rječnik od podataka koji su obrađeni i zatim zamjeniti te podatke sa indeksima iz toga rječnika na vrlo inventivan i jedinstven način. Sama metoda kreiranja rječnika u Lempel-Ziv kodiranju je razlog što je ova vrsta kodiranja vrlo učinkovita. Rječnik se kreira u jednom prolazu kodera kroz podatke te se na taj način osim dobivanja komprimiranog dokumenta koji zauzima manje prostora i samo komprimiranje obavalja relativno brzo. Vidjet ćemo da rječnik nije uvijek potrebno niti prenositi niti sačuvati prilikom komprimiranja iz razloga što dekoder dekomprimira podatke na analogni način koderu. Svoju metodu Lempel i Ziv su predstavili 1977. i 1978. godine u dvije inačice koje su poznatije pod imenima LZ77 i LZ78. Iz tih metoda komprimiranja razvile su se razne podvarijante koje unosne neznatne promjene u sam algoritam i uglavnom opisuju tehničku stranu realizacije algoritma u praksi. Razvijene su slijedeće inačice kodiranja LZ77 i LZ88 algoritmom:

• LZ77 inačice: LZR, LZSS, LZB, LZH • LZ78 inačice: LZW, LZC, LZT, LZMW, LZJ, LZFG Sve te inačice zajedno zovu se familija Lempel – Ziv algoritama.

Slika 1: Familija Lempel - Ziv algoritama

Page 5: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

5

3. LZ77

LZ77 algoritam postiže kompresiju zamjenom niza podataka sa odgovarajućim simbolom koji u rječniku sadrži upravo te podatke. Kad govorimo o rječniku mi zapravo zamišljamo rječnik kao strukutru podataka koja se puni podacima prilikom kodiranja i nakon što se proces kodiranja završi taj rječnik sačuvamo da bi prilikom dekodiranja imali odakle povratiti izvorne podatke. Kod LZ77 algoritma nije takav slučaj.

Pogledajmo najprije kako načelno taj algoritam radi:

Slika 2

Recimo da se niz podataka na slici 1 sastoji od dva niza: niz

E='abcbbacde' i niz S='bbadeaa'. I recimo da je niz E već bio prethodno kodiran a niz S još uvijek nije.

LZ77 algoritam prvo traži najduži odgovarajući niz podataka iz niza S u nizu E. U ovom slučaju najduži niz podataka je 'bba' koji je na trećoj poziciji od početka niza (brojeći od nule). Dakle moguće je kodirati prva tri podatka u nizu S kao referencu na ta ista tri podatka u nizu E počevši od treće pozicije. Referenca je kodni znak koji u sebi sadrži tri elementa: poziciju od početka niza, duljinu kodiranog niza i prvi sljedeći podatak koji se nalazi nakon kodiranog niza. U našem slučaju referenca je '33d'. Time smo niz od četiri znaka zamijenili jednom referencom i zapravo komprimirali podatke. Kada odgovarajući nizovi postani veći tada kompresija dolazi sve više do izražaja.

Page 6: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

6

Što se događa ako je odgovarajući niz vrlo dug i referenca u sebi sadrži velike brojeve?

LZ77 algoritam zato koristi stukturu prikazivanja podataka koja se zove

klizni prozor. Klizni prozor služi tome da kod kodiranja podataka i odabiranja pogodnih podataka za kodiranje koder gleda samo podatke koji se nalaze unutar tog prozora. Klizni prozor se sastoji od dva dijela: spremnik za usporedbu (search buffer) gdje su se podaci već kodirali i spremnik s novim podacima (lookahead buffer) koji sadrži podatke koji se jos nisu kodirali.

Slika 3: Pomični prozor

Pogledajmo sada i pravi LZ77 algoritam:

while (lookAheadBuffer not empty) {

get a reference (position, length) to longest match;

if (length > 0) {

output (position, length, next symbol);

shift the window length+1 positions along;

} else {

output (0, 0, first symbol in the lookahead buffer);

shift the window 1 character along;

}

}

Iz koda vidimo ukoliko nema odgovarajućeg niza u spremniku za usporedbu algoritam jednostavno upiše u referencu 0 0 i pomakne se za jedan znak.

Prilikom započinjanja procesa kodiranja u spremnik s novim podacima postavimo početak željenog dokumenta koji želimo kodirati, a spremnik za usporedbu napunimo sa unaprijed definiranim znakovima, u našem primjeru koristili smo nule.

Page 7: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

7

3.1. Primjer LZ77 kodiranja

U sljedećem primjeru proći ćemo LZ77 algoritam korak po korak. Neka ulazni niz bude niz S = 001010210210212021021200... i neka su

oba spremnika veličine 9 znakova. Proces započinjemo tako da spremnik za usporedbu napunimo nulama

a u spremnik s novim podacima unesemo prvih 9 znakova niza S. Algoritam traži najduži odgovarajući niz. U ovom slučaju to je niz '00' i budući da spremnik za usporedbu ima same nule može se uzeti bilo koji podniz kao odgovarajući. U primjeru smo uzeli zadnji znak kao početak odgovarajućeg podniza.

Slika 4: Primjer kodiranja

Kao što smo već ranije spomenuli odgovarajući nizovi su kodirani kao

referenca koja u sebi sadrži poziciju niza, njegovu dužinu i prvi sljedeći znak koji se pojavljuje nakon niza. Prvi niz je kodiran kao C 1 = 22021. 22 je pozicija niza u spremniku za usporedbu u bazi tri (810 = 223), 02 predstavlja duljinu niza (210 = 23) a 1 je prvi sljedeći znak koji se pojavljuje nakon odgovarajućeg niza.

Nakon toga prozor se pomiče udesno za duljinu niza i jedan znak dakle u ovom slučaju pomiče se za 3 i proces pronalaska odgovarajućeg niza počinje ponovo. Algoritam je pronašao niz '010' kao najdulji odgovarajući i to na sedmom mjestu u spremniku za usporedbu te je taj niz kodiran kao C2 = 21102. Prozor se ponovno pomiče, ali ovaj put za 4 znaka udesno. Postupak ponavljamo i dobivamo C3 = 20212 i C4 = 02220. Time smo niz S = 001010210210212021021200... zamijenili nizom kodiranih riječi C1C2C3C4 i time obavili značajnu kompresiju.

Kod dekodiranja se lako uočava zašto ne trebamo prenositi ili sačuvati rječnik. Na početku dekodiranja kao i kod kodiranja prvo napunimo

Page 8: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

8

spremnik za usporedbu nulama i spremnik s novim podacima ostavimo prazan. Dekodiranje se obavalja jednostavno čitajući kodirane riječi i radeći točno ono što piše.

Pogledajmo sliku pa ćemo proći korake dekodiranja zajedno:

Slika 5: Dekodiranje

Nakon što smo napunili spremnik za usporedbu nulama čitamo prvu

kodnu riječ: C1 = 22021. Ona nam govori: pozicioniraj se na osmo mjesto (223 = 810) spremnika za pretraživanje pročitaj znak i upiši u prvo mjesto spremnika s novim podacima, zatim se pomakni u oba spremnika za jedno mjesto udesno i ponovo učini isto. Postupak nastavi činiti sve dok se broj tih postupaka ne izjednači sa brojem koji se nalazi na drugom mjestu kodne riječi. Nakon toga upiši znak koji se nalazi na trećem, ujedno i zadnjem mjestu kodne riječi. Nakon toga prozor se pomiče udesno za jedan broj veći od drugog broja u kodnoj riječi, odnosno pomak udesno za jedan broj veći od niza koji smo upravo dekodirali. Uzimamo sljedeću kodnu riječ i ponovimo postupak. Cijeli postupak se ponavlja sve dok ne dodemo do zadnje kodne riječi, nju na isti način dekodiramo i dekodirali smo cijeli dokument koji je identičan izvornome.

Uočimo da nije važno ukoliko se iz spremnika za usporedbu pomaknemo u spremnik s novim podacima prilikom pomicanja udesno za jedan znak i čitanja sljedećeg znaka.

Vratimo se na naš primjer i pokušajmo ga dekodirati: prvi dio kodne riječi C1 = 22021 nam govori da se pozicioniramo na osmo mjesto u spreminku za pretraživanje. Kopiramo znak sa osmog mjesta na prvo mjesto u spremniku s novim podacima, provjerimo jesmo li došli do kraja niza znakova koji trebamo kopirati. Nismo, tako da se pomjeramo za jedno mjesto udesno u oba spremnika. Primjećujemo da smo iz spremnika za usporedbu prešli u spremnik sa novim podacima, to je dopušteno tako da ponavljamo postupak. Kopiramo znak sa tog mjesta na sljedeće mjesto u spremniku sa novim podacima. Provjerimo jesmo li došli do kraja niza, jesmo, pomičemo se za jedno mjesto u spremniku sa novim podacima i

Page 9: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

9

upisujemo znak sa zadnjeg mjesta u kodnoj riječi i pomičemo prozor za 3 mjesta udesno tako da je spremnik sa novim podacima ponovo prazan. Uzimamo sljedeću kodnu riječ i ponavljamo postupak. Nakon što dekodiramo sve kodne riječi dekodirali smo cijeli dokument.

Page 10: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

10

4. LZ78

LZ78 je algoritam koji za kopmresiju koristi rječnik koji se na vrlo jednostavan način gradi kod kodiranja i kasnije kod dekodiranja također na vrlo jednostavan način ponovo se izgradi i vraća izvorne dijelove dokumenta. Prilikom kodiranja i spremanja odgovarajućih podataka u rječnik algoritam generira kodne riječi koje se sastoje od dva elementa: indeks koji upućuje na najduži odgovarajući podatak u rječniku i sljedeći znak koji se pojavljuje nakon tog podatka. U početku rječnik je prazan i puni se podacima koji se iščitavaju iz dokumenta. Teoretski veličina rječnika bi mogla biti beskonačna, međutim u praksi se ona ograničava i kada se dostigne maksimalna veličina rječnika on se više ne proširuje sa novim zapisima.

Pogledajmo sada pojednostavljenu pseudokod verziju LZ78 algoritma da bismo ju mogli prodiskutirati i pomoću nje pokušati riješiti primjer:

w := NIL;

while (there is input){

K := next symbol from input;

if (wK exists in the dictionary) {

w := wK;

} else {

output (index(w), K);

add wK to the dictionary;

w := NIL;

}

}

Algoritam uzima iz niza podatak, provjerava postoji li taj podatak u

rječniku. Ukoliko ne postoji kreira ga u rječniku i na izlaz generira kodnu riječ i provjerava dalje sljedeći podatak iz niza. Ukoliko postoji u rječniku sačuva odgovarajući podatak i provjerava sljedeći podatak. Ukoliko i sljedeći podatak postoji u rječniku algoritam dodaje u niz prethodnom i tako nastavlja sve dok ne dode do znaka koji se sa prethodnim nizom još ne nalazi u rječniku. Tada ponovo na izlaz generira kodnu riječ koja se sastoji od indeksa niza koji se već nalazi u rječniku i novog znaka i kreira tu kodnu riječ također i u rječniku.

Page 11: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

11

4.1. Primjer LZ78 kodiranja

Uzmimo znakovni niz S = 001212121021012101221011 kao niz za kodiranje. Promotrimo sliku i pogledajmo kako je LZ78 algoritam kodirao niz S.

Slika 6: LZ78 kodiranje

U prvom koraku prvi znak koji zasigurno još nije u rječniku se u isti

dodaje i pridodaje mu se kodna riječ (0 0). Prva nula ukazuje na to da u rječniku nema odgovarajućeg niza ili znaka, a druga nula je upravo taj znak koji smo pročitali i dodali u rječnik. Pomičemo se za jedno mjesto i učitavamo sljedeći znak, primjećujemo da taj znak već postoji u rječniku te učitavamo dalje sljedeći znak. Tog znaka nema u rječniku te se generira sljedeća kodna riječ (1 1). Prva jedinica ukazuje na to da postoji taj znak u rječniku i to na prvom mjestu (gdje se nalazi znak 0), a druga jedinica je sljedeći znak koji se pojavio a nije u rječniku. Time se niz '01' dodao u rječnik. Proces se ponavlja dok se ne dođe do kraja niza. Nakon završetka procesa kodiranja niz S = 001212121021012101221011 se zamjenjuje nizom kodnih riječi '001102013150617271' koji je kraći i zauzima manje prostora.

Proces dekodiranja obavlja se na vrlo lagan i intuitivan način: dekoder dekodira kodne riječi na način da iz njih ponovo izgradi rječnik koji će biti identičan onome kod kodiranja te iz njega pročita izvorne podatke. Tako će ako krenemo dekodirati naš primjer dekoder prvo uzeti kodnu riječ (0 0) i dekodirati ju na način analogan kodiranju: prvu nulu shvatit će kao znak da se taj znak još ne nalazi u rječniku pa će sljedeći znak u kodnoj riječi koji je također nula zapisati kao prvi znak u nizu i kao prvi dekodirani znak koji će postaviti u rječniku. Sljedeća kodna riječ je (1 1) i

Page 12: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

12

ona označava da kod prvog znaka kodne riječi da se dio ovog kodiranog niza nalazi u rječniku i to pod rednim brojem jedan, drugi znak označava zadnji znak ovog kodiranog niza koji je u ovom slučaju znak jedan. Dekodirani niz koji je u ovom slučaju '01' pridodaje se prethodno dekodiranom nizu i postavlja se u rječniku kao drugi dekodirani niz. Proces se nastavlja sve dok se ne dođe do kraja niza koji treba dekodirati. Kao rezultat dekodiranja dobili smo izvorni niz S=001212121021012101221011 što možemo provjeriti na slici sedam koja nam prikazuje rječnik koji se izgradio od kodnih riječi i konačan dekodirani niz.

Slika 7: Dekodiranje

LZ78 ima nekoliko slabosti, jedna od njih je ta da rječnik može

unedogled rasti. Postoje razne metode koje se koriste da se to spriječi, neka od rješenja su da rječnik nakon što se napuni do neke određene mjere postane statične veličine ili da se postojeći rječnik odbaci i počne se stvarati iznova. Kod procesa izgradnje rječnika duže podnizove koje želimo kodirati a koji nam uvelike pridonose većoj kompresiji najčešće kodiramo tek pri kraju izgradnje rječnika i time ne ostvarujemo kompresiju koju bismo inače mogli ostvariti. Ipak, u praksi LZ78 algoritam kodiranja radi vrlo dobro i dovodi do vrlo velike kompresije podataka pod uvjetom da su ulazni podaci dovoljno veliki i da imaju određeni stupanj ponavljanja.

4.2. LZW

1984. godine Terry Welch je modificirao LZ78 algoritam kodiranja kako bi ga implementirao u vrlo brze diskovne kontrolere, što je rezultiralo nastajanjem Lempel-Ziv-Welch algoritma (poznatijeg kao LZW algoritam).

Page 13: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

13

Ova poboljšana verzija LZ78 algoritma je najpoznatija inačica i vrlo je često pogrešno nazivana kao izvorni Lempel – Ziv algoritam. Razlika u odnosu na izvorni LZ78 algoritam je u tome što prije nego što se započne proces kodiranja dokumenta prvo se u rječnik unesu svi znakovi, i to na prvih 256 mjesta u rječniku (naravno taj unos svih znakova se radi automatski, nije ih potrebno ručno unositi) i nakon toga se kreće kodirati dokument. Sada više nije potrebno svaki novi znak zasebno kodirati u rječnik jer su svi znakovi već na samom početku uneseni nego se počinje sa nizom od dva znaka i proces kodiranja se nastavlja jednako kao što se to činilo kod LZ78 algoritma.

Algoritam za LZW metodu izgleda ovako:

w := NIL;

add all possible charcodes to the dictionary

while (there is input){

K := next symbol from input;

if (wK exists in the dictionary) {

w := wK;

} else {

output (index(w));

add wK to the dictionary;

w := K;

}

}

Kod je gotovo identičan LZ78 kodu osim što se u početku u rječnik unesu svi mogući znakovi.

Dekodiranje se vrši identično kao kod LZ78 dekodiranja osim što se naravno ponovno najprije u rječnik učitaju svi znakovi.

LZW algoritam kompresije koristi se među ostalima i kod GIF fromata koji je 1987 godine razvila tvrtka CompuServe za pohranu i slanje slikovnih datoteka. GIF format je bio slobodan medij za korištenje i s vremenom postajao sve popularniji i korišteniji koliko u tvrtkama koje bi ga koristile za oglašavanje toliko i među korisnicima koji su GIF format koristili u privatne svrhe. Do 1994 godine GIF format je zamijenio PCX kao format koji se najčešće koristio za pohranu osmobitnih grafičkih datoteka. Te je godine tvrtka Unisys kao vlasnik patenta LZW algoritma zatražila od tvrtke CompuServe da plaća licencu za korištenje što je izazvalo snažno negodovanje u javnosti, posebice ako uzmemo u obzir da je tih godina internet industrija doživila veliki boom u razvoju a GIF je bio vodeći medij za prijenos grafičkih datoteka slabije rezolucije na internetu. Patent je istekao u SAD-u u lipnju 2003. godine a do srpnja 2004. godine i drugdje u svijetu.

Page 14: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

14

5. Zaključak

Lempel i Ziv su razvili vrlo jednostavan algoritam, a vrijeme je pokazalo da je to jedan od najučinkovitijih načina komprimiranja podataka koji poznajemo. Njegova primjena je vrlo raširena i danas je gotovo nemoguće naći osobu koja nije barem jednom koristila kompresiju podataka temeljenu na Lempel-Ziv algoritmu. Cijeli niz algoritama i metoda temelji se na osnovnim principima koje je postavio Lempel-Ziv algoritam, a njegov razvoj ne prestaje i svakim danom se nadograđuje sa novim mogućnostima i modifikacijama. Snaga Lempel-Ziv algoritma nalazi se u njegovoj jednostavnosti i brzini izvođenja što su jedni od glavnih preduvijeta da neka tehnologija postane prihvaćena od strane korisnika. Na jednostavan način ovaj algoritam dokazuje u kojem pravcu treba razvijati nove tehnologije i kako je uz pomoć osnovnih matematičkih operacija moguće razvijati velike stvari.

Page 15: Lempel - Ziv Vizualizacija

Lempel - Ziv vizualizacija

15

6. Literatura

[1] Zeeh, Cristina: The Lempel Ziv Algorithm, 2003. URL: http://tuxtina.de/files/seminar/LempelZivReport.pdf

[2] Grubišić, Ivor; Juroš, Petar; Srbiš, Mario: Lempel – Ziv vizualizacija URL: http://diana.zesoi.fer.hr/pvprm/igrubisi/lempel-ziv_vizualizacija.htm

[3] Wikipedia URL: http://en.wikipedia.org/wiki/LZW

[4] Wikipedia URL: http://en.wikipedia.org/wiki/LZ77_and_LZ78

[5] Interactive Data Compression Tutor URL: http://www.eee.bham.ac.uk/WoolleySI/All7/ziv_1.htm

[6] Nelson, Mark LZW Data Compression 1989. URL: http://marknelson.us/1989/10/01/lzw-data-compression/

[7] Lempel – Ziv – Welch (LZW) Compression URL: http://netghost.narod.ru/gff/graphics/book/ch09_04.htm