Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
SVEUČILIŠTE U ZAGREBU
FAKULTET ELEKTROTEHNIKE I RAČUNARSTVA
ZAVRŠNI RAD br. 4006
IZRADA SAMOSTOJNOG LEMPEL –
ZIVOVOG INDEKSA S PRIMJENOM U
ANALIZI GENOMA
Zoran Krišto
Zagreb, lipanj 2015.
IZVORNIK ZAVRŠNOG ZADATKA
Zahvala
Zahvaljujem svojoj obitelji, bez čije požrtvovnosti moje školovanje ne bi bilo
moguće. Također, veliko hvala mentorici doc. dr. sc. Mirjani Domazet-Lošo na
ukazanoj podršci.
Sadržaj
1 Uvod ................................................................................................................ 4
2 Notacija i strukture podataka ........................................................................... 6
2.1 Notacija ..................................................................................................... 6
2.2 Burrows – Wheelerova transformacija ( BWT ) ......................................... 7
2.3 Sufiksno polje ............................................................................................ 8
2.4 Prefiksno stablo ......................................................................................... 9
3 Ideja i način funkcioniranja LZ – indeksa....................................................... 10
3.1 LZ – indeks ( pregled teorije ) .................................................................. 11
3.2 LZ77 sažimanje teksta ............................................................................ 14
3.3 LZ78 sažimanje teksta ............................................................................ 16
3.4 Algoritam pretraživanja podniza pomoću LZ78 ....................................... 18
3.4.1 Vrste pojavljivanja podniza unutar niza ............................................. 18
3.4.2 Pojavljivanje podniza unutar jedne fraze .......................................... 19
3.4.3 Pojavljivanje podniza unutar dvije fraze ............................................ 22
3.4.4 Pojavljivanje podniza unutar tri ili više fraza ..................................... 25
4 LZ – indeks ( implementacija ) ...................................................................... 26
4.1 Izgradnja strukture Z-prefiksno stablo ( engl. Z-Trie ).............................. 27
4.1.1 Prefiksno stablo u LZ – indeksu ........................................................ 28
4.1.2 Reverzno prefiksno stablo u LZ – indeksu ........................................ 29
4.1.3 Z – prefiksno stablo .......................................................................... 31
4.1.4 Izgradnja Z – prefiksnog stabla ......................................................... 32
4.2 Izgradnja struktura rČvor i tČvor ............................................................. 34
4.3 Funkcija pretraži ...................................................................................... 35
4.3.1 Pojavljivanja podniza unutar jednog bloka ........................................ 35
4.3.2 Pojavljivanja podniza unutar dva bloka ............................................. 37
4.3.3 Pojavljivanja podniza unutar tri ili više blokova ................................. 39
5 Veličina, vrijeme izgradnje i pretraživanja LZ – indeksa ................................ 41
6 Usporedba s originalnom implementacijom LZ – indeksa ............................. 43
6.1 Memorijsko zauzeće indeksa .................................................................. 43
6.2 Vrijeme izgradnje indeksa ....................................................................... 44
6.3 Vremena pretraživanja podniza ............................................................... 45
7 Zaključak ....................................................................................................... 46
8 Literatura ....................................................................................................... 47
4
1 Uvod
Bioinformatika je interdisciplinarna znanstvena grana u kojoj se koriste
znanja vezana uz biologiju, računarstvo, matematiku, statistiku, znanost o tekstu.
Njena zadaća jest analiza bioloških podataka, npr. analiza sadržaja i organizacije
genoma, brzo pretraživanje sadržaja genoma, predviđanje struktura i
funkcionalnosti makromolekula, itd..
Genom je ukupan genetski materijal nekog organizma. Metoda kojom se
utvrđuje točan redoslijed gradivnih tvari koje čine velike molekule
(makromolekule/polimeri) kao što su DNA i RNA naziva se sekvenciranje genoma.
Deoksiribonukleinska kiselina ili skraćeno DNA je posebno zanimljiv polimer. DNA
je dvostruka uzvojnica koja se sastoji od četiri vrste nukleotida: adenina (A), citozina
(C), gvanina (G) i timina (T). Nukleotidi na istoj poziciji unutar svakog od dva lanca
povezuju se vodikovim vezama između adenina i timina te između citozina i
gvanina. Lanci molekule DNA su komplementarni i iz jednog lanca može se
rekonstruirati drugi, a samim time i cijela molekula DNA. Molekula
deoksiribonukleinske kiseline smještena je unutar jezgre stanice, točnije unutar
kromosomȃ. Važnost DNA očituje se u činjenici da je ona osnovna molekula
nasljeđivanja i kao takva čini osnovu za egzistenciju vrsta svih živih bića.
Tijekom posljednja dva desetljeća došlo je do smanjenja cijene
sekvenciranja, što je doprinijelo je razvoju bioinformatike. Uz ovakav razvoj
događaja pojavili su se i problemi vezani uz pohranu i obradu velikih količina
podataka. Uzmimo za primjer ljudsku DNA, čiji se jedan lanac sastoji od otprilike 3
∙ 109 nukleotidnih baza, ako je svaki znak pohranjen kao jedan oktet ( engl. byte ),
onda na tvrdom disku i u radnoj memoriji računala ova molekula zauzima 3 GB.
Velik je problem obrada takvog lanca na osobnom računalu.
Upravo radi velike količine podataka s kojima se bioinformatika susreće
veliku su popularnost stekli samostojni indeksi. To su strukture podataka koje
zapravo zamjenjuju izvorni oblik teksta, tj. organiziraju ga na drugačiji način i
sažimaju ga, a u isto vrijeme, ukoliko dođe do potrebe, omogućuju njegovu
rekonstrukciju. Samostojni indeksi omogućuju učinkovito pretraživanje teksta.
5
Veličina pojedinih indeksa ovisi o načinu implementacije. Trenutno, postoje tri
skupine samostojnih indeksa: FM skupina indeksa (Ferragina and Manzini, 2000),
CSA skupina indeksa (Sadakane, 2000) i LZ skupina indeksa (Navarro, 2004).
Prvi samostojni indeks, trenutno najpopularniji, predstavili su Giovanni
Manzini i Paolo Ferragina (Ferragina and Manzini, 2000), a nazvali su ga, ne prema
početnim slovima svojih prezimena, nego prema engleskom izrazu „Full-text Minute-
space“ koji označava brzu izgradnju unutar malo memorijskog prostora.
Sljedeća skupina indeksa naziva se CSA ( engl. Compressed Suffix Array )
(Sadakane, 2000). To je sažeta struktura podataka koja se temelji na obradi
sufiksnog polja, posebne strukture podataka koja je objašnjena u nastavku.
Posljednji, ali ne i najmanje bitan je LZ – indeks. Implementirali su ga
Gonzalo Navarro i Diego Arroyuelo sa Sveučilišta u Čileu(Navarro and Arroyuelo,
2006). Ovaj indeks koristi LZ skupinu algoritama za sažimanje podataka: LZ77 (Ziv
and Lempel, 1977) i LZ78 (Ziv and Lempel, 1978) čiji su tvorci Abraham Lempel i
Jacob Ziv, a po kojima je ovaj samostojni indeks i dobio naziv.
U ovom radu će se govoriti o LZ - indeksu i njegovoj implementaciji u
programskim jezicima C/C++. Razlog odabira programskog jezika C/C++ je upravo
u njegovoj velikoj brzini te smanjenoj potrošnji memorije u odnosu na više jezike (
npr. C#, Java, Python i drugi ). Odluci o istraživanju LZ – indeksa dodatno je
doprinijela činjenica da nije toliko istražen kao i prethodna dva navedena indeksa.
6
2 Notacija i strukture podataka
Ovo poglavlje svojevrstan je uvod u strukture podataka koje se najčešće
koriste tijekom izgradnje samostojnih indeksa, kao i uvod u notaciju koja će se
koristiti unutar cijelog rada.
2.1 Notacija
Neka je zadan niz T duljine n nad abecedom Σ duljine σ. Na kraj zadanog
niza T uvijek dodat ćemo jedan znak $, koji se ne nalazi u abecedi Σ, a koji je
leksikografski veći od bilo kojeg znaka abecede Σ. Ovaj završni rad namijenjen je
izgradnji LZ – indeksa u svrhu pretraživanja genoma, stoga se abeceda sastoji od
četiri znaka: A, C, G, T i $1.
Znak na i-tom mjestu unutar niza T označit ćemo s 𝑇[𝑖], uz uvjet 0 ≤ 𝑖 < 𝑛,
iz razloga što se prvi znak niza T nalazi na indeksu 0, tj. 𝑇[0], a posljednji znak se
nalazi na indeksu 𝑛 − 1 točnije𝑇[𝑛 − 1] . Podniz koji počinje na i-tom mjestu, a
završava na j-tom mjestu unutar niza T označit ćemo s 𝑇[𝑖, 𝑗] = 𝑃[𝑖, 𝑗], uz uvjet 0 ≤
𝑖 < 𝑗 < 𝑛. Prefiksni dio podniza P označit ćemo s 𝑃[1, 𝑚], uz uvjet 1 ≤ 𝑖 ≤ 𝑚 < 𝑗.
Sufiksni dio podniza P označavat će se s 𝑃[𝑚, 𝑗], uz uvjet 𝑚 ≤ 𝑗 < 𝑛. Znakom N
označavat ćemo broj pojavljivanja podniza P s tekstom T.
Tekst T kojeg smo dobili sažimanjem označit ćemo znakom K. Sažeti tekst
C sastojat će se od u blokova ( 𝑇 = 𝐶[0, 𝑢] ), uz uvjet 𝑢 < 𝑛, jer samo tada vrijedi da
je tekst uspješno sažet. Pojedini blok sažetog teksta C označit ćemo s 𝐶[𝑘] = 𝐵𝑘,
uz uvjet 0 ≤ 𝑘 ≤ 𝑢.
1 Ostali znakovi koji se mogu pojaviti (npr. N, R, W …) zbog netočnosti metode sekvenciranja se zanemaruju.
7
2.2 Burrows – Wheelerova transformacija ( BWT )
Vrlo korisna podatkovna struktura koju su predstavili Burrows i Wheeler
(Burrows and Wheeler, 1994) Burrows – Wheelerova reverzibilna transformacija (
engl. Burrows – Wheeler Transform ) koristi se u algoritmima za sažimaju podatke.
Ona koristi rotacije zadanog niza (Slika 2.) i ukoliko se dogodi da zadani niz ima
više jednakih podnizova, veća je vjerojatnost da će oni biti zajedno grupirani.
Reverzibilnost BWT-a vrlo je korisno svojstvo jer se ne gube podaci početnog
niza i moguće je transformaciju vratiti u početno stanje.
Slika 2.2.1 Izračun Burrows – Wheelerove transformacije pomoću rotacije, nad
nizom 𝑻 = 𝑻𝑨𝑨𝑮𝑪𝑻𝑮𝑨$
8
2.3 Sufiksno polje
Dugi niz godina sufiksna stabla ( engl. suffix tree ) su se koristila kao struktura
podataka koja se koristi u radu sa nizovima ( engl. string ). Sufiksno polje ( engl.
suffix array ) predstavili su Manber i Myers (Manber and Myers, 1993). Ono se koristi
u raznim algoritmima pretraživanja podnizova, može poslužiti za brzu izgradnju
Burrows - Wheelerove transformacije. Algoritam za izgradnju sufiksnog polja u
linearnom vremenu predstavili su Kärkkäinen and Sanders (Kärkkäinen and
Sanders, 2003). Sufiksno polje je polje svih leksikografski sortiranih sufiksa nekog
teksta, a sastoji se od ne-negativnih cijelih brojeva koji predstavljaju početne pozicije
istih (Slika 2.).
Slika 2.3.1 Izračun sufiksnog polja pomoću sortiranja sufiksa, nad nizom 𝑻 = 𝑻𝑨𝑨𝑮𝑪𝑻𝑮𝑨$
9
2.4 Prefiksno stablo
Prefiksno stablo (Liang, 1983), često nazivano i digitalno stablo ( engl. Trie )
sortirana je podatkovna struktura u obliku stabla, čiji se dijelovi sastoje od znakovnih
nizova. Svi prethodnici listova sadrže zajedničke prefikse osim korijena, koji je
prazan niz. Na slici ( Slika 2.4.1 ) dan je primjer prefiksnog stabla izračunatog nad
riječima: „BAZA“, „BIOM“, „BIOLOG“, „GENI“, „GENETIKA“ i „GENOM“. Prefiksno
stablo može se koristiti, između ostalog, u algoritimima za samo - dovršavanje (
engl. autocomplete ) riječi i u algoritmima za samo - ispravljanje ( engl. autocorrect
) riječi.
Slika 2.4.1 Prefiksno stablo izračunato nad riječima „BAZA“, „BIOM“, „BIOLOG“, „GENI“, „GENETIKA“ i „GENOM“.
10
3 Ideja i način funkcioniranja LZ – indeksa
Danas sve veću popularnost imaju tzv. samostojni indeksi. To su strukture
koje sažimaju izvorni tekst u svrhu njegovog lakšeg pretraživanja. Naziv samostojni
dobili su po tome što u potpunosti zamjenjuju tekst nad kojim se žele raditi upiti,
točnije zbog činjenice što isti taj tekst koji mijenjaju mogu i vratiti u izvorni oblik,
ukoliko to korisnik poželi.
LZ – indeks ( engl. LZ – index ) je struktura podataka, koja se sastoji od više
manjih kompleksnih struktura( Navarro and Arroyuelo, 2006). Tijekom gradnje LZ
indeksa, kao što je navedeno, koristi se i sažimanje teksta, što još više utječe na
činjenicu koliko je indeks kompleksan. Poseban naglasak stavit će se na Lempel-
Ziv skupinu sažimanja, točnije na LZ78(Ziv and Lempel, 1978).
Poznato je da LZ78(Ziv and Lempel, 1978) gradi svoj rječnik kojim se
praktički radi faktorizacija teksta na dijelove ( u daljnjem tekstu blokove ). Upravo se
svojstva dobivenih blokova, tj. riječi rječnika koriste za izgradnju raznih struktura,
što će i biti prikazano u nastavku.
U ovom potpoglavlju prikazat će se ideja i okvirni način rada LZ – indeksa
nad radnim primjerom. Radni primjer bit će primjer za prikaz funkcionalnosti
navedenih struktura. Točan algoritam za važnije funkcije poput one search može se
pronaći u radu Indexing text using the Ziv – Lempel trie (Navarro, 2004), a u ovom
završnom radu će se prikazati način rada te funkcije. Za radni primjer koristit će se
tekst 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$.
11
3.1 LZ – indeks ( pregled teorije )
Unutar ovog poglavlja navedena je ideja i način funkcioniranja LZ - indeksa ,
ali u teoretskom smislu , kojeg je 2009. godine, dugo nakon same implementacije
2004. godine (Navarro, 2004), detaljno iznio G. Navarro (Navarro, 2009).
Za izgradnju LZ indeksa teorijski su predviđene četiri strukture: LZTrie,
RevTrie, Node i Range (Navarro, 2004). LZTrie je prefiksno stablo izgrađeno nad
radnim primjerom 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺 . Nad LZTrie je potrebno
obavljati pet vrsta operacija: idt(x), leftrankt(x) i rightrankt(x), parentt(x), childt(x, c),
rtht(x), njihovi opisi mogu se vidjet i u Tablici 3.1, a slika struktura LZTrie i RevTrie
na Slici 3.1.1.
Tablica 3.1 Funkcije LZ - indeksa
FUNKCIJA OPIS
idt(x) Pojedinom čvoru daje identifikacijsku oznaku.
leftrankt(x) Vraća rang trenutnog čvora x.
rightrankt(x) Vraća rang čvora x čiji je podataka leksikografski najveći, a
nalazi se unutar podstabla trenutnog čvora.
parentt(x) Vraća poziciju čvora koji je roditelj zadanog čvora x.
childt(x, c) Vraća poziciju čvora koji je dijete čvora x, a do kojeg vodi
znak c. Ukoliko nema takvog čvora vraća se NULL
vrijednost.
rtht(x) Za zadani rang čvora, ova funkcija vraća identifikacijsku
oznaku čvora x.
12
Sljedeća struktura je RevTrie koja se gradi iz rječnika riječi koje su dobivene
tijekom izgradnje strukture LZTrie, a predstavljaju njihove obrnute nizove (npr.
ukoliko u prefiksnom stablu postoji podniz P=AB, u reverznom prefiksnom stablu taj
niz će biti predstavljen obrnutim nizom, dakle Pr=BA ). Treba napomenuti, da neke
riječi ne će postojati u rječniku, stoga će njihovi čvorovi biti predstavljeni praznim
znakovnim nizom. Funkcije potrebne uz ovu strukturu jednake su onima za strukturu
LZTrie, tj. njihove funkcionalnosti su jednake. To su funkcije: 𝑖𝑑𝑟(𝑥), 𝑙𝑒𝑓𝑡𝑟𝑎𝑛𝑘𝑟(𝑥)
i 𝑟𝑖𝑔ℎ𝑡𝑟𝑎𝑛𝑘𝑟(𝑥), 𝑝𝑎𝑟𝑒𝑛𝑡𝑟(𝑥), 𝑐ℎ𝑖𝑙𝑑𝑟(𝑥, 𝑐), 𝑟𝑡ℎ𝑟(𝑥), analogno funkcijama prikazanima
u Tablici 3.1. U primjeru kasnije se vidi da je ovo struktura koja može imati i čvorove
koji nisu predstavljeni identifikatorom.
Treća struktura koju LZ – indeks treba teorijski2 je Node. To je struktura koja
mapira identifikatore čvorova prefiksnog stabla.
Posljednja struktura koja se koristi u LZ – indeksu je Range. Range je
dvodimenzionalna matrica u kojoj su zapisani identifikatori čvorova čije su
koordinate određene njihovim rangom3 i reverznim rangom4. Svaka dva uzastopna
bloka teksta T su par koji imaju reverzni rang i rang ( redom 𝑟1 i 𝑟2 ). Identifikator
čvora čiji redni broj određuje reverzni rang 𝑟1 za jedan je manji od identifikatora
čvora čiji redni broj određuje rang 𝑟2. Dakle, vrijedi 𝑟𝑡ℎ𝑟(𝑟1) + 1 = 𝑟𝑡ℎ(𝑟2). Range
struktura podataka može se vidjeti u matrici koja je prikazana u obliku tablice u
Tablici 3.4.
Četiri navedene strukture podataka dostatne su za izgradnju LZ – indeksa
koji se gradi nad ulazom 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$. Na Slici 3.1.1(a) mogu
se vidjeti dobiveni blokovi LZ78 sažimanjem, na Slici 3.1.1(b) može se vidjeti izračun
funkcija navedenih u Tablici 3.1, vezanih uz LZtrie strukturu podataka. Funkcije za
strukturu podataka RevTrie su analogne i prikazane su na Slici 3.1.1(c).
2 Treba napomenuti da je praktična izvedba nekih struktura podataka slična, ali ne i ista. Naime, ponekad je u praksi potrebno malo izmijeniti neke stvari zbog praktičnosti rješenja. Za više informacija pogledati rad Indexing text using the Ziv – Lempel trie (Navarro, 2004). Treba nadodati da moja implementacija također nema ovu strukturu podataka. 3 Redni broj čvora kada se stablom prolazi u preorder poretku. 4 Redni broj čvora kada se reverznim stablom prolazi u preorder poretku.
13
Slika 3.1.1 (a) Blokovi dobiveni LZ78 sažimanjem nad ulaznim nizom 𝑻 = 𝑨𝑪𝑻𝑮𝑨𝑪𝑻𝑨𝑪𝑨𝑪𝑨𝑪 TAGCTACG$. (b) Izgled strukture LZTrie s izračunom pripadajućih funkcija (c) Izgled strukture RevTrie i izračun njenih pripadajućih funkcija
14
3.2 LZ77 sažimanje teksta
U ovom odlomku prikazat će se LZ77 kompresija (Ziv and Lempel, 1977), koja
se može također koristiti u svrhu izgradnje LZ – indeksa. Obavit će se kompresija
nad tekstom 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ . Osnovni algoritam LZ77 koristi
statički rječnik čiji su ulazi predefinirani i konstantni tijekom trajanja kompresije.
Osnovna ideja LZ77 kompresije je podjela teksta na dijelove tako da se
stavljaju pokazivači na one dijelove koji se ponavljaju, ali ovoga puta pomoću dva
statička prozora ( izgradnja rječnika ): prozor za traženje veličine 7 i prozor za
kodiranje veličine 5 5 . Postupak sažimanja radnog primjera 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴
𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ može se vidjeti u Tablica 3., a objašnjenje ispod nje.
Tablica 3.2 Prikaz LZ77 kompresije nad nizom 𝑻 = 𝑨𝑪𝑻𝑮𝑨𝑪𝑻𝑨𝑪𝑨𝑪𝑨𝑪𝑻𝑨𝑮𝑪𝑻𝑨𝑪𝑮$. Veličina prozora za traženje je 7, a prozora za kodiranje je 5.
ACTGACTACACACTAGCTACG$
PROZOR ZA TRAŽENJE
7 6 5 4 3 2 1 PROZOR ZA KODIRANJE
OSTATAK IZLAZ KORAK
← A C T G A CTA… (0, 0, A) 1
← A C T G A C TAC… (0, 0, C) 2
← A C T G A C T ACA.. (0, 0, T) 3
← A C T G A C T A CAC… (0, 0, G) 4
← A C T G A C T A C ACA.. (4, 3, A) 5
C T G A C T A C A C A C TAG… (3, 1, A) 6
G A C T A C A C A C T A GCT… (2, 3, T) 7
A C A C A C T A G C T A CG$... (3, 1, G) 8
A C A C T A G C T A C G $ (4, 3, C) 9
T A G C T A C G $ (5, 1, $) 10
G C T A C G $
5 Ove vrijednosti uzete su nasumično i bez ikakvog pravila, u svrhu demonstracije algoritma sažimanja.
15
Na početku ( za prva četiri znaka ) ulazni niz ulazi u prozor za traženje, znak
po znak, jer znak koji se nalazi na prvom mjestu ( gledano s lijeva ) nije unutar njega.
U petom koraku u prostoru za traženje nalaze se znakovi 𝐴𝐶𝑇𝐺, a u prozoru
za kodiranje nalaze se znakovi 𝐴𝐶𝑇𝐴𝐶, počevši od četvrtog mjesta ( gledano zdesna
). Iz prostora za kodiranje prva četiri znaka ne poklapaju se sa znakovima iz prostora
za traženje. Međutim, prva tri znaka se poklapaju se s tri znaka iz prostora za
traženje i to počevši od odmaka ulijevo duljine četiri. U ovom slučaju, izlaz čini zapis
(4, 3, 𝐴). Prvi dio izlaza čini brojka četiri koja označava koliki je odmak ulijevo u
prozoru za traženje, a na kojem počinje podniz koji se podudara s početkom niza
unutar prozora za kodiranje. Drugi dio izlaza čini brojka tri koja označava duljinu
podniza unutar prozora za traženje koji se podudara s nizom u prozoru za kodiranje
( to je podniz 𝐴𝐶𝑇 ). Treći dio izlaza čini slovo ( u ovom slučaju slovo 𝐴 ) koje
označava znak koji je sljedeći poslije niza unutar prozora za kodiranje, točnije znak
koji se nalazi na četvrtom mjestu ( brojka iz srednjeg dijela izlaza uvećana za jedan
).
LZ77 sažimanje teksta nastavlja se sve dok se ne dođe do kraja zadanog
teksta. Treba napomenuti da u ovakvoj vrsti sažimanja postoji jedan poseban slučaj.
Naime, ukoliko smo našli podniz unutar prozora za traženje i njegov kraj se nalazi
na prvom mjestu ( gledano zdesna ), a taj isti podniz ne završava na kraju prozora
za kodiranje, tada se ponovno gleda početak istog tog podniza u prozoru za traženje
i ukoliko se on ponovno poklapa sa sljedećim znakom iz prozora za kodiranje,
kodiranje se nastavlja ( ovaj slučaj nije se dogodio u gore izračunatom primjeru ).
Posljednji izlaz svakog LZ77 sažimanja podataka završava posebnim
znakom koji je uveden i označava kraj ulaznog niza ( znak $ ), samim time završava
i LZ77 algoritam.
16
3.3 LZ78 sažimanje teksta
U ovom odlomku prikazat će se LZ78 sažimanje teksta (Ziv and Lempel,
1978). Upravo LZ78 način sažimanja koristit će se u izgradnji LZ - indeksa, tome
najviše pridonosi činjenica da se izlaz u ovom načinu sažimanja sastoji od manje
podataka od LZ78 načina, stoga koristi manje memorije.
Osnovna ideja LZ78 kompresije je podjela teksta na dijelove tako da se
stavljaju pokazivači na one dijelove koji se ponavljaju ( izgradnja rječnika ).
Postupak izgradnje rječnika s blokovima ( riječi u rječniku ) prikazan je u tablici 2.
Izlaz kompresije LZ78 je niz oblika ( 𝑘, 𝑛𝑜𝑣𝑜_𝑠𝑙𝑜𝑣𝑜 ) gdje je k pokazivač na indeks
bloka u rječniku, 𝑛𝑜𝑣𝑜_𝑠𝑙𝑜𝑣𝑜 je zadnji znak novog bloka rječnika kao dodatak na
blok na kojeg pokazuje pokazivač. Sažimanje radnog primjera 𝑇 = 𝐴𝐶𝑇𝐺𝐴
𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ može se vidjeti u Tablica 3.3, a objašnjenje ispod nje.
Tablica 3.3 Prikaz LZ78 kompresije za radni primjer 𝑻 = 𝑨𝑪𝑻𝑮𝑨𝑪𝑻𝑨𝑪𝑨𝑪𝑨𝑪𝑻𝑨𝑮𝑪𝑻𝑨𝑪𝑮$
IDENTIFIKATOR BLOKA BLOK IZLAZ
0 „“
1 „A“ ( 0, A )
2 „C“ ( 0, C )
3 „T“ ( 0, T )
4 „G“ ( 0, G )
5 „AC“ ( 1, C )
6 „TA“ ( 3, A )
7 „CA“ ( 2, A )
8 „CAC“ ( 7, C )
9 „TAG“ ( 6, G )
10 „CT“ ( 2, T )
11 „ACG“ ( 5, G )
12 „$“ ( 0, $ )
17
LZ77 sažimanje teksta uvijek započinje praznim nizom. Praznom nizu uvijek
se dodjeljuje broj nula kao identifikator, dakle on je nulti blok ( nulta riječ ) unutar
rječnika.
Sljedeća četiri bloka u Tablici 3.3 čine po jedno slovo koje do tada nije bilo
unutar rječnika, točnije u skupu blokova. Neka se uzme izlaz koji pripada bloku
jedan: (0, 𝐴), prvi dio izlaza jest brojka, tj. pokazivač na blok koji prethodi trenutnom
bloku, drugi dio jest slovo kojim trenutni blok završava.
Peti izlaz pokazuje na prvi blok što znači da mu prethodi blok koji završava
na slovo A. Općenito vrijedi da svaki blok čini cjelokupni niz prethodnika na koje
svaki od njih pokazuje.
LZ78 sažimanje ulaznog niza nastavlja se sve dok se ne dođe do posljednjeg
bloka koji završava posebnim znakom za kraj $. Dakle, nad ulaznim nizom 𝑇 =
𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ izgrađen je rječnik LZ78 algoritma koji se sastoji od
blokova. Možemo vidjeti niz fraza 𝐶[1, 𝑢] = |A|C|T|G|AC|TA|CA|CAC|TAG|CT
|ACG|$, upravo će prefiksno stablo biti izgrađeno nad ovim blokovima u nastavku, a
reverzno prefiksno stablo će biti izgrađeno nad ovim, ali invertiranim blokovima, kao
što će biti prikazano.
18
3.4 Algoritam pretraživanja podniza pomoću LZ78
Algoritam pretraživanja podniza temeljni je algoritam na kojem se temelji rad
LZ – indeksa stoga će se ideja ovog algoritma temeljito objasniti. Dijelovi koji se ne
podudaraju s implementacijom bit će objašnjeni u poglavlju u kojem se govori o
načinu implementacije ove funkcije unutar programskih jezika C i C++ ( Poglavlje
4. ). Funkcija koja pretražuje ulazni niz u potrazi za podudaranjem s podnizom koji
korisnik zada sastoji se od tri velika dijela.
3.4.1 Vrste pojavljivanja podniza unutar niza
Ovisno o duljini pretraživanog podniza 𝑃 duljine 𝑚 moguće je da se dogode
tri vrste pojavljivanja ( engl. occurence ) podniza unutar bloka koji su dobiveni u
odlomku LZ78 sažimanje teksta. Sve vrste mogu se vidjeti na Slici 3.4.1.
Prva vrsta je pojavljivanje podniza unutar jednog bloka. Ovakva vrsta
pojavljivanja dogodi se kada se cijeli podniz nađe unutar jednog bloka, a početna
pozicija takvog bloka može se dogoditi na bilo kojoj poziciji unutar bloka za koju
vrijedi da od te pozicije podniz još uvijek završava unutar kraja bloka.
Druga vrsta je pojavljivanje podniza unutar dva bloka. Ovakva vrsta
pojavljivanja dogodi se kada se podniz podudara s dva bloka, ako i samo ako su ta
dva bloka jedan iza drugog, tj. vrijedi da je identifikator prvog bloka za jedan veći od
identifikatora drugog bloka.
Treća vrsta jest pojavljivanje podniza unutar više blokova. Ovakva vrsta
pojavljivanja dogodi se uglavnom kada je podniz dugačak i proteže se kroz više
blokova.
Slika 3.4.1 Moguće vrste pojavljivanja podniza s bilo kojim ulaznim nizom
19
3.4.2 Pojavljivanje podniza unutar jedne fraze
Na Slici 3.4.1 moglo se vidjeti pojavljivanje unutar jednog bloka, označeno
brojkom 1. Treba napomenuti da takvo pojavljivanje ne mora ići od početka do kraja
fraze nego može biti i kraće. Kao primjer, podniz čije pojavljivanje će se tražiti unutar
jednog bloka bit će 𝑃 = 𝐴𝐶. Kako bi se pronašla sva pojavljivanja podniza 𝑃 unutar
jednog bloka u zadanom tekstu 𝑇 koristi se sljedeći algoritam(Navarro, 2004):
Pronaći reverzni podniz od 𝑃 unutar reverznog prefiksnog stabla RevTrie.
Ovime se stiglo do čvora 𝑥 takvog da svaki čvor unutar podstabla čiji je
korijen čvor 𝑥 predstavlja frazu koja završava podnizom P.
Izračunati vrijednosti funkcija 𝑙𝑒𝑓𝑡𝑟𝑎𝑛𝑘𝑟(𝑥) i 𝑟𝑖𝑔ℎ𝑡𝑟𝑎𝑛𝑘𝑟(𝑥) čime se dobiva
leksikografski interval, unutar reverznih blokova, blokova koji završavaju
podnizom P.
Za svaki rang 𝑟 ∈ 𝑙𝑒𝑓𝑡𝑟𝑎𝑛𝑘𝑟(𝑥) … 𝑟𝑖𝑔ℎ𝑡𝑟𝑎𝑛𝑘𝑟(𝑥) treba pronaći odgovarajući
čvor u strukturi LZTrie, 𝑦 = 𝑁𝑜𝑑𝑒(𝑟𝑡ℎ𝑟(𝑟)). Sada su identificirani čvorovi u
strukturi LZTrie koji završavaju s podnizom P .
Za svaki čvor 𝑦 koji je identificiran u prethodnoj točki algoritma treba obići
podstablo čiji je korijen čvor 𝑦 i zabilježiti takve čvorove. Tijekom ovog
procesa zna se točna udaljenost između kraja podniza 𝑃 i kraja fraze.
Treba zapaziti da ukoliko jedan blok unutar RevTrie sadrži nekoliko
pojavljivanja podniza 𝑃 , svako pojavljivanje takvog podniza 𝑃 bit će zabilježeno
točno jednom iz razloga što svaki čvor 𝑦 unutar jednog podstabla strukture LZTrie
odgovara točno jednom čvoru 𝑥, tj. njegovoj dubini u stablu koja zapravo znači broj
odmaka od početka pojedinog bloka podstablu strukture LZTrie6, a samim time i
pojavljivanje na različitom mjestu.
6 Tijekom objašnjenja ovog dijela algoritma nazvanog search (Navarro, 2004) koristit će se samo prijavljivanje onih dijelova koji se nalaze potpuno u jednom bloku, iako podniz koji tražimo u tekstu postoji, ali algoritam za pojavljivanje podniza unutar dva bloka bit će objašnjen u nastavku.
20
Na slikama u nastavku može se vidjeti način rada algoritma za pojavljivanja
podniza unutar jednog bloka. Na Slika 3.4. se može vidjeti način rada prve dvije
točke algoritma. Pronađen je čvor x nad kojim su zatim obavljene operacije
leftrankr(x), rightrankr(x) i rthr(x).
Na Slici 3.4.3(a) se može vidjeti da su označeni čvorovi 5 i 8, ali i čvor 11
unutar strukture LZTrie. Naime, čvor 11 označen je zbog čvora 5, razlog je objašnjen
u četvrtom dijelu algoritma. a Slici 3.4.3(b) vide se blokovi u kojima su prijavljena
pojavljivanja podniza P unutar teksta T.
Slika 3.4.2 Prikaz strukture podataka RevTrie s izračunom funkcija potrebnih za pronalazak
podudaranja unutar jednog bloka za radni primjer 𝑻 = 𝑨𝑪𝑻𝑮𝑨𝑪𝑻𝑨𝑪𝑨𝑪𝑨𝑪𝑻𝑨𝑮𝑪𝑻𝑨𝑪𝑮$
21
Slika 3.4.3 Izgled prefiksnog stabla LZTrie s prikazanim čvorovima koji su prijavljeni (a) i pojavljivanje podniza unutar jednog bloka za dani ulazni niz
𝑻 = 𝑨𝑪𝑻𝑮𝑨𝑪𝑻𝑨𝑪𝑨𝑪𝑨𝑪𝑻𝑨𝑮𝑪𝑻𝑨𝑪𝑮$ (b)
22
3.4.3 Pojavljivanje podniza unutar dvije fraze
Na slici 3.4.1. može se vidjeti pojavljivanje unutar dvije fraze ( bloka )
označeno brojkom 2. Podniz čije pojavljivanje ( engl. occurence ) će se tražiti unutar
jednog bloka bit će 𝑃 = 𝐶𝑇𝐴. Ideja je da se za svaku moguću vrstu razdvajanja
traženog podniza uzme prefiksni dio ( do granice fraze ) i sufiksni dio ( od granice
fraze ) . Prefiksni dio se zatim traži u strukturi RevTrie a sufiksni dio u strukturi
LZTrie. Sada se promatraju dvije vrste ranga, oblika ( 𝑟1, 𝑟2 ), gdje je r1 rang iz
strukture RevTrie, a r2 rang iz strukture LZTrie.
Kako bi se pronašla sva pojavljivanja podniza P unutar dva bloka u zadanom
tekstu T koristi se sljedeći algoritam (Navarro, 2004):
Napraviti sve moguće prefikse i sufikse zadanog podniza P.
Za svaki prefiks ( kojeg treba prvo invertirati ) tražiti čvor x kojim reverzni
prefiks završava u strukturi RevTrie, a za svaki sufiks, treba ga tražiti ga u
strukturi podataka LZTrie dok ne se ne dođe do čvora y.
Koristeći strukturu Range pronaći rang [𝑙𝑒𝑓𝑡𝑟𝑎𝑛𝑘𝑟(x) … 𝑟𝑖𝑔ℎ𝑡𝑟𝑎𝑛𝑘𝑟(x)] ×
[𝑙𝑒𝑓𝑡𝑟𝑎𝑛𝑘𝑡(y) … 𝑟𝑖𝑔ℎ𝑡𝑟𝑎𝑛𝑘𝑡(y)].
Za svaki par oblika ( 𝑟1, 𝑟2 ) zabilježiti 𝑟1.
Pošto je zadan podniz 𝑃 = 𝐶𝑇𝐴, od njega je potrebno napraviti sve moguće
sufikse i prefikse. Imamo prefikse 𝐶 𝑖 𝐶𝑇 u jednom bloku i sufikse 𝑇𝐴 i 𝐴 u njemu
desnom susjednom bloku. Prefiksi se invertiraju pa se pretražuju 𝐶 𝑖 𝑇𝐶 u strukturi
RevTrie ( slika 3.3.2.1. ), sufikse pretražujemo u strukturi LZTrie ( slika 3.3.2.2. ).
Ukratko će se objasniti način dobivanja vrijednosti unutar matrice Range ( tablica 3.
). Imamo kao nultu frazu 𝐹(0) = „“ i kao prvu frazu 𝐹(1) = „𝐴“. Rang nulte fraze u
reverznom prefiksnom stablu RevTrie je 0, a rang druge fraze u prefiksnom stablu
je 2. Na ovaj način dobila se pozicija ove dvije fraze u matrici Range. U LZTrie
strukturi podataka pronađeni očitavanjem funkcija oblika iz treće točke algoritma su
[1, 3] i [10, 11], a u RevTrie strukturi pronađeni su [11, 11]i[4, 6]. Sada u matrici
Range ( tablica 3.) postoje dva dvodimenzionalna ranga: (11, 1) × (10, 3) i
(4, 11) × ( 6, 11). Potpuni postupak unutar ovog odlomka može se vidjeti na Slici
3.4.4, u Tablici 3.4.
23
Slika 3.4.4 Prikaz blokova nad kojima je izgrađeno prefiksno stablo (a), prikaz
strukture LZTrie s izračunatim funkcijama (b) za podniz 𝑷 = 𝑪𝑻𝑨 (b), prikaz strukture RevTrie s funkcijama izračunatim za dani podniz (c) i
prikaz pojavljivanja podniza 𝑷 za dva bloka
24
Tablica 3.2 Prikaz strukture podataka Range dobivene iz fraza LZ78 rječnika
Dakle, imali smo dva izračunata dvodimenzionalna ranga: (11, 1) × (10, 3) i
(4, 11) × ( 6, 11). Njih treba označiti i provjeriti postoje li identifikatori unutar njih (
zelenom bojom označena polja unutar Tablice 3.4 ). Može se vidjeti da su prijavljena
točno tri identifikatora blokova ( 5, 8 i 10 ). To su upravo blokovi u kojima se podniz
𝑃 = 𝐶𝑇𝐴 pojavljuje. Mjesta tih identifikatora u ulaznom nizu mogu se vidjeti na Slici
3.4.2 u d dijelu.
rang revrang 0 1 2 3 4 5 6 7 8 9 10 11 12
0 0
1 1
2 7
3 6
4 2
5 5
6 8
7 4
8 9
9 11
10 3
11 10
12
25
3.4.4 Pojavljivanje podniza unutar tri ili više fraza7
Prisjetimo se da LZ78 algoritam garantira da za svaki čvor koji postoji u
LZTrie-u postoji jedan i samo jedan blok. Ideja algoritma za izračunavanje
pojavljivanje podniza unutar tri ili više blokova je sljedeća. Uzet će se srednji dio
uzorka koji pretražujemo unutar teksta dakle 𝑃[𝑖, 𝑗] i pokušavati ga povezati sa
prethodnim 𝐾[𝑘 − 1] = 𝑃[0, 𝑖 − 1] i sljedećim 𝐾[𝑘 + 1] = 𝑃[𝑟, 𝑚 − 1] blokom tako
da se dobije uzorak 𝑃[0, 𝑖 − 1] + 𝑃[𝑖, 𝑗 − 1] + 𝑃[𝑗, 𝑟 − 1]8 + 𝑃[𝑟, 𝑚 − 1] =
𝑃[0, 𝑚 − 1], gdje je " + " oznaka za konkatenaciju. Vrijedi 1 < 𝑖 ≤ 𝑗 ≤ 𝑟 < 𝑚.
Broj pojavljivanja ovakvog podniza ne može biti veći od 𝑚2, ako se uzme 𝑚 = |𝑃|
Kako bi se pronašla sva pojavljivanja podniza 𝑃 unutar tri ili više blokova u
zadanom tekstu 𝑇 koristi se sljedeći algoritam(Navarro, 2004):
Za svaki 1 ≤ 𝑖 ≤ 𝑗 ≤ 𝑚 pronaći podniz 𝑃[𝑖, 𝑗] u prefiksnom stablu i zapamtiti
ga zapisivanjem u posebno polje za svaki 𝑖. Ako ne postoji takav
podniz za par ( 𝑖 , 𝑗 ) prestajemo traženje i krećemo na sljedeću
iteraciju ( 𝑖 + 1, 𝑗 + 1 ).
Za svaki 1 ≤ 𝑖 ≤ 𝑗 < 𝑚 ( za svaku iteraciju 𝑖, povećava se 𝑗 ) i pokušava se
produžiti podniz 𝑃[𝑖, 𝑗] nadesno. Zaustaviti se kada se više ne može
napredovati udesno. Stalo se na 𝑃[𝑗, 𝑟], uz uvjet 𝑟 < 𝑚 − 1. Slijedi:
o Za svaki 𝑃[𝑗, 𝑟] koji se ponašao, a da za takav vrijedi 𝑟 < 𝑚 − 1. Provjeriti
postoji li blok 𝑃[𝑟, 𝑚 − 1] koji se nadovezuje na blok
𝑃[𝑖, 𝑗]. Ukoliko je 𝑟 < 𝑚 − 1, a na blok se ne nadovezuje podniz
𝑃[𝑟, 𝑚], tada ne postoji takav podniz i prelazi se na sljedeću
iteraciju 𝑃[𝑖, 𝑗 + 1].
o Ako je 𝑖 > 1 treba provjeriti postoji li blok 𝑃[0, 𝑖] takav da se na njega
nadovezuje blok 𝑃[𝑖, 𝑚 − 1]. Ukoliko ne postoji pređi na
sljedeću iteraciju.
o Ako postoji takav blok 𝑃[1, 𝑖 − 1], pronašli smo podniz koji se nalazi
unutar tri ili više blokova.
7 Ovaj dio algoritma bit će detaljnije objašnjen u sljedećim poglavljima koji se bave točnom implementacijom u praksi. 8 Ako postoji, to bi značilo da se podniz proteže kroz više od tri bloka.
26
4 LZ – indeks ( implementacija )
Izgradnja LZ – indeksa jako je komplicirana pošto koristi mnoge strukture
podataka kako bi se brzo došlo do rezultata koje se dobije traženjem pojavljivanja
podniza P unutar teksta T. Naš radni primjer će opet biti 𝑇 = 𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴
𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ , radi lakšeg povlačenja poveznica između mog i indeksa
Navarra (Navarro, 2009).
Ovo poglavlje daje kompletan pregled procesa izrade jednog LZ – indeksa,
temeljenog na ideji koju je dao Navarro (Navarro, 2004), od izgradnje pojedinih
struktura podataka, vremena pretraživanja, pa sve do količine potrošnje memorije
ovog indeksa.
Sama izgradnja indeksa odvija se u nekoliko velikih koraka:
Učitavanje i čitanje datoteke
Izgradnja strukture prefiksno stablo ( ekvivalent LZTrie )
Izgradnja strukture reverznog prefiksnog stabla ( ekvivalent RevTrie )
Izgradnja strukture tČvor
Izgradnja strukture rČvor
Rangiranje čvorova prefiksnog i reverznog prefiksnog stabla
Implementacija funkcije za prijavljivanje podniza unutar jednog bloka
Implementacija funkcije za prijavljivanje podniza unutar dva bloka
Implementacija funkcije za prijavljivanje podniza unutar više blokova
Oslobađanje zauzete memorije.
27
4.1 Izgradnja strukture Z-prefiksno stablo ( engl. Z-Trie )
U odlomku LZ78 i LZ – indeks ) objašnjeno je što je to LZ78 kompresija i
kako ona pomaže u stvaranju blokova kojima će se izgraditi prefiksno stablo ( u
nastavku PS ) i reverzno prefiksno stablo ( u nastavku RPS ), međutim njihova se
implementacija učinila vrlo kompliciranom.
Razmatrala se mogućnost izgradnje PS-a tijekom koje će se pamtiti blokovi
koji su dobiveni LZ78 sažimanjem ulaznog niza. unutar dinamičkog polja, kako bi se
kasnije pomoću njih mogao izgraditi RPS. Indeks sam po sebi ima veliko zauzeće
unutar radne memorije, stoga nije prihvatljivo dodatno ju opterećivati. Sljedeća
zamisao bila je zapisivanje riječi u posebnu datoteku iz koje će se kasnije one čitati.
Nedostatak ovakve implementacije je sporost izvođenja. Došao sam na ideju
izgradnje potpuno nove strukture podataka, koja nije postojala dosad. Do ove
strukture podatka doći ćemo nakon što se prisjetimo njenih građevnih elemenata.
Za potrebe izrade LZ – indeksa, tj njegovih struktura navode se blokovi
dobiveni LZ78 načinom sažimanja podataka: 0 | A | C | T | G | AC | TA | CA |
CAC | TAG | CT | ACG | $ čiji je ulaz bio niz koji služi kao radni primjer 𝑇 =
𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$, a koji su već prikazani kod teoretskog dijela LZ –
indeksa.
28
4.1.1 Prefiksno stablo u LZ – indeksu
Prisjetimo se izgleda PS-a ( ovog puta u trodimenzionalnom prikazu, radi
lakše vizualizacije - Slika 4.1.1 Prefiksno stablo ).
Iz gornje slike se može vidjeti da je ova struktura ( PS ) i za kratak tekst 𝑇 =
𝐴𝐶𝑇𝐺𝐴𝐶𝑇𝐴𝐶𝐴𝐶𝐴𝐶𝑇𝐴𝐺𝐶𝑇𝐴𝐶𝐺$ duljine samo 𝑛 = 22 znaka ( prisjetimo se da mi
koristimo datoteke u kojima se nalazi puno više od 106 znakova ) znaka poprima
kompliciran oblik. Međutim ona ima neka vrlo važna i povoljna svojstva koje LZ –
indeks koristi u najvećoj mogućoj mjeri. Jedan čvor ( y ) predstavlja točno jedan blok
i ne može postojati drugi blok koji završava u prethodnom čvoru ( svaki čvor ima
svoj jedinstveni identifikator ). Što se dublje ide u stablo, to je dužina bloka dulja.
Uzmimo za primjer čvorove s identifikatorima 1 i 11 ( 0 označava početak
teksta, tj. prazan niz ). Da bismo došli do bloka 1 potrebno je proći po grani s
oznakom „A“. To znači da je B1 = A. Da bismo došli do bloka 11, potrebno je proći
po grani s oznakom „A“ do čvora s identifikatorom 1, zatim po grani s oznakom „C“
do čvora s identifikatorom 5 i na posljetku ući u čvor s identifikatorom 11, prolazeći
po grani s oznakom „G“. To bi značilo da blok s identifikatorom 11 zapravo označava
blok B11 = ACG. Ovo je bio način čitanja riječi blokova iz stabla.
Slika 4.1.1 Prefiksno stablo
29
Na Slici 4.1.2 nalaze se varijable čvorova PS-a na sljedećem odsječku C koda:
struct element {
char nukleotid;
char brojDjece;
long int identifikator;
long int rang;
char zauzetaMemorija;
struct element *djeca[BROJ_DJECE];
};
typedef struct element trieCvor; Slika 4.1.2 Prikaz varijabli svakog čvora strukture PS
Može se vidjeti da se čvor sastoji od varijabli: nukleotid koja označava koji je
posljednji put kojim smo prošli kako bismo došli do njega, brojDjece koja govori
koliko djece neposredno ima čvor u kojem se nalazimo, zauzetaMemorija koja
govori točno koje dijete čvora u kojem se nalazimo postoji, identifikator, rang –
varijabla koja govori koji je ( leksikografski ) po redu trenutni čvor od svih čvorova i
polje pokazivača djeca koje sadrži pokazivače na djecu čvora. Ovo je također
osnovni građevni element svih struktura podataka koje koristi LZ – indeks ( uz malu
nadopunu jedne varijable koju koristi RPS ).
4.1.2 Reverzno prefiksno stablo u LZ – indeksu
Reverzno prefiksno stablo koje koristim u LZ – indeksu vrlo je slično
prefiksnom stablu, a najveća je razlika što se reverzno prefiksno stablo, kako sam
naziv kaže popunjava blokovima Bk u obrnutom redoslijedu. Uzmimo ponovno blok
11 iz poglavlja 4.1.1. On je označavao podniz ACG. U slučaju reverznog prefiksnog
stabla, Blok B11 označavat će podniz GCA ( Slika 4.2 ). No, može se primijetiti da
reverzni niz CA zasad ne postoji u reverznom stablu i mora se stvoriti prazan čvor
s identifikatorom 0, na putu C. Od praznog čvora ( crvene kuglice - Slika 4.1.3 )
postoji čvor s identifikatorom 11 i smještamo se u njega.
30
Slika 4.1.3 Reverzno prefiksno stablo
Implementacija reverznog prefiksnog stabla u pogledu izgradnje čvorova s
identifikatorima puno je jednostavnija od izgradnje prefiksnog stabla jer već imamo
gotove blokove koje ćemo ubacivati. S druge strane, izgradnja se komplicira
postojanjem čvorova koji nemaju identifikator, što ujedno otežava i obilazak stabla.
struct revElement {
char nukleotid;
char brojDjece;
long int identifikator;
long int rang;
char zauzetaMemorija;
trieNode *mapaCvora;
struct revElement *djeca[BROJ_DJECE];
};
typedef struct revElement revTrieCvor; Slika 4.1.4 Varijable pojedinog čvora unutar strukture RPS
Vidimo sa Slike 4.1.3 da su gotovo sve varijable jednake kao i u PS-u, uz
dodatak pokazivača na čvor iz PS-a – ovo ujedno ovu strukturu čini jedinstvenom.
31
4.1.3 Z – prefiksno stablo
U ovom poglavlju govori se o potpuno novoj strukturi podataka koju je
najprikladnije prikazati trodimenzionalnom9, kompleksne građevne jedinice su joj
strukture PS i RPS. Upravo u činjenici da je ovo trodimenzionalna struktura leži i dio
naziva ove strukture, a to je Z, što u matematici obično označava treću os na
grafikonima ( z – os ) u koordinatnom sustavu. Z-prefiksno stablo ( engl. Z-Trie )
centralna je struktura implementacije LZ – indeksa ovog završnog rada i važna je
za kompetitivnu brzinu pretraživanja pojavljivanja podnizova unutar zadanog teksta.
Na Slici 4.1.5 mogu se prepoznati osnovne strukture podataka PS i RPS.
Linije koje su u različitim bojama su zapravo jednosmjerni pokazivači iz smjera RPS-
a prema PS-u što ovu strukturu podataka čini kompaktnom. Na Slika 4.1.5 Z-prefiksno
stablo1.5 može se uočiti da su identifikatori pokazivača RPS-a za jedan manji od
identifikatora pokazivača PS-a. Upravo to svojstvo koristi se u algoritmu
pretraživanja pojavljivanja podniza P unutar dva bloka, jer par ( 𝑖𝑑(𝑅𝑃𝑆), 𝑖𝑑(𝑃𝑆) )
čini most među dva susjedna bloka.
9 Baš kao i trodimenzionalnog polja( koje se prikazuje u obliku kocke ) građa ove strukture čini je prikladnom za prikaz unutar koordinatnog sustava s tri osi ( 𝑥, 𝑦, 𝑧 ).
Slika 4.1.5 Z-prefiksno stablo
32
Kao što se moglo vidjeti ova struktura podataka je vrlo kompleksna. Broj
čvorova koji se stvori u ovisnosti o veličini ulazne datoteke, prikazan je na Slici 4.1.6,
koja ujedno i pokazuje učinak kompresije koja se odvila tijekom izgradnje Z –
prefiksnog stabla.
4.1.4 Izgradnja Z – prefiksnog stabla
Izgradnja Z – prefiksnog stabla zauzima daleko najveći postotak u ukupnom
vremenu izgradnje LZ – indeksa, upravo zbog svoje kompleksnosti. Za potrebe ovog
završnog rada implementirao sam dva različita načina izgradnje Z – prefiksnog
stabla. Jedan način je statičko polje koje sadrži pokazivače na čvorove – djecu (
prisjetimo se da se naša abeceda sastoji od 4 znaka: A, C, G, T i specijalnog znaka
$, u svrhu pretraživanja genoma ), što znači da čvor roditelj ima pokazivače na pet
čvorova – djece. Drugi način je bio dinamičko polje pokazivača, kojim svaki
novostvoreni čvor nema pokazivača na djecu, sve dok se ne stvori neki novi čvor
koji je dijete čvora.
Slika 4.1.6 Broj nastalih čvorova u ovisnosti o veličini ulazne datoteke
33
Rješenje G. Navarra (Navarro, 2004) je sporije pošto on prefiksno stablo (
LZTrie ) i reverzno prefiksno stablo ( RevTrie ) gradi jedno po jedno. Ubrzanje u
odnosu na Navarrovo rješenje je u istodobnoj izgradnji ovih struktura što je
kompliciraniji način.
Istovremenu izgradnju PS-a i RPS-a omogućuje niz koji je dobiven
pamćenjem znakova koji se nalaze unutar jednog bloka PS-a. Usred izgradnje PS-
a, kada smo napunili određeni blok, gradimo RPS, što se pokazalo veoma
vremenski učinkovitim. Trajanja izgradnje Z – prefiksnog stabla na oba načina mogu
se vidjeti na Slici 4.5.
Sa Slike 4.5 može se očitati da je izgradnja Z – prefiksnog stabla s dinamičkim
poljem pokazivača na djecu gotovo duplo sporija od one sa statičkim poljem. Razlog
se pronalazi u tome što je za dinamičko polje potrebno puno manjih zauzimanja
memorije, dok za statičko polje to nije slučaj.
Slika 4.1.7 Vrijeme izgradnje Z - prefiksnog stabla
34
4.2 Izgradnja struktura rČvor i tČvor
Dvije manje strukture koje se koriste u implementaciji LZ – indeksa ovog
završnog rada su rČvor i tČvor. One su polja pokazivača na djecu Z – prefiksnog
stabla, točnije struktura tČvor pokazuje na djecu PS-a, a struktura rČvor na djecu
RPS-a. Specifičnost ovih struktura je ta što je čvor na koji one pokazuju određena
numeričkim redoslijedom prolaska kroz PS i RPS ( preorder prolazak kroz stabla ).
Ukoliko je na primjer čvor s identifikatorom treći po redu u preorder obilasku
PS-a, tada se on nalazi u polju na 3. mjestu ( 𝑡Č𝑣𝑜𝑟[3], 0. mjesto zauzima korijen
PS-a koji označava prazan niz ). Dakle ove strukture se grade rekurzivnim
obilaskom Z – prefiksnog stabla.
Sa slike ( Slika 4.2.1 ) očitavamo da je vrijeme izgradnje ovih struktura puno
manje u usporedbi s izgradnjom Z – prefiksnog stabla, kao što sam i naveo. Brzina
izgradnje je neovisna o vrsti implementacije polja pokazivača na djecu zbog
rekurzivnog spusta, stoga su navedena vremena samo kod implementacije
statičkim poljem.
Slika 4.2.1 Vrijeme izgradnje struktura tČvor i rČvor
35
4.3 Funkcija pretraži
Funkcija pretraži, kao što i sam naziv govori, jest funkcija koja omogućuje
pronalazak pojavljivanja zadanog podniza P unutar teksta T. Funkcija pretraži ovog
završnog rada implementira manje podfunkcije: pojavljivanje podniza unutar jednog,
dva i tri ili više blokova koje je Navarro (Navarro, 2009) predložio u teoretskom dijelu,
uz neke izmjene koje su prilagođene strukturama podataka za potrebe ovog
završnog rada. Ova funkcija sastoji se od tri vrste pretrage: pretraživanje unutar
jednog, dva ili više blokova.
4.3.1 Pojavljivanja podniza unutar jednog bloka
Ovakva vrsta pojavljivanja vrlo je česta i relativno je lagana za izračunati. Na
slici ( Slika 4.3.1 ) možemo vidjeti broj pronalazaka podniza u ovisnosti o veličini
datoteke i duljini tog istog podniza. Možemo vidjeti da taj broj pojavljivanja naglo
opada s porastom duljine podniza kojeg pretražujemo. Tomu doprinosi činjenica da
su blokovi relativno kratki, stoga je puno manja vjerojatnost pronalaska pojavljivanja
podniza unutar jednog bloka, za razliku od pronalaska pojavljivanja unutar dva bloka
( kao što će biti prikazano ). Svi podnizovi unutar funkcija pretraživani su nad
datotekama generiranim slučajnim putem unutar programa Unipro UGENE
(Okonechnikov et al., 2012) koji se bavi istraživanjem genoma.
Slika 4.3.1 Broj pojavljivanja podniza s tekstom unutar jednog bloka
36
Kako bi se pronašla sva pojavljivanja podniza, implementiran je sljedeći
algoritam:
Pozicionirati se u RPS. Ukoliko takav čvor ( nazovimo ga y ) ne postoji, nema
ovakve vrste pojavljivanja.
Za svaki čvor y u podstablu moramo pronaći njegov ekvivalent u PS-u i
izračunati blok s najvećim rangom. Razlika između dobivenog ranga i ranga
trenutnog čvora je upravo dio broj pojavljivanja podniza P s T.
Ponoviti ovaj postupak za svaki čvor u podstablu čvora do kojeg smo došli u
prvom koraku. Ovakvi čvorovi pronalaze se rekurzivno.
Na Slici 4.3.2 može se vidjeti da je pretraživanje ove vrste vrlo brzo i efikasno
( prikazana su vremena u milisekundama ) i da je brzina pretraživanja podniza
unutar jednog bloka u vrlo visokoj korelaciji s duljinom podniza kojeg pretražujemo
( dulji podniz, kraće vrijeme pretraživanja ) i s veličinom datoteke, tj. teksta T koji je
pretraživan ( veći tekst, dulje vrijeme pretrage ).
Slika 4.3.2 Trajanje pretraživanja pojavljivanja podniza unutar jednog bloka
37
4.3.2 Pojavljivanja podniza unutar dva bloka
Ovo je najčešća vrsta pojavljivanja, a razlog leži u tome što imamo puno
malenih blokova, stoga je vrlo velika vjerojatnost da ćemo pronaći pojavljivanje koje
leži na dva bloka ( Slika 4.3.3 ).
Velik broj današnjih uređivača teksta uopće nema implementiranu funkciju
pretraživanja unutar dva ili više blokova, tj. prebrojavanja takvih pojavljivanja10, zato
s njima ne možemo pronaći sva pojavljivanja podniza unutar nekog teksta. Uzmimo
za primjer T = AAA. Današnji pretraživači tekstova kao što su MS Word, Notepad++
i dr. pronaći će samo jedno pojavljivanje s podnizom P = AA i to na prvom mjestu
AAA, dok će podniz AAA zanemariti.
Sa slike možemo vidjeti da se broj ovakvih podnizova naglo smanjuje s
njihovom duljinom, a nakon određene duljine ( otprilike 12 ) takvih pojavljivanja
praktički nema, dio razloga leži u tome što su testne datoteke generirane slučajnim
procesima.
10 Ove mogućnosti testirane su na danom primjeru, u nastavku. Word može pronaći ovakvo pojavljivanje, ali ne može ih izbrojati
Slika 4.3.3 Broj pojavljivanja s tekstom unutar dva bloka
38
Algoritam za pretraživanje podniza unutar dva bloka zauzima daleko najveće
vrijeme pretrage. Jedan razlog je taj što ovakvih pojavljivanja imamo najviše, a drugi
jest kompleksnost ovog dijela algoritma za pretraživanje podniza unutar dva bloka:
Podniz 𝑃[0, 𝑚 − 1] podijeliti u sve moguće parove sufiksa i prefiksa
𝑃[0, 𝑚 − 1] = 𝑃[0, 𝑖 − 1] + 𝑃[𝑖, 𝑚 − 1], 0 ≤ 𝑖 ≤ 𝑚 − 1.
Za svaki takav par 𝑃[0, 𝑖 − 1] pronađi u PS-u, a 𝑃[𝑖, 𝑚 − 1] pronađi u RPS,
ako ne postoje, ne postoji ni takvo pojavljivanje.
Za svako postojanje pojavljivanja takvog para s identifikatorima blokova obiđi
RPS, a u isto vrijeme traži par za kojeg vrijedi da je identifikator RPS-a za
jedan manji od identifikatora u PS. Ukoliko postoji takav par prijavi
pojavljivanje.
U posljednjem dijelu algoritma za pretraživanje pojavljivanja unutar dva bloka
imamo linearizaciju postupka traženja takvih parova pomoću Z – prefiksnog stabla,
upravo zato što smo takve čvorove iz RPS-a povezali s čvorovima PS-a na mjestu
gdje je identifikator PS-a za jedan veći od identifikatora RPS-a. Naime, prije nego
što sam implementirao taj dio, vrijeme ove pretrage trajalo je i do tisuću puta dulje,
sada su ta vremena svedena na vrlo kratak interval ( Slika 4.3.43.4 ). Možemo vidjeti
da ta vremena dosežu svoj maksimum za duljinu podniza 7 – 10.
Slika 4.3.4 Trajanje pretraživanja pojavljivanja podniza unutar dva bloka
39
4.3.3 Pojavljivanja podniza unutar tri ili više blokova
Ovakva vrsta pojavljivanja gotovo da i ne postoji unutar tekstova, tj. vrlo je
mala vjerojatnost da će se pronaći pojavljivanje ove vrste. Razlog tomu leži u
činjenici da LZ78 sažimanje garantira da postoji najviše jedan blok za sve
kombinacije 𝑖 i 𝑗 Najveći mogući broj pojavljivanja, ako uzmemo da je duljina
podniza m, jest m2 , s obzirom da LZ78 sažimanje podataka garantira da je svaki
blok predstavljen jedinstvenim slijedom nukleotida. Kako bi ovo pravilo bilo
omogućeno, dodan je specijalni znak $ na kraj niza, inače bismo imali problema s
identifikacijom zadnjeg bloka, koji bi mogao prebrisati neki od prethodnih blokova.
Algoritam glasi ovako:
Izgraditi matricu 𝑚𝑥𝑚 čiji su redovi zapravo liste identifikatora blokova,
matrica se gradi za sve moguće sufikse podniza P. Konkretno za blokove
radnog primjera 𝐶 = |𝐴|𝐶|𝑇|𝐺|𝐴𝐶|𝑇𝐴|𝐶𝐴|𝐶𝐴𝐶|𝑇𝐴𝐺|𝐶𝑇|𝐴𝐶𝐺|$ i na primjer
podniz 𝑃 = 𝐴𝐶𝐴𝐶𝐴 matrica se gradi ovako:
o Za svaki 𝑖 , 𝑖 < 𝑚, 𝑚 = |𝑃|:
Iz korijena pozicionirati se u čvor granom znaka 𝑃[𝑖]
Za svaki 𝑗, 𝑗 < 𝑚, 𝑚 = |𝑃|:
Na polje matrice s koordinatama (𝑖, 𝑗) upisati
identifikator čvora u koji se stiglo iz korijena za sve
čvorove do kojih se stiglo, kada se dođe do čvora iz
kojeg ne vodi grana s oznakom 𝑃[𝑗] izađi iz petlje i
povećaj 𝑖 za jedan.
Tablica 4.1 Matrica m*m
i \ j 0 1 2 3 4
0 1 5
1 2 7 8
2 1 5
3 2 7
4 1
40
Uzeti sve vrste kombinacija prefiksa, infiksa i sufiksa podniza
𝑃[0, 𝑚 − 1], vrijedi 𝑃[0, 𝑚 − 1] = 𝑃[0, 𝑖 − 1] + 𝑃[𝑖, 𝑟 − 1] + 𝑃[𝑟, 𝑚 − 1] , uz
uvjet 0 ≤ 𝑖 < 𝑟 < 𝑚.
Za svaki takav dio unutar matrice tražiti po redovima blokove. Identifikator
svakog sljedećeg bloka mora biti veći od identifikatora prethodnog bloka.
Kada više nema takvog identifikatora u sljedećem bloku, provjeriti postoji li
blok prethodnik i sljedbenik skupine blokova koji su pronađeni u matrici, a da
završavaju i počinju odgovarajućim znakovima iz podniza.
Implementacija strukture Range za svrhe ovog završnog rada nije bila
potrebna. Ta struktura bila bi bila jako velika i zauzimala bi velik prostor u radnoj
memoriji ( 𝑛𝑥𝑛 okteta ), te bi njeno pretraživanje bilo vremenski zahtjevno. Na Slici
4.3.5 mogu se vidjeti vremena pretraživanja pojavljivanja podniza unutar tri ili više
blokova.
Slika 4.3.5 Trajanje pretraživanja pojavljivanja podniza unutar dva bloka
41
5 Veličina, vrijeme izgradnje i pretraživanja LZ – indeksa
Kao što je pokazano u 4. poglavlju, strukture podataka koje koristi LZ – indeks
veoma su velike ( Slika 5.1 ), ali omogućavaju vrlo brzu pretragu podnizova.
Na Slici 5.1 vidimo da brža verzija LZ – indeksa koja je implementirana za
svrhe ovog završnog rada uzima oko 10𝑛 okteta radne memorije, dok sporija (
također za svrhe ovog završnog rada ) verzija zauzima otprilike 9𝑛 okteta. Takva
memorijska potrošnja je cijena vrlo brzog pretraživanja unutar velikih tekstova
( ≫ 10 MB ).
Slika 5.1 Memorijska potrošnja LZ - indeksa
Slika 5.2 Trajanje izgradnje LZ - indeksa
42
Izgradnja kod brže verzije indeksa za trećinu je brža nego kod originalne
Navarrove implementacije, dok to i nije baš slučaj kod verzije indeksa sa dinamičkim
poljem pokazivača ( Slika 6.2.1. ), međutim , ta verzija zauzima manje okteta u
radnoj memoriji, pri izgradnji.
Brzina kojom se pretražuje tekst iznosi od nekoliko mikrosekundi za manje
ulazne datoteke ( nekoliko MB ) do otprilike stotinjak milisekundi za velike ulazne
datoteke ( stotinjak MB ), kao što se može vidjeti na Slici 5.311.
Vremena pretraživanja u visokoj su korelaciji s veličinom datoteke, a u puno
manjoj mjeri ovise o duljini podniza koji se pretražuje. U Poglavlju 6 usporedit će se
dobivena vremena dvije implementacije LZ – indeksa za svrhe ovog završnog rada
s vremenima Navarrove implementacije.
11 Prikazane su vrijednosti za bržu implementaciju LZ – indeksa za potrebe ovog završnog rada.
Slika 5.3 Vrijeme pretraživanja podniza unutar zadanog teksta
43
6 Usporedba s originalnom implementacijom LZ – indeksa
6.1 Memorijsko zauzeće indeksa
U odvagivanju između memorijske potrošnje i brzine napravljen je indeks koji
zauzima zadovoljavajuću veličinu u radnoj memoriji, ali koji je dovoljno biti brz.
Kao što se može očekivati implementacija u kojoj je izgrađeno Z – prefiksno
stablo čiji su pokazivači na djecu implementirani u obliku dinamičkog polja
pokazivača i statičkog polja pokazivača ( dvije verzije ) zauzima više radne memorije
od Navarrove implementacije.
Razlika u potrošnji memorije između originalnog LZ – indeksa i mojih indeksa
je vidljiva, gdje treba uzeti u obzir da je originalni Navarrov indeks izveden uz pomoć
mnogih sažimanja struktura podataka, čemu onda doprinosi i činjenica da je on u
svojoj implementaciji strukture LZTrie i RevTrie gradio jednu po jednu. Na slici (
Slika 6.1.1 Potrošnja memorije različitih LZ - indeksa) prikazana je maksimalna potrošnja
memorije, a testovi su obavljeni na osobnom računalu ( Toshiba Satellite C855 –
12L: RAM 4 GB, procesor Intel B960 ( 1 jezgra ) takta 2,2GH, na OS-u Ubuntu 14.04
).
Slika 6.1.1 Potrošnja memorije različitih LZ - indeksa
44
6.2 Vrijeme izgradnje indeksa
Verzija iz ovog završnog rada, a koja zauzima manje memorije (
implementirana pomoću dinamičkog polja pokazivača na djecu ), vrlo je
konkurentna u vremenu izgradnje originalnom LZ – indeksu kojeg je implementirao
G. Navarro (Navarro, 2004). Međutim, verzija indeksa u kojem su čvorovi Z –
prefiksnog stabla implementirani kao statičko polje pokazivača na djecu, ne samo
da je konkurentna nego trajanje izgradnje ovakvog indeksa gotovo je dvostruko brža
od originalne Navarrove implementacije, kao što se može i vidjeti na donjoj slici.
Na slici 6.2.1 moje dvije implementacije LZ – indeksa u sklopu ovog završnog
rada označene su crvenom ( najsporiji ) i zelenom ( najbrži ) bojom, dok je Navarrov
indeks označen plavom bojom. Velikoj razlici u vremenu izgradnje dakako
doprinijela je brzina izgradnje Z – prefiksnog stabla, kao što se može vidjeti na Slici
6.2.2.
Slika 6.2.1 Usporedba vremena izgradnje s originalnim LZ - indeksom
45
6.3 Vremena pretraživanja podniza
Na slici 6.3.1 može se uopćiti da su vremena pretraživanja indeksa
implementiranih za potrebe ovog završnog rada sporija od originalne
implementacije LZ – indeksa12. Uzimajući u obzir vremena izgradnje bržeg indeksa
i originalnog rada, korisnik bi trebao napraviti više od 150 različitih kako bi se to
vrijeme nadoknadilo.
12 Za potrebe testiranja funkcije pretraži koristit će se genom vinske mušice ( lat. drosophila melanogaster ) koji se može pronaći na poveznici ftp://ftp.fruitfly.org/pub/download/compressed/ na_whole-genome_genomic_dmel_RELEASE3.FASTA.gz. Veličina genoma vinske mušice iznosi 133 MB ( Mjesta na kojima nije poznat nukleotid će se preskočiti )
Slika 6.3.1 Vremena pretraživanja podniza različitih LZ – indeksa
Slika 6.2.2 Vremena izgradnje prefiksnih stabala različitih LZ - indeksa
46
7 Zaključak
Samostojni indeksi su strukture podataka koje sažimaju tekst i omogućavaju
njegovo efikasno pretraživanje. Pri tome, mora se paziti na količinu radne memorije
koju oni zauzimaju i na brzinu kojom oni pretražuju velike ulazne nizove ( npr. slijed
nukleotida unutar nekog genoma ).
U ovom završnom radu prikazana je ideja implementacije samostojnog
indeksa kao što je LZ – indeks, koji je svoju popularnost stekao zahvaljujući
implementaciji znanstvenika D. Arroyuela i G. Navarra. Kao što se moglo i vidjeti,
implementacija jednog takvog indeksa veoma je složena i zahtijeva vještine
korištenja velikih struktura podataka i optimizacije u programskim jezicima C/ C++.
Vrijeme izgradnje brze verzije mog LZ – indeksa najbrže je vrijeme izgradnje
od bilo koje tri vrste originalnih implementacija prikazanih u radu G. Navarra
Implementing the LZ – index: Theory versus Practice ( Navarro, 2009). Po potrošnji
radne memorije moje dvije implementacije indeksa, nešto su slabije, ali ne i
najslabije.
U budućnosti ću nastaviti raditi na ovom indeksu i novoj strukturi podataka
koje je stvorena u svrhe ovog završnog rada. Orijentirat ću se na optimizaciju bržeg
algoritma, iako sporiji ima više potencijala za tekstove s velikim abecedama.
Poboljšanje je moguće u brzini pretraživanja i brzini izgradnje Z – prefiksnog stabla.
47
8 Literatura
[1] Arroyuelo,D. et al. (2006) Reducing the Space Requirement of LZ-Index. In,
Proceedings of the 17th Annual Conference on Combinatorial Pattern
Matching, CPM’06. Springer-Verlag, Berlin, Heidelberg, pp. 318–329.
[2] Burrows,M. et al. (1994) A block-sorting lossless data compression
algorithm.
[3] Domazet-Lošo,M. and Šikić,M. (2014) Bioinformatika skripta.
[4] Ferragina,P. and Manzini,G. (2000) Opportunistic data structures with
applications. In, 41st Annual Symposium on Foundations of Computer
Science, 2000. Proceedings., pp. 390–398.
[5] Kärkkäinen,J. and Sanders,P. (2003) Simple Linear Work Suffix Array
Construction. In, Baeten,J.C.M. et al. (eds), Automata, Languages and
Programming, Lecture Notes in Computer Science. Springer Berlin
Heidelberg, pp. 943–955.
[6] Liang,F.M. (1983) Word Hy-phen-a-tion by Com-put-er (Hyphenation,
Computer).
[7] Manber,U. and Myers,G. (1993) Suffix Arrays: A New Method for On-Line
String Searches. SIAM J. Comput., 22, 935–948.
[8] Manzini,G. (2001) An Analysis of the Burrows&Wheeler Transform. J ACM,
48, 407–430.
[9] Navarro,G. (2009) Implementing the LZ-index: Theory Versus Practice. J
Exp Algorithmics, 13, 2:1.2–2:1.49.
[10] Navarro,G. (2004) Indexing text using the Ziv–Lempel trie. J. Discrete
Algorithms, 2, 87–114.
[11] Okonechnikov,K. et al. (2012) Unipro UGENE: a unified bioinformatics
toolkit. Bioinformatics, 28, 1166–1167.
[12] Sadakane,K. (2000) Compressed Text Databases with Efficient Query
Algorithms Based on the Compressed Suffix Array. In, Goos,G. et al. (eds),
Algorithms and Computation, Lecture Notes in Computer Science. Springer
Berlin Heidelberg, pp. 410–421.
[13] Valgrind; URL: http://valgrind.org/.
48
[14] Ziv,J. and Lempel,A. (1977) A universal algorithm for sequential data
compression. IEEE Trans. Inf. Theory, 23, 337–343.
[15] Ziv,J. and Lempel,A. (1978) Compression of individual sequences via
variable-rate coding. IEEE Trans. Inf. Theory, 24, 530–536.
Završni rad:
Izrada samostojnog Lempel – Zivovog indeksa s primjenom u analizi
genoma
Sažetak
Samostojni Lempel – Zivov indeks primjenjuje se u analizi genoma za
rješavanje problema pronalaska podniza u zadanom tekstu . U tu svrhu tekst se
sažima i priprema za efikasnu obradu. Lempel – Zivov indeks u ovom radu izgrađen
je pomoću potpuno nove strukture podataka, Z – prefiksnog stabla, čija brza
izgradnja čini ovaj indeks još kvalitetnijim u smislu brzine izgradnje, odnosno, čini
ga indeksom koji se gradi brže od bilo koje originalne implementacije Lempel-
Zivovog indeksa.
Ključne riječi: LZ – indeks, kompresija, Z-prefiksno stablo, pretraživanje
Bachelor thesis:
The Lempel-Ziv self-index with an application to genome analysis
Abstract
The Lempel-Ziv self-index is often used for analysing genomes for solving
the problem of finding a pattern in a text. It uses compression in order to prepare
text for efficient processing. In this work, LZ – index was implemented by using
newly discovered data structure Z – Trie, whose construction speed makes this
index even more competitive. It is significantly faster than any original made type of
LZ– index.
Keywords: LZ – index, compression, Z – Trie, pattern matching