String Matching Algoritmiek
String Matching Gegeven string (haystack): aabaabbabaaba zoek patroon abba (needle) 4 algoritmen: Naïef Rabin-Karp Eindige Automaat Knuth-Morris-Pratt 2
String Matching (formeel) Tekst A[0 n 1], patroon P[0 m 1] Wil: k zodat A k k + m = P[0 m 1] Substring met lengte m van A die begint op positie k Tekst is over alfabet Σ ({0,1}, {A, B,, Z}, [0,255], o.i.d.) 3
Naïef NaiveMatch(A,P) for i := 0 to n-m-1 if Checkmatch(A,i,P) yield i return Bekijk alle mogelijke shifts Looptijd? CheckMatch(A,k,P) for i := 0 to m-1 if A[k+i] P[i] return false return true 4
Rabin-Karp Idee: vat strings op als getallen in base Σ hallo is 8 1 12 12 5 base 26 (= 3681813) 00101 is 00101 base 2 (= 20) Vergelijk getallen ipv. strings 5
Voorbeeld Zoek orit in algoritme orit = 15 26 3 + 18 26 2 + 9 26 1 + 20 = 276062 algo = 1 26 + 12 26 + 7 26 + 15 = 25885 lgor = 12 26 + 7 26 + 15 26 + 18 = 216052 gori= 7 26 + 15 26 + 18 26 + 9 = 133649 orit= 15 26 + 18 26 + 9 26 + 20 = 276062 6
Rabin-Karp (1) RK1(A,P) H = String2Int(P) for i := 0 to n-m-1 if String2Int(A[I i+s]) = H yield i return String2Int(A) r = h for i := 0 to n-1 h := Σ h + A[i] return h Looptijd? 7
Snel herberekenen Herberekenen kan in O 1 door te schuiven H 0 = 1 26 3 + 12 26 2 + 7 26 1 + 15 20 1 H 1 = 12 26 3 + 7 26 2 + 15 26 1 + 18 Algemeen: H i + 1 = A i + m + 1 + Σ (H i A i Σ m 1 ) Rolling Hash 8
Rabin-Karp (2) RK2(A,P) ph = String2Int(P) sh = String2Int(A[1 m]) for i := 0 to n-m-1 if ph = sh yield i sh := sh Σ + A[i+m] A[i] Σ m return Looptijd? 9
Wat schiet dit op? Hash is 32-bit integer: werkt alleen voor m 5 (26 7 > 2 32 ) Idee: bekijk getallen modulo q Je kan alle tussenresultaten mod q nemen, resultaat blijft gelijk 10
Voorbeeld 1 26 + 12 26 + 7 26 + 15 = 25885 10 (mod 23) 1 1 (mod 23) 1 26 + 12 = 38 15 (mod 23) 15 26 + 7 = 397 6 (mod 23) 6 26 + 15 = 171 10 (mod 23) Rekent nooit met getallen > q Σ 11
Rabin-Karp (3) RK3(A,P) ph = String2Int(P) % q sh = String2Int(A[0 m-1]) % q for i := 0 to n-m-1 if ph = sh yield i sh := sh Σ + A[i+m] A[i] Σ m % q return 12
Spurious Hits Zoek orit in algoritme; orit = 15 26 3 + 18 26 2 + 9 26 1 + 20 = 276062 16 mod 17 algo = 1 26 + 12 26 + 7 26 + 15 = 25885 11 mod 17 lgor = 12 26 + 7 26 + 15 26 + 18 = 216052 16 mod 17 13
Rabin-Karp (4) RK4(A,P) ph = String2Int(P) % q sh = String2Int(A[0 m-1]) % q for i := 0 to n-m-1 if ph = sh && CheckMatch(A,i,P) yield i sh := sh Σ + A[i+m] A[i] Σ m % q return 14
Looptijd O(n) voor het checken van de hash, PLUS: 1. O(m) per gevonden substring 2. O(m) per spurious hit Wat is het aantal spurious hits? 15
Gemiddelde looptijd Aaname: q vast, tekst vast, patroon random Kans dat het patroon zelfde hash heeft als een gegeven shift van de tekst is 1/q E spurious hits = E Σ i I shift i is hit = Σ i E I shift i is hit = Σ i 1/q = n/q Gemiddelde looptijd: O n + nm/q 16
Aanvallen! Er zijn superslechte invoeren te bedenken Tekst: aaaaaaaaaaaaaaa, patroon: aaaaaaxx Een aanvaller kan ons systeem platleggen met slechte invoer (DOS-aanval) Oplossing: maak q random (priem) 17
Verwachte looptijd Gemiddeld v.s. Verwacht Bekijk vaste strings en shift orit = 15 26 3 + 18 26 2 + 9 26 1 + 20 = 276062 lgor = 12 26 3 + 7 26 2 + 9 26 1 + 20 = 216052 Wanneer spurious hit? 18
Verwachte looptijd orit = 15 26 3 + 18 26 2 + 9 26 1 + 20 = 276062 lgor = 12 26 3 + 7 26 2 + 9 26 1 + 20 = 216052 H A k k + m H P mod q H A k k + m H P 0 (mod q) 276062 216052 = 60010 = 2 5 17 353 Spurious hit als q een van de priemfactoren is 19
Rabin-Karp Rolling hash met O(1) updates Uit te breiden naar 2D (en 3D, ) String matching in verwacht O n + mk + m sp. hits = O(n + mk) tijd Nog wel O m tijd per echte hit Veel hits = veel tijd 20
Matching met Eindige Automaat Eindige Automaat/Finite Automaton O(n) tijd met O m Σ preprocessing Geen kosten voor hits 21
Eindige Automaat Toestanden: Q Overgangen: δ: Q Σ Q 22
Eindige Automaat Toestanden: Q Overgangen: δ: Q Σ Q niks niks eten eten,niks eten 23
Constructie (formeel) m + 1 states: niks gematched, 1 gematched,, n gematched (alles) δ i, x = i + 1 als x = P[i] de grootste j i zodat P i j i 1 = P[0 j 2] en P j 1 = x 0 indien zo n j niet bestaat 24
Constructie (informeel) We weten dat P[0 i 1] het huidige stuk tekst matcht Toevoegen karakter x Als x = P[i] matchen we één karakter meer Anders zoeken we de langste suffix van P 0 i 1 x die ook een prefix van P is P = abbaba: als je na abbab een b ziet, is de langste suffix abbabb 25
DFA Matcher DFA-Match(A,P) s := 0 δ := overgangsfunctie van P for i := 0 to n-1 s := δ(s, A[i]) if s = m yield i-m+1 return 26
Bouwen van δ Kan in O m 3 Σ met naïef algoritme Kan ook in O m Σ Finite Automata: je kan op iedere reguliere expressie matchen O(n) tijd, O m Σ preprocessing Worst case: O m 2 preprocessing én ruimte 27
Knuth-Morris-Pratt Verbetering van Eindige Automaat Automaat: indien x een mismatch is, kijk welke suffix van P 0 i 1 x een prefix van P is KMP: kijk alleen naar P 0 i 1, niet naar x! In geval van mismatch schuift i niet verder 28
KMP Matcher KMP-Match(A,P) s := 0 π := prefixfunctie van P for i := 0 to n-1 if A[i] = P[s] s := s + 1 else if s > 0 s = π[s] i := i - 1 if s = m yield i-m+1 ; s = π[s] ; i := i - 1 return 29
Prefixfunctie π s = grootste j < s zodat P 0 j 1 = P[s j s 1] Opmerking 1: je kan deze j s enumereren while(j > 0) j = π[j] yield j Geeft alle j s die aan de eis voldoen 30
Prefixfunctie while(j > 0) j = π[j] yield j π s = grootste j < s zodat P 0 j 1 = P[s 1 j s 1] Opmerking 1: je kan deze j s enumereren Opmerking 2: splits de eis in twee delen a) P 0 j 2 = P s 2 j s 2 b) P j 1 = P[s 1] a) kun je met opmerking 1 bepalen! 31
Prefixfunctie ComputePI(s) j := ComputePI(s 1) while(j > 0 && P[j] P[s - 1]) j := ComputePI(j) if(p[j] P[s - 1]) return 0 return j + 1 Dynamisch Programmeren! 32
Prefixfunctie (iteratief) ComputePI(s) π[0] := 0 ; π[1] := 0 j := 0 for s := 2 to m 1 while(j > 0 && P[j] P[s - 1]) j = π[j] if(p[j] = P[s - 1]) j := j + 1 π[s] = j 33
Knuth-Morris-Pratt Matching in O(n) met O m preprocessing Eindige Automaat maar dan slimmer Automaat bekijkt elke letter 1 keer KMP vaker 34
Eindfeest k 18 vrienden naar feest brengen in graaf met n 5000 nodes Looptijd: 2 k poly n GEEN n k (FPT) Vrienden lopen S langzamer dan auto Ophalen op handige locaties, wachten op lopende vrienden NP-volledig 35
Eindfeest Gelaagde graaf: v, S, v V, S Vrienden Niet expliciet maken (O 2 k n geheugen met kleine constante) Doorzoeken met Dijkstra Wanneer heb je een kant, welke gewichten? Fruitmand. 36
Eindfeest Zie ook Tom s Quest uit Wybe Workshop 37