11. Merkkijonot. 11. luku 560

Samankaltaiset tiedostot
Algoritmit 2. Luento 6 To Timo Männikkö

Algoritmit 2. Luento 6 Ke Timo Männikkö

Algoritmit 2. Luento 13 Ti Timo Männikkö

Hahmon etsiminen syotteesta (johdatteleva esimerkki)

Automaatit. Muodolliset kielet

Se mistä tilasta aloitetaan, merkitään tyhjästä tulevalla nuolella. Yllä olevassa esimerkissä aloitustila on A.

8. Kieliopit ja kielet

Algoritmit 2. Luento 13 Ti Timo Männikkö

Tietotekniikan valintakoe

uv n, v 1, ja uv i w A kaikilla

Datatähti 2019 loppu

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 5. marraskuuta 2015

Äärellisten automaattien ja säännöllisten kielten ekvivalenssi

Ei-yhteydettömät kielet [Sipser luku 2.3]

(0 1) 010(0 1) Koska kieli on yksinkertainen, muodostetaan sen tunnistava epädeterministinen q 0 q 1 q 2 q3

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 19. tammikuuta 2012

Algoritmit 2. Luento 12 To Timo Männikkö

TIEA241 Automaatit ja kieliopit, kevät Antti-Juhani Kaijanaho. 12. tammikuuta 2012

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 16. marraskuuta 2015

Algoritmit 1. Luento 8 Ke Timo Männikkö

Luku 8. Aluekyselyt. 8.1 Summataulukko

Hakupuut. tässä luvussa tarkastelemme puita tiedon tallennusrakenteina

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 29. toukokuuta 2013

10. Painotetut graafit

Epädeterministisen Turingin koneen N laskentaa syötteellä x on usein hyödyllistä ajatella laskentapuuna

Algoritmit 1. Luento 7 Ti Timo Männikkö

Luonnolliset vs. muodolliset kielet

Säännöllisten kielten sulkeumaominaisuudet

Algoritmit 2. Luento 2 To Timo Männikkö

