Parallelle Algoritmen String matching
1 Beter algoritme patroonanalyse Bottleneck in eenvoudig algoritme: WITNESS(j) (j = kandidaat in eerste i-blok) berekenen m.b.v. brute force algoritme –Kijkt voor elke k in 1..m-i+1 of dat een geldige WITNESS(j) kan zijn -> O(m) operaties Proberen werk te verminderen
2 Beter algoritme patroonanalyse (2) Input: een patroon P(1:m) met m = 2 s Output: de WITNESS(1:r) array met r = min(p,2 s-1 ) en p de periode van P
3 Beter algoritme patroonanalyse (3) 1.for 1 ≤ i ≤ m/2 pardo WITNESS(i) := 0 2.for i = 1 to s - 1 do 1.j := kandidaat in eerste i-blok, bereken WITNESS(j) via brute force met prefix P(1:2 i+1 ). Als WITNESS(j) != 0, ga verder zoals in vorig algoritme voor deze iteratie, anders is p := j-1 de periode van van P(1:2 i+1 ) 2.zoek grootste ≥ i + 1 zodat p een periode is van P(1:2 ). Als = log(m), p is de periode van het hele patroon -> klaar 3.gebruik lemma (zie verder) om alle WITNESS(l) met p ≤ l ≤ 2 -1 te bepalen en gebruik duels voor een aantal eliminaties bij de rest
4 Beter algoritme patroonanalyse (4) Lemma Als: –p periode van P(1:2 ) maar niet van P(1:2 +1 ) –waarden WITNESS(t) voor 2 ≤ t ≤ p beschikbaar en WITNESS(t) ≤ r < 2 Dan: Voor elke k met p < k ≤ 2 geldt: 1.als k ≠ 1 mod p en k ≤ 2 - r, dan geldt WITNESS(k) = WITNESS(k mod p) 2.als k = 1 mod p, stel dan w = kleinste index waarvoor P(w) ≠ P(p+w), dan geldt WITNESS(k) = p + w - k + 1
5 Beter algoritme patroonanalyse (5) Complexiteit: 1.WITNESS array initializeren: tijd: O(1) werk: O(m/2) = O(m) 2.WITNESS waarden berekenen: 1.WITNESS(kand. eerste i-blok) berekenen: tijd: O(1) werk: O(2 i )
6 Beter algoritme patroonanalyse (6) Complexiteit (vervolg) 2.WITNESS waarden berekenen: Als P(1:2 i+1 ) niet periodiek, duels uitvoeren: tijd: O(1) werk: O(m/2 i ) Als P(1:2 i+1 ) wel periodiek met periode p: 1.kijken tot waar periode zich uitstrekt (stel tot P(1:2 )): tijd: ( -i) * O(1) = O( -i) werk: = O(2 )
7 Beter algoritme patroonanalyse (7) Complexiteit (vervolg) 2.WITNESS waarden berekenen: 2.WITNESS(j) met 2 ≤ j ≤ 2 -1 bepalen (lemma): tijd: O(1) werk: 2 -1 * O(1) = O(2 -1 ) 3.duels uitvoeren onder overige elementen: tijd: ( -i) * O(1) = O( -i) werk: (2 -i ) * O(m/2 ) = O(m/2 i )
8 Beter algoritme patroonanalyse (8) Complexiteit (vervolg) Totaal om van iteratieTotaal: naar iteratie te gaan: –tijd: O( -i)O(log m) –werk: O(m/2 i + 2 )O(m) PRAM model: CRCW PRAM
9 Suffix bomen een digitale zoekboom T is een gewortelde boom met m bladen zodat 1.elke tak is gelabeld met een element van ∑ en is gericht weg van de wortel 2.geen twee takken hebben hetzelfde label 3.elk pad van de wortel naar een blad identificeert een Y i
10 Suffix bomen een suffix boom T X is een suffix boom geassocieerd met een string X: analoog als zoekboom, maar elke tak is gelabeld met een substring van X i.p.v. een enkel teken -> compacte versie van een zoekboom
11 Suffix bomen (2) Algoritme om suffix boom T X voor string X op te stellen (“vaag”): input: X# := string X met lengte 2 q = m en aangevuld met m-1 sentinels/terminators output: suffix boom T X 1.Maak boom T 0 = boom met wortel en m takken die de prefixen met lengte m beginnend op positie 1,.., m als label hebben
12 Suffix bomen (3) 2. for i = q-1 downto 1 do for alle toppen v van de boom T q-i pardo if (v heeft meerder takken met label met hetzelfde prefix van lengte 2 i ) then begin splits deze takken in prefix en rest merge prefixen tot 1 tak maak resten kinderen van nieuwe tak end verwijder toppen waaruit maar 1 boog vertrekt T q-i+1 := resultaat
13 Suffix bomen (4) hoe snel kijken of twee prefixen gelijk zijn? gelijke prefixen met lengte 2 i zelfde ID geven (een getal) def: Descriptor U (met U substring van X) = koppel (i,|U|), wil zeggen dat substring van X beginnend op positie i met lengte |U| gelijk is aan U alfabet ∑ hernummeren op basis van input string (via sortering en ranking)
14 Suffix bomen (5) def: Array ID[1..|X|,0..log(|X|)] –rijnummer: startpositie substring –kolomnummer: log(len(substring)) –waarde op ID[i,j] = unieke identifier (getal) voor substring U beginnend op positie i met lengte 2 j
15 Suffix bomen (6) Opstellen ID array: input: string X# met |X|= n = 2 k en laatste teken X = # (# komt nergens anders voor in X), elke X(i) is getal tussen 1 en n output: eerder beschreven ID array gebruikt hulp-array BB[1..n,1..n+1]
16 Suffix bomen (7) 1. for 1 ≤ i ≤ n pardo ID[i,0] := X(i) 2. for q = 1 to log(n) do for 1 ≤ i ≤ n pardo 1.k1 := ID[i,q-1], k2 := ID[i+2 q-1,q-1] 2.BB[k1,k2] := i 3.ID[i,q] := BB[k1,k2] Opmerking: wanneer in stap 2.1 de waarde i+2 q-1 > n, stel dan k := n+1 tijd: O(log(n))werk: O(n*log(n))
17 Suffix bomen (8) ID[i,j] = k wil zeggen dat substring met descriptor (i,2 j ) dezelfde is als die met descriptor (k,2 j ) (door constructie) structuur suffix boom: elke top v heeft 1.een array OUT v (1..n) met OUT v (j) = u voor elke top u die verbonden is met v en j het ID van het label (= een substring) horende bij de boog (v,u) 2.link naar ouder p(v) 3.descriptor van de substring horend bij link (p(v),v)
18 Suffix bomen (9) Implementatie algoritme: 1.kijken welke takken (v,u k ) van top v een label met hetzelfde prefix van lengte 2 i-1 hebben: input: OUT v (j) = u k, top u k bevat descriptor van label van boog (v,u k ) = (s k,l k ) output: j ID dat prefix van u k met lengte 2 i-1 uniek aanduidt 1.stel j ID = ID[s k,i-1] Dit moet gebeuren voor alle toppen v, dus: tijd: O(1) werk: O(n)
19 Suffix bomen (10) 2.maak nieuwe boog die ouder zal zijn van alle bogen met zelfde prefix met lengte 2 i-1 1.stel OUT v (j ID ) := u k 2.if meerdere u k ’s eenzelfde j ID hebben en elkaar dus zouden overschrijven then maak nieuwe top v’ met p(v’) = v, descriptor (j ID,2 i-1 ) stel OUT v’ (ID[s k +2 i-1,i-1]) = u k stel OUT v (j ID ) := v’ stel descriptor u k in op (s k +2 i-1,l k -2 i-1 ) Moet weer gebeuren voor alle kinderen -> tijd: O(1)werk: O(n)
20 Suffix bomen (11) 3.verwijderen toppen waaruit maar 1 boog vertrekt 1. if v na de vorige stap slechts 1 kind heeft then set w := p(v) maak nieuwe top v’ met p(v’) = w, descriptor (s v,l v +2 i-1 ) OUT w (ID[s v,i-1]) := v’ Moet gecontroleerd (en mogelijk uitgevoerd) worden voor alle v’s -> tijd: O(1)werk: O(n)
21 Suffix bomen (12) Oorspronkelijk algoritme voert vorige stappen uit in lus die log(n) maal wordt uitgevoerd. Dus : tijd: log(n) * O(1) = O(log(n)) werk: log(n) * O(n) = O(n*log(n))