The Knuth-Morris-Pratt Algorithm Università Ca’ Foscari di Venezia Dipartimento di Informatica Corso di Laboratorio di Linguaggi docente: Cocco Nicoletta Cappellazzo Pietro – 809652 – Rizzato Andrea – 809392 –
Introduzione al problema “Ricerca esatta” Dato un testo T (T[1…n]) di lunghezza n e un pattern P (P[1…m]) lungo m, determinare se e dove il pattern occorre nel testo 1 2 3 4 5 6 7 8 9 10 11 12 13 a b c T s = 3 P a b Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Campi applicativi Potenziamento di applicazioni informatiche Comando “trova”, “trova e sostituisci” negli editor di testo, browser Web, … Comandi di sistema (es: grep, egrep, fgrep, … in ambiente Unix) Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Campi applicativi Problemi legati alla bioinformatica ricostruzione delle serie lunghe di DNA dai suoi frammenti (fragment assembly); confronto di due o più stringhe di DNA per somiglianza; ricerca di modelli nuovi o mal definiti che occorrono frequentemente in DNA; ricerca dei modelli strutturali in DNA e proteina; Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Knuth-Morris-Pratt: Intuizione Idea di base: Per avere un algoritmo di ricerca più efficiente occorre separare il procedimento di ricerca in due fasi: Preprocessing: elaborazione preliminare del pattern dalla quale si ricavano informazioni che verranno utilizzate nella seconda fase Scanning: scansione veloce del testo Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Knuth-Morris-Pratt: Intuizione G A C s A G C T P q P è allineato con T, in modo tale che P[1…q] = T[s+1…s+q] La conoscenza di questi q caratteri consente di determinare immediatamente che certi spostamenti (s+1 e s+2) non sono validi Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
La funzione prefisso Dato un pattern P[1..m], la funzione prefisso per il pattern P è la funzione p:{1,..,m} →{0,..,m-1} t.c. p[i]= max{k:k<q &PK PQ} P: PQ: PK: p[q] è la lunghezza del prefisso più lungo di P che è anche un suffisso di PQ A G C T A G C i 1 2 3 4 5 6 7 P[i] A G C T p[i] A G C Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
La funzione prefisso pseudocodice Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso Compute-Prefix-Function(P) Pattern P: m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a Variabili: m = 4 π[1] = 0 k = 0 q = 2 Funzione Prefisso π 1 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso k+1 = 1 Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a ? = b a q = 2 Variabili: k = 0+1 = 1 q = 2 Funzione Prefisso π 1 2 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso k+1 = 2 Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a ? = b a q = 3 Variabili: k = 1+1 = 2 q = 3 Funzione Prefisso π 1 2 3 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso k+1 = 3 Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a ? = b a q = 4 P[3] ≠P[4] → Entro nel while Funzione Prefisso π 1 2 3 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso k+1 = 2 Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a ? = b a q = 4 Percorro il pattern all’indietro fino a trovare il primo spostamento valido Funzione Prefisso π 1 2 3 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Esempio di calcolo della funzione prefisso k+1 = 1 Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π b a ? = b a q = 4 Sono tornato all’inizio: l’unico spostamento valido è 0 Funzione Prefisso π 1 2 3 4 i π[i] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Analisi del tempo computazionale Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π O(m) } O(1) Il costo del ciclo for (linea 4) è O(m) Il valore della funzione potenziale dipende da k La linea 6 decrementa il valore di k perché π[k]<k La linea 8 incrementa il di k al più di 1 Il costo ammortizzato delle linee 5-9 è quindi 1 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Analisi del codice Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π k rappresenta uno spostamento valido Il caso base (π[1] = 0) è garantito dalle linee 2-3 Il valore di k all’inizio di ogni iterazione del ciclo for è uguale a π[q-1] Tale condizione rimane vera nelle successive iterazioni grazie alle linea 9 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Analisi del codice Compute-Prefix-Function(P) m ← length[P] π[1] ← 0 k ← 0 for q ← 2 to m do while k>0 e P[k+1] ≠ P[q] do k ← π[k] if P[k+1] = P[q] then k ← k+1 π[q] ← k return π Le linee 5-8 fanno sì che k diventi il valore corretto di π[q] Il ciclo alle linee 5-6 cerca tra tutti gli spostamenti calcolati in π uno per cui P[k+1] = P[q] A questo punto k è lo spostamento cercato Se un tale valore non viene trovato, k=0 alle linee 7-9 e a π[q] è assegnato 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Sfruttando la funzione di prefisso si può definire un algoritmo con queste caratteristiche: Legge il testo un carattere alla volta senza ritornare indietro Il pattern non viene sempre riletto dall’inizio Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Pseudocodice KMP-Matcher(T,P) nlenght[T] mlenght[P] p COMPUTE-PREFIX-FUNCTION(P) q0 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “Il pattern appare con spostamento” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione KMP-Matcher(T,P) nlenght[T] mlenght[P] p COMPUTE-PREFIX-FUNCTION(P) q0 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a b a 1 2 3 4 Variabili: n=9 m=4 p=[0,1,2,0] q=0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a b a 1 2 3 4 Variabili: n=9 m=4 p=[0,1,2,0] q=0 1 i=1 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a b a 1 2 3 4 Variabili: n=9 m=4 p=[0,1,2,0] q=1 2 i=2 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a b a 1 2 3 4 Variabili: n=9 m=4 p=[0,1,2,0] q=2 3 i=3 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a b a 1 2 3 4 Variabili: n=9 m=4 p=[0,1,2,0] q=3 4 i=4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=4 i=4 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Aggiornamento di q q = p[4] = 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=0 1 i=5 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=1 2 i=6 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=2 3 i=7 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=3 p[3] 2 i=8 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=2 3 i=8 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=3 4 i=9 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Esempio di applicazione 1 2 3 4 5 6 7 8 9 Testo = Pattern = b a Variabili: n=9 m=4 p=[0,1,2,0] q=4 i=9 b a 1 2 3 4 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Output Il pattern appare con spostamento 0 Il pattern appare con spostamento 5 Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Analisi della complessità computazionale KMP-Matcher(T,P) nlenght[T] mlenght[P] pCOMPUTE-PREFIX-FUNCTION(P) q0 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] La chiamata alla funzione esterna COMPUTE-PREFIX-FUNCTION ha un costo O(m) come visto in precedenza. Il costo del ciclo for (linea 5) è O(n), lineare rispetto alla lunghezza del testo. O(m) O(n) Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Analisi della complessità computazionale KMP-Matcher(T,P) nlenght[T] mlenght[P] pCOMPUTE-PREFIX-FUNCTION(P) q0 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Il costo ammortizzato delle linee 6-12 è Il tempo effettivo di esecuzione di KMP-Matcher è O(n+m) O(m) O(n) } O(1) Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Analisi del codice (linea 5)Il ciclo for garantisce che la ricerca avviene in modo lineare (confrontando ogni elemento del testo). (linee 6,7)In caso di mismatch si ritorna indietro fino a trovare un prefisso valido (dato dalla funzione prefisso), oppure fino all’inizio del pattern. KMP-Matcher(T,P) nlenght[T] mlenght[P] p COMPUTE-PREFIX-FUNCTION(P) q0 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Algoritmo Knuth-Morris-Pratt Analisi del codice (linee 8,9)Se i caratteri selezionati nel pattern P e nel testo T sono uguali, garantiscono l’avanzamento del carattere controllato nel pattern. (linea 12)Necessaria per rilevare correttamente le occorrenze di P in T successive alla prima. KMP-Matcher(T,P) nlenght[T] mlenght[P] p COMPUTE-PREFIX-FUNCTION(P) q0 for i1 to n do while q>0 e P[q+1]≠T[i] do qp[q] if P[q+1]=T[i] then qq+1 if q=m then stampa “…” i-m qp[q] Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Confronto con altri algoritmi Naive (O((n-m+1)m)), soddisfacente se: si vuole trovare solo la prima occorrenza di un pattern e questa ha buona probabilità di trovarsi all’inizio del testo. Se si cercano pattern al più di 3-4 caratteri (improbabile per pattern di DNA). Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Knuth-Morris-Pratt VS Boyer-Moore KMP:(O(n+m)) complessità sempre lineare adatto a testi con sequenze ripetitive efficiente con pattern corti BM: In media sub-lineare Problemi con stringhe ripetitive Caso peggiore O(n2) In pratica è il più veloce per la maggior parte delle applicazioni Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Bibliografia T.H. Cormen, C.E. Leiserson, R.L. Rivest, Introduzione agli algoritmi, Jackson Libri, seconda edizione. pp. 805-833 cap. 34. D. E. Knuth, J. H. Morris and V. R. Pratt. Fast Pattern Matching in Strings. SIAM Jrnl. Comput. 6(2) p323-350 Jun 1997. M. Régnier Knuth-Morris-Pratt alghorithm: an analysis. INRIA , Jan 1989. Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Bibliografia R. Grossi Algoritmi per internet e Web: Ricerca e indicizzazione di testi. Università degli studi di pisa, 2003. C. Charras, T. Lecroq Handbook of Exact String Matching Algoritms. A.V. Aho, Algorithms for finding patterns in strings. in Handbook of Theoretical Computer Science, Volume A, Algorithms and complexity, J. van Leeuwen ed., Chapter 5, pp 255-300, Elsevier, Amsterdam. 1990. Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm
Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm Link utili http://www-igm.univ-mlv.fr/~lecroq/string/index.html http://www.ics.uci.edu/~eppstein/161/960227.html http://www.med.yale.edu/bcmm/Informatics/Jan20/KMP.htm Cappellazzo Pietro, Rizzato Andrea - The Knuth Morris Pratt Algorithm