Parallelle Algoritmen
String matching
2
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
3
Beter algoritme patroonanalyse (2)
• Input: een patroon P(1:m) met m = 2s
• Output: de WITNESS(1:r) array met r = min(p,2s-1) en p de periode van P
4
Beter algoritme patroonanalyse (3)1. for 1 ≤ i ≤ m/2 pardo
WITNESS(i) := 0
2. for i = 1 to s - 1 do1. j := kandidaat in eerste i-blok, bereken WITNESS(j) via
brute force met prefix P(1:2i+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:2i+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
5
Beter algoritme patroonanalyse (4)• LemmaAls:
– 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
6
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(2i)
7
Beter algoritme patroonanalyse (6)Complexiteit (vervolg)
2. WITNESS waarden berekenen:• Als P(1:2i+1) niet periodiek, duels uitvoeren:
• tijd: O(1)
• werk: O(m/2i)
• Als P(1:2i+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)
€
2r
r= i
α +1
∑
8
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/2i)
9
Beter algoritme patroonanalyse (8)
Complexiteit (vervolg)
Totaal om van iteratie Totaal:
naar iteratie te gaan:– tijd: O(-i) O(log m)– werk: O(m/2i + 2) O(m)
PRAM model: CRCW PRAM
10
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 Yi
11
Suffix bomen
• een suffix boom TX 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
12
Suffix bomen (2)
• Algoritme om suffix boom TX voor string X op te stellen (“vaag”):
• input: X# := string X met lengte 2q = m en aangevuld met m-1 sentinels/terminators
• output: suffix boom TX
1. Maak boom T0 = boom met wortel en m takken die de prefixen met lengte m beginnend op positie 1, .., m als label hebben
13
Suffix bomen (3)2. for i = q-1 downto 1 do
for alle toppen v van de boom Tq-i pardoif (v heeft meerder takken met label met
hetzelfde prefix van lengte 2i) then
beginsplits deze takken in
prefixen rest
merge prefixen tot 1 takmaak resten kinderen
van nieuwe takend
verwijder toppen waaruit maar 1 boog vertrekt
Tq-i+1 := resultaat
14
Suffix bomen (4)
• hoe snel kijken of twee prefixen gelijk zijn?• gelijke prefixen met lengte 2i 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)
15
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 2j
16
Suffix bomen (6)
Opstellen ID array:
• input: string X# met |X|= n = 2k 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]
17
Suffix bomen (7)
1. for 1 ≤ i ≤ n pardoID[i,0] := X(i)
2. for q = 1 to log(n) dofor 1 ≤ i ≤ n pardo
1. k1 := ID[i,q-1], k2 := ID[i+2q-1,q-1]
2. BB[k1,k2] := i
3. ID[i,q] := BB[k1,k2]
Opmerking: wanneer in stap 2.1 de waarde i+2q-1 > n, stel dan k := n+1
• tijd: O(log(n)) werk: O(n*log(n))
18
Suffix bomen (8)• ID[i,j] = k wil zeggen dat substring met
descriptor (i,2j) dezelfde is als die met descriptor (k,2j) (door constructie)
• structuur suffix boom: elke top v heeft1. een array OUTv(1..n) met OUTv(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)
19
Suffix bomen (9)
Implementatie algoritme:
1. kijken welke takken (v,uk) van top v een label met hetzelfde prefix van lengte 2i-1 hebben:
• input: OUTv(j) = uk, top uk bevat descriptor van label van boog (v,uk) = (sk,lk)
• output: jID dat prefix van uk met lengte 2i-1 uniek aanduidt1. stel jID = ID[sk,i-1]
Dit moet gebeuren voor alle toppen v, dus:• tijd: O(1)• werk: O(n)
20
Suffix bomen (10)
2. maak nieuwe boog die ouder zal zijn van alle bogen met zelfde prefix met lengte 2i-1
1. stel OUTv(jID) := uk
2. if meerdere uk’s eenzelfde jID hebben en elkaar dus zouden overschrijven then
maak nieuwe top v’ met p(v’) = v,
descriptor (jID,2i-1)
stel OUTv’(ID[sk+2i-1,i-1]) = uk
stel OUTv(jID) := v’
stel descriptor uk in op (sk+2i-1,lk-2i-1)Moet weer gebeuren voor alle kinderen ->• tijd: O(1) werk: O(n)
21
Suffix bomen (11)
3. verwijderen toppen waaruit maar 1 boog vertrekt1. if v na de vorige stap slechts 1 kind heeft then
set w := p(v)
maak nieuwe top v’ met p(v’) = w,
descriptor (sv,lv+2i-1)
OUTw(ID[sv,i-1]) := v’
Moet gecontroleerd (en mogelijk uitgevoerd) worden voor alle v’s ->
• tijd: O(1) werk: O(n)
22
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))