M =(K, Σ, Γ,, s, F ) Σ ={a, b} Γ ={c, d} = {( (s, a, e), (s, cd) ), ( (s, e, e), (f, e) ), (f, e, d), (f, e)

Turingin koneen laajennuksia

Algoritmit 2. Luento 9 Ti Timo Männikkö

S BAB ABA A aas bba B bbs c

Algoritmit 2. Luento 2 Ke Timo Männikkö

Algoritmit 1. Luento 1 Ti Timo Männikkö

Algoritmit 2. Luento 7 Ti Timo Männikkö

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

Tehtävä 2: Loppuosataulukko

T Syksy 2002 Tietojenkäsittelyteorian perusteet Harjoitus 8 Demonstraatiotehtävien ratkaisut

Tehtävä 2: Säännölliset lausekkeet

vaihtoehtoja TIEA241 Automaatit ja kieliopit, syksy 2016 Antti-Juhani Kaijanaho 13. lokakuuta 2016 TIETOTEKNIIKAN LAITOS

Algoritmit 1. Luento 12 Ke Timo Männikkö

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 19. syyskuuta 2016

1. (a) Seuraava algoritmi tutkii, onko jokin luku taulukossa monta kertaa:

Datatähti 2019 alku. task type time limit memory limit. A Kolikot standard 1.00 s 512 MB. B Leimasin standard 1.00 s 512 MB

Automaattiteoria diskreetin signaalinkäsittelyn perusmallit ja -menetelmät ( diskreettien I/O-kuvausten yleinen teoria)

AVL-puut. eräs tapa tasapainottaa binäärihakupuu siten, että korkeus on O(log n) kun puussa on n avainta

TIEA241 Automaatit ja kieliopit, kesä Antti-Juhani Kaijanaho. 22. toukokuuta 2013

9.5. Turingin kone. Turingin koneen ohjeet. Turingin kone on järjestetty seitsikko

Algoritmit 1. Luento 9 Ti Timo Männikkö

Säännöllisen kielen tunnistavat Turingin koneet

Ongelma(t): Mikä on Turingin kone? Miten Turingin kone liittyy funktioihin ja algoritmeihin? Miten Turingin kone liittyy tietokoneisiin?

Säännölliset kielet. Sisällys. Säännölliset kielet. Säännölliset operaattorit. Säännölliset kielet

Yhteydettömän kieliopin jäsennysongelma

Jos sekaannuksen vaaraa ei ole, samastamme säännöllisen lausekkeen ja sen esittämän kielen (eli kirjoitamme R vaikka tarkoitammekin L(R)).

Chomskyn hierarkia ja yhteysherkät kieliopit

Yhteydettömät kieliopit [Sipser luku 2.1]

Ongelma(t): Miten merkkijonoja voidaan hakea tehokkaasti? Millaisia hakuongelmia liittyy bioinformatiikkaan?

Täydentäviä muistiinpanoja Turingin koneiden vaihtoehdoista

Muodolliset kieliopit

on rekursiivisesti numeroituva, mutta ei rekursiivinen.

A ja B pelaavat sarjan pelejä. Sarjan voittaja on se, joka ensin voittaa n peliä.

811120P Diskreetit rakenteet

1. Universaaleja laskennan malleja

isomeerejä yhteensä yhdeksän kappaletta.

811120P Diskreetit rakenteet

Algoritmit 1. Luento 3 Ti Timo Männikkö

Esimerkkejä polynomisista ja ei-polynomisista ongelmista

811312A Tietorakenteet ja algoritmit, , Harjoitus 7, ratkaisu

ICS-C2000 Tietojenkäsittelyteoria. Tähän mennessä: säännölliset kielet. Säännöllisten kielten pumppauslemma M :=

Laskennan teoria (kevät 2006) Harjoitus 3, ratkaisuja

Algoritmit 1. Luento 12 Ti Timo Männikkö

TIEA241 Automaatit ja kieliopit, kevät 2011 (IV) Antti-Juhani Kaijanaho. 31. maaliskuuta 2011

Algoritmit 2. Luento 14 Ke Timo Männikkö

ICS-C2000 Tietojenkäsittelyteoria

Johdatus graafiteoriaan

Algoritmit 1. Demot Timo Männikkö

5.3 Ratkeavia ongelmia

T Syksy 2006 Tietojenkäsittelyteorian perusteet T Harjoitus 7 Demonstraatiotehtävien ratkaisut

Algoritmit 1. Luento 10 Ke Timo Männikkö

Yllä osoitettiin, että säännöllisten kielten joukko on suljettu yhdisteen

Algoritmit 1. Luento 13 Ti Timo Männikkö

Algoritmit 2. Luento 4 To Timo Männikkö

Luku 7. Verkkoalgoritmit. 7.1 Määritelmiä

Algoritmi on periaatteellisella tasolla seuraava:

Tietorakenteet, laskuharjoitus 7, ratkaisuja

Laskennan mallit (syksy 2010) Harjoitus 4, ratkaisuja

IDL - proseduurit. ATK tähtitieteessä. IDL - proseduurit

Tietorakenteet ja algoritmit - syksy

ATK tähtitieteessä. Osa 3 - IDL proseduurit ja rakenteet. 18. syyskuuta 2014

Algoritmit 1. Demot Timo Männikkö

13 Lyhimmät painotetut polut

Pysähtymisongelman ratkeavuus [Sipser luku 4.2]

Pinot, jonot, yleisemmin sekvenssit: kokoelma peräkkäisiä alkioita (lineaarinen järjestys) Yleisempi tilanne: alkioiden hierarkia

Tarkennamme geneeristä painamiskorotusalgoritmia

Laskennan mallit (syksy 2009) Harjoitus 11, ratkaisuja

TIEA241 Automaatit ja kieliopit, syksy Antti-Juhani Kaijanaho. 3. joulukuuta 2015

Rekursiolause. Laskennan teorian opintopiiri. Sebastian Björkqvist. 23. helmikuuta Tiivistelmä

Output. Input Automaton

9. Matemaattisista koneista.

Transkriptio:

11. Merkkijonot Dokumenttien käsittely tietokoneissa on kasvanut valtavasti viimeisen parinkymmenen vuoden aikana. Tietokoneita käytetään dokumenttien kirjoittamiseen, muuttamiseen, etsimiseen ja siirtämiseen tietoverkoissa. Monenlainen tietojenkäsittely tietoverkoissa on lisääntynyt suorastaan räjähdysmäisesti vuosikymmenessä. Kaikessa tässä ovat tietojenkäsittelyn kannalta merkkijonot avainasemassa; merkkijonoiksi voidaan tietysti mieltää kaikki tietojenkäsittelyn tieto mentäessä aina bittijonoihin asti, mutta tässä yhteydessä tarkastellaan merkkijonoja nimenomaan jonkinlaista tekstiä, merkkejä tai symboleja, sisältävänä tietona eikä mennä alisymboliseen bittiesitykseeen. 11. luku 560

11.1. Merkkijonojen abstrakti tietotyyppi Abstraktisti ajatellen merkkijono (string) on pelkästään jono merkkejä jostakin aakkostosta (alphabet), joka on merkkien (character) joukko. Merkkijonot toteutetaan lähes tulkoon aina taulukkoina, joten yksittäinen merkki saadaan niistä vakioajassa indeksinsä mukaan taulukosta. Jokaisessa tietokoneessa on sisäänrakennettu merkkijärjestelmä, joka on tyypillisesti nykyään esim. ASCII- tai Unicode-koodi. Aakkosto voi toki olla mikä tahansa sovelluksessa määritelty; siksi tarkastellaan sitä yleisesti ja merkitään symbolilla. Olkoon P = P[0]P[1]P[2] P[m-1] m merkin merkkijono. P voisi olla esim. luonnollista kieltä, kuten kissan viikset, jonka pituus on 14 merkkiä. Se voisi olla myös CGTAATAGTTAATCCG, joka on 16 merkkiä pitkä ja olisi DNA-sekvenssi. Edellisessä tapauksessa koodi olisi esim. Unicode ja jälkimmäisessä {A, C, G, T}. 11. luku 561

Monet tyyppilliset merkkijonokäsittelyt pitävät sisällään merkkijonojen pilkkomista osiin. Näistä käytetään nimitystä osajono (substring), jolloin P:n tapauksessa osajono on muotoa P[i]P[i+1]P[i+2] P[j], kunon0 i j m-1. Merkkijono voi olla näin ollen itsensä osajono, kun i = 0 ja j = m-1. Jos tämä ääritilanne jätetään pois, kysymys on aidosta (proper) osajonosta, jolloin i > 0 tai j < m-1. Lyhennysmerkintänä eo. merkkijonosta voidaan käyttää merkintää P[i..j]. Voidaan käyttää myös tyhjää merkkijonoa (i > j edellä), jonka pituus on 0. Etuliite (prefix) on osajono P[0..i],kun0 i m-1. Loppuliite (suffix) on muotoa P[i..m-1], kun 0 i m-1. Vastakohtana merkkijonon pilkkomiselle on yhdistäminen, katenaatio (concatenation), jolloin merkkijonoista P = P[0]P[1]P[2] P[m-1] ja Q = Q[0]Q[1]Q[2] Q[m-1] yhdistetään uudeksi merkkijonoksi P + Q eli P[0]P[1]P[2] P[m-1]Q[0]Q[1]Q[2] Q[m-1] (toisinaan käytetään muitakin symboleita kuin + tai vain kirjoitetaan ne peräkkäin katenaation osoittamiseksi). 11. luku 562

Merkkijono-operaatiot jaotellaan kahteen tyyppiin, muuttaviin (mutable) ja muuttamattomiin (immutable), sen mukaan, voidaanko operaatiolla muuttaa merkkijonoa. Esim. Javassa tämä määritellään täsmällisesti luokilla String jälkimmäiselle ja StringBuffer edelliselle. Muuttamattomia operaatioita ovat mm. merkkijonon pituuden määrittäminen, katenaatio ja osajonon määrääminen. Muuttavia operaatioita ovat erilaiset päivitystoiminnat, kuten merkin lisääminen merkkijonon johonkin kohtaan, merkin vaihtaminen toiseen tai merkkijonon kääntäminen. Operaatiosta riippuen näiden suoritusajat vaihtelevat ajasta O(1) aikaan O(n), O(m) tai O(n+m), missä n ja m ovat operaatioissa esiintyvien merkkijonojen pituudet. 11. luku 563

11.2. Hahmontäsmäämisalgoritmeja Merkkijonojen klassisessa hahmontäsmäämisongelmassa (pattern matching) on merkkijono T pituudeltaan n, ja halutaan selvittää, onko P merkkijonon T osajono. Tämä käsite tarkoittaa kysymystä, onko olemassa T:n osajonoa jostakin indeksistä i alkaen, joka on merkki merkiltä sama kuin P. Laskennan tulos on ilmoitus siitä, onko näin vai ei. Jos hahmo esiintyy merkkijonossa T, annetaan alkukohta i. Olkoot P ja T aakkoston merkeistä muodostettuja. Vaikka aakkosto ymmärretään yleisenä, oletetaan sen koon olevan äärellinen ja vakio. Tarkastellaan seuraavassa suppeasti hahmontäsmäämisalgoritmeja. 11. luku 564

Raa an voiman hahmontäsmäämisalgoritmi Raa an voiman hahmontäsmäämisalgoritmi (brute-force pattern matching) on todennäköisesti ensimmäinen, joka tulisi mieleen, jos ongelmaa pitäisi lähteä ratkaisemaan uutena. Siinä tutkitaan yksinkertaisesti kaikki mahdolliset P:n sijainnit T:ssä. Algoritmi (koodi 11.1.) on yksinkertainen ja toimii jopa rajoittamattomalle aakkostolle. Esim. 11.1. Olkoot merkkijonona T teksti abacaabaccabacabaabb ja hahmona P merkkijono abacab. Kuvassa 11.1. esitetään algoritmin suoritus esimerkin tapauksessa. 11. luku 565

Algorithm BruteForceMatch(T,P): Input: merkkijonot T ja P ja näissä n ja m merkkiä Output: löydetyn osajonon ensimmäisen merkin indeksi T:ssä tai ilmoitus, ettei P:tä esiinny T:ssä for i 0 to n-m {jokaiselle mahdolliselle indeksille T:ssä} do j 0 while (j<m and T[i+j] = P[j]) do j = j+1 if j=m then return i return osajonoa P ei esiinny T:ssä Koodi 11.1. Raa an voiman hahmontäsmäämisalgoritmi. 11. luku 566

a b a c a a b a c c a b a c a b a a b b 1 2 3 4 5 6 a b a c a b 7 a b a c a b 8 9 a b a c a b 10 a b a c a b lisää 12 vertailua 23 24 25 26 27 28 täsmäys indeksillä 10 a b a c a b Kuva 11.1. Esimerkkisuoritus raa an voiman algoritmista, missä joudutaan tekemään 28 vertailua. 11. luku 567

Raa an voiman algoritmi on yksinkertaisin mahdollinen. Se käsittää kaksi sisäkkäistä silmukkaa, joilla tehtävä selvästi ratkeaa. Kyseessä on täydellinen haku merkkijonossa T. Algoritmin suorituskyky ei ole kuitenkaan hyvä, koska pahimmillaan joudutaan tekemään m vertailua sen toteamiseksi, ettei hahmo täsmää käsiteltävän osajonon kanssa. Algoritmin ulompaa silmukkaa suoritetaan enintään n - m + 1 kertaa ja sisempää enintään m kertaa. Näistä tulee menetelmän suoritusajaksi O((n-m+1)m), joka on muunnettavissa muotoon O(nm). Boyer-Moore-algoritmi Aina ei ole tarpeen käydä läpi kaikkia T:n merkkejä osajonon P löytämiseksi. Isohko osa T:n merkkien ja P:n välisistä vertailuista on mahdollista välttää käytettäessä Boyer-Moore-algoritmia (BM), josta tässä esitetään yksinkertaistettu versio. 11. luku 568

BM-algoritmi hyödyntää tietoa, että aakkoston koko eli merkkien määrä on kiinnitetty. Tämä on myös menetelmän rajoitus, kun taas raa an voiman algoritmi toimii rajoittamattomalla aakkostolla. BM-algoritmi toimii parhaiten suppealla aakkostolla. Näin se on usein hyvä sanojen etsimiseksi (luonnollisen kielen) tekstistä. Raa an voiman menettelyä tehostetaan kahdella (mahdollisesti) aikaa säästävällä heuristiikalla: Peili-heuristiikka: Vertailtaessa mahdollista P:n täsmäämistä jossakin kohtaa T:ssä vertaaminen aloitetaan P:n lopusta tämän alkuun päin edeten. 11. luku 569

Merkki-hyppy-heuristiikka: Jos vertailussa esiintyy merkin T[i]=c epätäsmääminen vertailtavan P[j] kanssa, tilanne hoidetaan seuraavasti. Jos c ei esiinny ollenkaan P:ssä, P siirretään kokonaan merkin T[i] ohi, sillä sehän ei voi täsmätä minkään P:n merkin kanssa. Muuten P:tä siirretään eteenpäin, kunnes P:n merkki c täsmää jonkin merkin T[i] kanssa. Edellinen heuristiikka on hyödyllinen, kun kohdataan P:n loppupäästä olevan merkin kohdassa epätäsmääminen, jolloin ei tarvitse verrata enää P:n alkupään merkkejä. Sen sijaan hypätään näiden merkkien yli T:ssä jälkimmäisen heuristiikan mukaisesti. Näin voidaan säästää runsaasti vertailuja. 11. luku 570

Määritellään funktio last(c). Tämä käsittää aakkoston merkin c ja määrää, kuinka kauas hahmoa P voidaan siirtää, kun löydetään tekstistä merkki c, joka ei täsmää hahmon kanssa: Jos c on mukana hahmossa P, last(c) on yhtä kuin c:n viimeisen eli oikeanpuolimmaisen esiintymän indeksi. Muuten määritellään, että last(c)=-1. Kun käytetetään merkkejä vastaavia indeksejä talletettuina taulukkoon, last-funktio on helposti toteutettavissa hakutauluna. Tämä voisi olla harjoitustehtävä. Hakutaulu on laskettavissa suoritusajassa O(m+ ) tunnettaessa P (monp:n pituus ja aakkoston merkkien määrä). 11. luku 571

Algorithm BM(T,P): Input: Teksti eli merkkijono T (n merkkiä) ja hahmo P (m merkkiä). Output: Alkuindeksi ensimmäisestä osamerkkijonosta, joka täsmää T:ssä P:n kanssa, tai ilmoitus, ettei täsmäystä esiinny. Laske funktio last. i m-1 j m-1 repeat if P[j]=T[i] then if j=0 then return i {täsmäys!} else i i-1 j j-1 Koodi 11.2. Boyer-Moore-hahmontäsmäysalgoritmin alkuosa. 11. luku 572

else i i+m-min(j,1+last(t[i])) {hyppy} j m-1 until i>n-1 return T:ssä ei ole P:n kanssa täsmäävää osamerkkijonoa. Koodi 11.2. Boyer-Moore-hahmontäsmäysalgoritmin loppuosa. Hyppyvaihetta havainnollistetaan seuraavalla kuvalla. 11. luku 573

(a) a i a b l j m-(1+l) a b 1+l (b) a i b a j l m-j b a j Kuva 11.2. Hypyn esitys Koodin 11.2. mukaan, kun l=last(t[i]). Erotetaan kaksi tapausta: (a) 1+l j, jossa siirretään hahmoa j-l yksikköä, ja (b) j<1+l, jossa siirretään hahmoa yhdellä yksiköllä kuvan tilanteessa. 11. luku 574

a b a c a a b a d c a b a c a b a a b b a b a c a 1 b 4 3 2 a b a c a b 5 a b a c a b a b a c a 6 b 13 12 11 10 9 8 a b a c a b 7 a b a c a b ch a b c d last(ch) 4 5 3-1 Kuva 11.3. Tämä vastaa Kuvan 11.1. tilannetta yhden merkin erolla, jossa on merkki d yhden c:n esiintymän sijasta. BM-algoritmi suorittaa 13 merkkivertailua. 11. luku 575

BM-algoritmin pahimman tapauksen suoritusaika on O(nm+ ). Tällöin O(m+ ) on last-funktion laskenta-aika ja hahmon etsintä vie enimmillään O(nm), saman kuin raa an voiman algoritmi. Pahin tapaus esiintyy esim. seuraavassa tilanteessa: n T = aaaaaa.a m-1 P = baa a Tällainen on kuitenkin sangen harvinainen tilanne, erityisesti luonnollisen kielen tekstissä seuraavan kuvan tapaan. 11. luku 576

a p a t t e r n m a t c h i n g a l g o r i t h m 1 3 5 11 10 9 8 7 r i t h m r i t h m r i t h m r i t h m 2 4 6 r i t h m r i t h m r i t h m Kuva 11.4. Haettaessa hahmoa luonnollisen kielen tekstistä keskimääräinen vertailujen määrä on yleensä melko pieni. Kokeellisten testien mukaan englanninkielisestä se on keskimäärin 0.24 vertailua merkkiä kohti viisimerkkisellä hahmolla. 11. luku 577

Knuth-Morris-Pratt-algoritmi Raa an voiman algoritmissa oli muuan heikkous. Kun esimerkissä 11.1. havaittiin jossakin kohtaa, ettei osajono täsmää hahmon kanssa, hylättiin kaikki siltä kohtaa kerätty informaatio (osittainen täsmäys tavallaan) ja aloitettiin vertaaminen uudestaan yhden indeksin verran eteenpäin liikkuen. Tätä menettelyä on mahdollista tehostaa, kun hyödynnetään vertailujen tuottamaa informaatiota. 11. luku 578

Knuth-Morris-Pratt-agoritmissa (KMP) esikäsitellään hahmoa P niin, että voidaan hyödyntää mahdollisimman laajasti aiemmin suoritettuja vertailuja. Muodostetaan epäonnistumisfunktio (failure function) f, joka osoittaa P:n sopivan siirron hyödyntäen aiempia vertailuja. Epäonnistumisfunktio määritellään P:n pisimpänä etuliitteenä, joka on osajonon P[1..j] loppuliite (ei siis P[0..j]). Myöhemmin esitetään, miten f lasketaan. Epäonnistumisfunktio koodaa toistetut osajonot hahmon sisällä. Tätä tietoa käytetään tarpeettomien vertailujen välttämiseksi. Hypätään niiden yli, koska tiedetään tällöin osajonon alkupään täsmäävän, kun oli löydetty sille täsmäävää toistoa (hahmon mitan sisältä) myöhemmin merkkijonosta. Esim. 11.2. Tarkastellaan hahmoa P = abacab esimerkistä 11.1. KMPalgoritmin epäonnistumisfunktio f(j) on (toistoina kahdesti a ja kerran ab): j 0 1 2 3 4 5 P[j] a b a c a b 11. luku 579 f(j) 0 0 1 0 1 2

KMP-algoritmi (koodi 11.2.) käy peräkkäin merkkijonoa T läpi verraten sitä hahmon P kanssa. Löydettäessä täsmäävät merkit lisätään molempien indeksien arvoja yhdellä. Jos vastinmerkit T:stä ja P:stä eivät täsmää ja edellisessä merkkien vertailussa oli täsmäys, katsotaan epäonnistumisfunktiosta uusi indeksi P:ssä, mistä pitää jatkaa vertailua. Muuten (oli epätäsmäys ja käsittely on hahmon alussa) lisätään yksinkertaisesti T:n indeksiä (P:n indeksi pysyy muuttumattomana eli hahmon alussa). Tätä toistetaan, kunnes täsmäys tapahtuu tai saavutetaan merkkijonon T loppu. Kuvassa 11.2. on esitetty esimerkki KMP-algoritmin toiminnasta. Huomataan sen tekevän vähemmän vertailuja kuin raa an voiman algoritmi. 11. luku 580

Algorithm KMPMatch(T,P): Input: merkkijonot T ja P, joiden pituudet ovat n ja m Output: löydetyn osajonon alkukohdan indeksi T:stä tai ilmoitus, ettei hahmoa löydetty f KMPfailureFunction(P) {muodostetaan epäonnistumisfunktio f} i 0 j 0 while i < n do if P[j] = T[i] then if j = m - 1 then return i - m + 1 {täsmäys tapahtui} i i + 1 j j + 1 Koodi 11.3. (alku) Knuth-Morris-Pratt-algoritmi. 11. luku 581

else if j > 0 {liittyy ens. if:iin; ei täsmäystä, mutta on edetty P:ssä} then j f(j -1) {muutetaan indeksiä epäonnistumisfunktion mukaan} else i i + 1 return osajonoa P ei ole merkkijonossa T Koodi 11.3. (loppu) Knuth-Morris-Pratt-algoritmi. KMP-algoritmin pääosa on while-silmukka, joka suorittaa T:n ja P:n merkkien vertailun. Tämän tuloksesta riippuen algoritmi joko siirtyy niiden seuraaviin merkkeihin, käyttää epäonnistumisfunktiota uutta merkkiehdokasta varten P:stä tai aloittaa uudestaan seuraavasta merkistä T:ssä. Tarpeettomat vertailut ohitetaan käsittelyssä, sillä epäonnistumisfunktio takaa niiden olevan redundantteja. 11. luku 582

a b a c a a b a c c a b a c a b a a b b 1 2 3 4 5 6 a b a c a b 7 a b a c a b 8 9 10 11 12 a b a c a b vertailu ei tässä ole tarpeen 13 a b a c a b 14 15 16 17 18 19 a b a c a b Kuva 11.5. Esimerkkisuoritus KMP-algoritmista, missä selvitään 19 vertailulla, kun apuna on esimerkin 11.2. epäonnistumisfunktio f. 11. luku 583

Yksityiskohtiin kajoamatta ja epäonnistumisfunktion muodostamista huomioon ottamatta todetaan KMP-algoritmin suoritusajan muilta osin olevan luokkaa O(n). Epäonnistumisfunktio muodostetaan vyörytysmenetelmällä (boot-strapping), joka muistuttaa itse KMP-algoritmia. Verrataan hahmoa itseensä. Joka kerta, kun on täsmäävät merkit (saman merkin kaksi eri esiintymää hahmossa), asetetaan f(i) =j+ 1. Koska on i > j koko algoritmin suorituksen ajan, f(j-1) on aina määritelty sitä tarvittaessa. Epäonnistumisfunktion laskenta on suoritusajaltaan O(m) eli luonnollisesti hahmon pituudesta riippuva. Täten KMP-algoritmin suoritusaika on kokonaisuudessaan O(n+m). 11. luku 584

Algorithm KMPFailureFunction(P): Input: merkkijono P (hahmo) m merkkeineen Output: merkkijonon P epäonnistumisfunktio f, joka kuvaa j:n P:n pisimmän etuliitteen pituudeksi, kun etuliite on P[1..j]:n loppuliite i 1 j 0 f(0) 0 while i m - 1 do if P[j] = P[i] then {on täsmätty j + 1 merkkiä} f(i) j + 1 i i + 1 j j + 1 Koodi 11.4. (alku) KMP-algoritmin epäonnistumisfunktion laskeminen. Algoritmi hyödyntää funktion edeltäviä arvoja uusia laskiessaan. 11. luku 585

else if j > 0 then {j indeksoi P:n etuliitteen jälkeen, jota on täsmättävä} j f(j-1) else {täsmäystä ei tässä ole} f(i) 0 i i + 1 Koodi 11.4. (loppu) KMP-algoritmin epäonnistumisfunktion laskeminen. Algoritmi hyödyntää funktion edeltäviä arvoja uusia laskiessaan. Voisi kuvitella, että merkkijonon T jokainen merkki on pakko käydä läpi vertailuissa. Näin ei kuitenkaan aina ole, vaan siitä voidaan usein hypätä yli osia. Tällainen on Boyer-Moore-algoritmi edeltä. 11. luku 586

11.3. Trie Nimi trie tulee sanasta retrieval, sillä rakenne on tärkeä tiedonhaussa (information retrieval). Kyseessä on puu, jonka solmut sisältävät merkkitietoa. Pääasialliset kyselyoperaatiot, joita trielle sovelletaan, ovat hahmon täsmääminen ja etuliitteen täsmääminen. Jälkimmäinen tarkoittaa merkkijonon X etsimistä joukon S merkkijonoista näiden alkuosana. Tarkastellaan ainoastaan standardi-trietä, joka on lähtökohta useimmiten käytännössä sovellettaville monimutkaisemmille, mutta tehokkaammin merkkejä tallettaville trie-rakenteille. 11. luku 587

Olkoon S aakkoston merkkijonojen joukko. Älköön lisäksi mikään merkkijono näistä ole jonkin toisen etuliite (prefix). Standardi-trie on tällöin puu T, jolla on ominaisuudet: Juurta lukuun ottamatta jokainen T:n solmu merkitään aakkoston merkillä. Sisäsolmun lapsisolmut järjestetään aakkostossa määritellyllä järjestyksellä. Puun T jokaiseen lehteen v liittyy S:n merkkijono. Polku juuresta lehteen v määrittää tähän liittyvän merkkijonon. Kun edellytettiin, ettei mikään S:n merkkijono ole toisen etuliite, jokainen S:n merkkijono liittyy yksikäsitteisesti T:n lehteen. Tarvittaessa tämä voidaan varmistaa liittämällä erikoismerkki, joka ei kuulu joukkoon. 11. luku 588

Trien sisäsolmulla voi olla mikä tahansa määrä lapsisolmuja väliltä 1 ja d, kun d on aakkoston koko. Ehtona on, että solmussa esiintyvä merkki on myös jossakin S:n merkkijonossa niin monentena, kuin se on myös kyseisellä polulla juuresta lehteen. Tällöin polku juuresta sisäsolmun v syvyydellä i vastaa S:n merkkijonon Xi-merkkistä etuliitettä X[0..i-1]. Jokaista merkkiä c kohti, joka voi seurata etuliitettä X[0..i-1] jossakin S:n merkkijonossa, on olemassa c:llä merkitty v:n lapsi. Kuvan 13.6 mukaisesti sisäsolmulla voi olla vain yksi lapsi, mutta enimmillään d lasta. Täten trie on monitiehakupuu. Kuvan 13.6. puussa on useita yksilapsisia solmuja. Näitä perättäisiä yksisolmuisia voitaisiin yhdistää merkitsemällä solmuun useita merkkejä. Näin saataisiin tiivistetty trie, joka on tehokkaampi kuin standardi-trie. Tiivistettyä muotoa ei kuitenkaan tässä esitetä. 11. luku 589

b s e i u e t a l d l y l o r l l l c p Kuva 11.6. Merkkijonojen {bear, bell, bid, bull, buy, sell, stock, stop} standardi-trie. k 11. luku 590

Standardi-triellä, jossa on d merkin aakkostosta kokoelman S s merkkijonoa kokonaispituudeltaan n, on ominaisuudet: T:n jokaisella sisäsolmulla on enintään d lasta. T:llä on s lehteä. T:n korkeus on yhtä kuin S:n pisimmän merkkijonon pituus T:n solmujen lukumäärä on O(n). Solmujen suhteen pahin tapaus esiintyy, kun ei millään kahdella merkkijonolla ole yhteistä (ei-tyhjää) etuliitettä, ts. jokaisella sisäsolmulla on ainoastaan yksi lapsi. 11. luku 591

Trietä voidaan käyttää sanakirjan toteutukseen avainten ollessa S:n merkkijonot. Haettaessa merkkijonoa X triestä T lähdetään juuresta ja edetään alas merkkien viitoittamaa polkua. Jos tällainen polku on olemassa triessä ja päädytään lopulta lehteen, X on sanakirjassa. Jos tällaista kokonaista polkua ei ole koko merkkijonolle eli se loppuu kesken merkkijonoa tultaessa (ennenaikaisesti) lehteen tai polun päättyessä sisäsolmuun, kyseinen merkkijono ei ole sanakirjassa. Esim. bull päättyy lehteen, joten se on Kuvan 11.6. trien sana. Sen sijaan be, bee, bet, between, big tai buoy eivät ole tässä triessä. Merkkijonon haku triestä vaatii aikakompleksisuuden O(dm), jossa m on merkkijonon pituus, sillä enintään d merkin vertaamista tarvitaan kussakin solmussa. Joillekin aakkostoille vertaamisten määrää voidaan pudottaa arvoon O(log d) tai jopa O(1) käyttämällä merkkien talletukseen hajautustaulua. Kun yleensä d voidaan ajatella vakiona, voidaan pitäytyä ajatukseen, että kussakin solmussa tarvitaan aikaa O(d). 11. luku 592

Trie sopii erityisen hyvin sanojen täsmäämiseen, jossa selvitetään, vastaako annettu hahmo täsmällisesti jotakin tekstin sanaa. Tämä on rajoitetumpi tilanne kuin tavallinen hahmon täsmääminen, koska hahmo ei voi olla mielivaltaisesti yhdistetty merkkijono, vaan jokin tekstin sana tekstin ollessa esim. luonnollista kieltä. Yleisesti oli aikavaatimus O(dm) haettaessa sana triestä. Kun sana on esim. luonnollista kieltä tai DNAmerkkijono, joiden aakkoston koko on kiinnitetty eli vakio, kysely vaatii vain O(m). Kuvassa 11.7. on esimerkki. Tehtäessä trie kukin S:n merkkijono lisätään kerrallaan. Mikään niistä ei ole toisten etuliite. Lisättäessä X triehen jäljitetään sitä vastaavaa polkua. Jäljitys päättyy sisäsolmuun v, joka on ennen merkkijonon X viimeistä merkkiä ja jonka mikään lapsi ei täsmää uuden merkkijonon seuraavan merkin kanssa. Luodaan tällöin uusi haara vastaamaan merkkijonon loppuja merkkejä. Yhden merkkijonon lisäys vaati ajan O(dm) ja S:n koko trien muodostaminen ajan O(dn), jossa n on S:n merkkijonojen kokonaispituus. 11. luku 593

s e e a b e a r? s e l l s t o c k! 0 4 6 12 17 23 s e e a b u l l? b u y s t o c k! 24 28 30 36 40 46 b i d s t o c k! b i d s t o c k! 47 51 58 62 68 h e a r t h e b e l l? s t o p! 69 74 78 84 88 (a) Kuva 11.7. Standardi-trien sanan täsmääminen ja etuliitteen täsmääminen: (a) käsiteltävä teksti. 11. luku 594

b h s e i u e e t a l d l r l 6 78 47, 58 l 30 y 36 (b) 51, 62 Kuva 11.7. (jatkoa) (b) Trie muodostettu (poistosanat, kuten artikkelit a ja the on suljettu pois epäsemanttisina ), kun lehtiin on lisätty sanojen alkukohtien indeksit. a r 69 e 0, 24 11. luku 595 l l 12 c k o 17, 40 p 84

11.4. Hahmontäsmäys säännöllisten ilmauksien avulla Edellä esitetyt hahmontäsmäysalgoritmit olivat kaikki tarkoitetut ratkaisemaan ongelmia, joissa etsitään tekstistä määrättyä osajonoa, hahmoa. Monesti on tarvetta merkkijonojen etsimiseen, missä halutaan yleistä muotoa olevia hahmoja, ei ainoastaan yhtä määrättyä. Säännölliset ilmaukset (regular expressions) kuvaavat tällaisia yleisiä hahmoja. Säännölliset ilmaukset Säännölliset ilmaukset ovat yksinkertaisia, mutta tehokkaita käsitteitä kuvattaessa merkkijonojen mahdollisesti äärettömiä joukkoja, joita kutsutaan myös formaaleiksi kieliksi (formal language) yli annetun aakkoston. Säännöllisiä perusilmauksia määritellään kahdella säännöllä: 11. luku 596

1. Tyhjä on säännöllinen ilmaus, joka viittaa joukkon { }. Tämä sisältää ainoastaan tyhjän merkkijonon, jonka pituus on nolla. 2. Jokaisella symbolilla a joukosta on säännöllinen ilmaus, joka on joukko {a}. Seuraavilla kolmella säännöllä yhdistetään edeltävien perussääntöjen antamia ilmauksia uusien säännöllisten ilmausten luomiseksi: 1. Jos ja ovat säännöllisiä ilmauksia kuvaten joukot A ja B, ( + ) on säännöllinen ilmaus määrittäen joukon A B. 2. Jos ja ovat säännöllisiä ilmauksia kuvaten joukot A ja B, ( ) on säännöllinen ilmaus määrittäen kaikkien sellaisten merkkijonojen joukon, missä merkkijonot on muodostettu ottamalla merkkijono joukosta A ja katenoimalla se merkkijonoon joukosta B. 11. luku 597

3. Jos on säännöllinen ilmaus kuvaten joukon A, niin ( *) on säännöllinen ilmaus, joka kuvaa kaikkien sellaisten merkkijonojen joukon, jossa merkkijonot on muodostettu katenoimalla i merkkijonoa joukosta A (toistot sallimalla), kun i 0 (tapaus i = 0 tarkoittaa tyhjää merkkijonoa ). Tämä operaatio on joukon A Kleenen sulkeuma (Kleene closure). Kun halutaan käyttää tätä ilman tyhjää merkkijonoa, merkitään ( + ), missä on siis i 1. Aritmeettisten lausekkeiden tavoin säännöllisille ilmauksille voidaan määritellä presedenssi, jolloin sulkeet ovat poistettavissa, jos ne noudattavat presedenssiä. Kleenen sulkeumalla on suurin presedenssi. Sitä seuraa katenaatio, ja lopuksi operaatiolla + on matalin. Täten ilmaus ((ab) +(b*)) on sama kuin ab + b* ja ilmaus (((ab) +b)*) sama kuin(ab + b)*. 11. luku 598

Esim. 11. 3. Säännölliset ilmaukset kykenevät esittämään yksinkertaisesti merkkijonojen joukkoja oheisten esimerkkien tapaan aakkoston ollessa {a, b}. 1. ab + b on joukon {ab, b} säännöllinen ilmaus. 2.(ab + ba)ba on joukon {abba, baba} säännöllinen ilmaus. 3. a* on joukon {, a, aa, aaa, aaaa, } säännöllinen ilmaus. 4.(a+b)* on aakkoston ={a,b} kaikkien merkkijonojen joukko. 5. a + b + on kaikkien sellaisten merkkijonojen joukon säännöllinen ilmaus, josssa katenaatiolla on yhdistetty merkkien a ja b muodostamat merkkijonot. 11. luku 599

6. b*(ab*a)*b* on kaikkien sellaisten merkkijonojen joukon säännöllinen ilmaus, jossa merkkejä a on parillinen määrä tai ei yhtään. Säännölliset ilmaukset ja äärelliset automaatit Halutaan määrätä, onko jokin merkkijono x säännöllisen ilmauksen kuvaamassa merkkijonojen joukossa. Jotta säännöllinen ilmaus voitaisiin esittää tehokkaalla tavalla, siitä muodostetaan abstrakti kone, jolla on helppo suorittaa merkkijonojen käsittelyä ja vastata alussa esitettyyn tehtävään. Muodostetaan äärellinen tila-automaatti eli lyhyemmin äärellinen automaatti (finite state automaton, FSA). Se on eräänlainen yksinkertainen laskentamalli säännöllisten formaalien kielten merkkijonojen täsmäämiseksi. 11. luku 600

Säännöllisen kielen (regular language) sanat vastaavat säännöllisten ilmauksien merkkijonoja. Äärellinen automaatti sisältää viisi osaa: 1. Tilojen (states) äärellinen joukko S (tilat numeroidaan luvusta 1 lukuun k). 2. Aakkosto. Tämä määrittelee merkit, joilla merkkijonot muodostetaan. 3. Alkutila (starting, initial state) q 1 S, joka määrittelee äärellisen automaatin alkukonfiguraation. 4. Lopputila (final state) q f S, joka on hyväksyvä konfiguraatio, kun äärellinen automaatti on tunnistanut merkkijonon täsmäävän määritellyn hahmon kanssa. 11. luku 601

5. Transitiofunktio (transition function), joka määrittelee äärellisen automaatin tilat. Näihin tiloihin siirrytään nykyisestä tilasta riippuen seuraavasta merkistä merkkijonossa. Seuraava merkki voi olla myös tyhjä. Transitiofunktio kuvaa parin (q,a), jossa q S on tila ja a { }, joukon S osajoukkoon. Tämä sisältää muut mahdolliset tilat, joihin voidaan siirtyä oltaessa tilassa q ja luettaessa a seuraavana merkkinä merkkijonosta (jos on a =, voidaan siirtyä johonkin mahdolliseen tilaan lukematta yhtään merkkiä tekstistä). Äärellinen automaatti esitetään suunnattuna graafina, jonka solmut ovat tiloja ja joukon { } symbolein eli merkein leimatut eli merkityt kaaret ovat transitioita. Jos on siis (q,a) = r, niin graafissa on suunnattu kaari tilasta q tilaan r (jokaiselle r S) ja kaari on merkitty merkillä a. Äärellinen automaatti hyväksyy (accepts) merkkijonon x, jos automaatti alkutilasta lähdettyään päätyy lopputilaan samalla, kun merkkijono x on prosessoitu merkeittäin vasemmalta oikealle siirtyen kulloinkin merkin määräämään tilaan prosessin aikana. 11. luku 602

Tilasiirtymät on tällöin tehty transitiofunktion mukaan ja myös -transitio on sallittu. Niinpä äärellinen automaatti hyväksyy merkkijonon x, jos automaatin graafista saadaan suunnattu polku alkusolmusta loppusolmuun prosessoitaessa x alusta loppuun. Tällöin x saadaan katenoimalla polun kaarien merkit. Kuvattu äärellisen automaatin toimintapa on epädeterministinen (nondeterministic), koska on useita laillisia polkuja, joita automaatti voi valita annetulle merkkijonolle x. Kun prosessi voi seurata vain määriteltyjä transitioita, epädeterministinen hyväksymissääntö merkitsee myös, että jos jokin polku johtaa tilaan q, josta ei ole määritelty transitiota merkkijonon x seuraavalle merkille, niin polku päätetään kesken - se ei voi johtaa lopputilaan. Jos ei ole laillista polkua lopputilaan (niitä voi olla useita), merkkijonoa x ei ole hyväksytty. Kuvassa 11.8. on muutamia esimerkkejä äärellisistä automaateista. 11. luku 603

0 a a 1 b (a) b a b a 0 1 2 3 (b) Kuva 11.8. Esimerkkejä äärellisistä automaateista: (a) hyväksyy merkkijonot, joissa on parillinen määrä (tai ei yhtään) merkkejä a ja (b) hyväksyy merkkijonon aba. Lopputila on merkitty kaksoisympyränä. 11. luku 604

1 a 2 3 b 4 5 a b 6 a, b (c) Kuva 11.8. (loppu) Esimerkkejä äärellisistä automaateista: (c) hyväksyy merkkijonot, jotka sisältävät osanaan merkkijonon aa tai bb. 11. luku 605

Säännöllisiä ilmauksia äärellisinä automaatteina toteutettuina käytetään tunnistamaan eli hyväksymään säännöllisiä (formaaleja) kieliä. Automaatille, joka toteuttaa säännöllisen ilmauksen ohella tätä vastaavaa säännöllistä (formaalista) kielioppia, syötetään merkkijono. Jos merkkijono on säännöllisen ilmauksen mukainen eli samalla säännöllisen kieliopin generoiman kielen sana (tai lause), automaatti hyväksyy merkkijonon. Tarkemmitta perusteluitta mainitaan lopuksi seuraavat lauseet. Lause 11.1. Olkoot säännöllisen ilmauksen pituus m merkkiä ja merkkijonon x pituus n merkkiä. Se, onko x säännöllisen ilmauksen määrittämän säännöllisen kielen mukainen, on laskettavissa ajassa O(nm). Lause 11.2. Olkoot merkkijono (teksti) Tnmerkkiä pitkä ja säännöllinen ilmaus m merkkiä pitkä. Säännöllisen ilmauksen määrittämän kielen mukainen osajono löydetään tai todetaan, ettei sellaista ole, ajassa O(nm). 11. luku 606