Algorithmique du texte Recherche de motifs Introduction Rechercher un motif dans un texte, indexer des données textuelles, expliciter les régularités d’un texte sont des problèmes omniprésents en informatique : éditeur de texte, moteur de recherche, bases de données textuelles, analyse de séquences biologiques, compression Contingences pratiques : • on travaille sur des données de grande taille ⇒ il est impératif de trouver des algorithmes qui soient de petites complexités à la fois en temps et en espace • les données sont des séquences de caractères et n’ont pas de structure explicite ⇒ définir des algorithmes rapides nécessite de définir les structures adéquates pour représenter et manipuler efficacement les chaı̂nes de caractères (structures pas trop coûteuses à construire et peu gourmandes en espace) 2 Notations Un alphabet Σ : un ensemble fini de symboles, appelés lettres ou caractères Un motif ou un texte sur l’alphabet Σ : une suite de lettres de Σ La longueur d’un mot w, notée |w| : le nombre de lettres du mot Le mot vide, i.e., le mot de longueur 0 : ε Par convention, on indice les lettres d’un mot à partir de 0 : w = w[0]w[1] . . . w[n − 1] avec n = |w| La séquence de lettres partant de la position i et de longueur j : w[i : i + j] = w[i]w[i + 1] . . . w[i + j − 1] Σ∗ : l’ensemble de tous les mots sur Σ Σ+ : l’ensemble de tous les mots non vides sur Σ 3 Notations Les préfixes de w : Pref(w) = {x : il existe y ∈ Σ∗ tel que w = xy} Les suffixes de w : Suf(w) = {y : il existe x ∈ Σ∗ tel que w = xy} Les facteurs de w : Fact(w) = {z : il existe x, y ∈ Σ∗ tel que w = xzy} Un préfixe, suffixe ou facteur d’un mot w est propre, s’il est différent de w lui-même. Exemple w = abbaac Pref(w) = Suf(w) = Fact(w) = 4 Notations Les préfixes de w : Pref(w) = {x : il existe y ∈ Σ∗ tel que w = xy} Les suffixes de w : Suf(w) = {y : il existe x ∈ Σ∗ tel que w = xy} Les facteurs de w : Fact(w) = {z : il existe x, y ∈ Σ∗ tel que w = xzy} Un préfixe, suffixe ou facteur d’un mot w est propre, s’il est différent de w lui-même. Exemple w = abbaac Pref(w) = {ε, a, ab, abb, abba, abbaa, abbaac} Suf(w) = {ε, c, ac, aac, baac, bbaac, abbaac} Fact(w) = {ε, a, b, c, aa, ab, ac, ba, bb, aac, abb, baa, bba, abba, baac, bbaa, abbaa, bbaac, abbaac} 4 Recherche de motif Trouver les occurrences d’un motif u dans un texte t 0 u 1 n-1 texte t i motif u 0 m-1 Deux types de solutions 1. Motif fixé, texte variable • Prétraitement sur le motif basé sur des propriétés combinatoires du motif • Recherche 2. Texte fixé, motif variable • Prétraitement sur le texte basé sur des techniques d’indexation • Recherche 5 Menu des premières séances Recherche d’un motif fixé dans un texte variable Motif vu comme - un simple mot - une expression régulière - un ensemble fini de mots - un mot approché Techniques variées : - stratégie de la fenêtre coulissante - basées sur les automates finis - avec une structure de Trie - via de la programmation dynamique 6 Stratégie de la fenêtre coulissante Balayage et Décalage (Scan & Shift) On lit le texte au travers d’une fenêtre coulissante de la taille du mot. fenêtre décalage texte t balayage motif u Schéma de base Positionner la fenêtre au début du texte Tant que la fenêtre est sur le texte Si fenêtre == motif alors Signaler occurrence Décaler la fenêtre Balayage Décalage 7 Algorithme naı̈f Recherche exhaustive Entrée : Un mot u de longueur m Un texte t de longueur n pour i de 0 à n-m faire si u == t[i:i+m] alors signaler une occurrence à la position i Avec un balayage de gauche à droite 8 Algorithme naı̈f Recherche exhaustive Entrée : Un mot u de longueur m Un texte t de longueur n pour i de 0 à n-m faire si u == t[i:i+m] alors signaler une occurrence à la position i Avec un balayage de gauche à droite Entrée : Un mot u de longueur m Un texte t de longueur n i = 0 j = 0 tant que i < n-m+1 tant que j < m et u[j] == t[i+j] faire j = j+1 si j == m alors signaler une occurrence à la position i i = i+1 j = 0 8 Algorithme naı̈f Exemple b a b = 6= Le texte : aababbabababb Le motif cherché : ababa Exemple a a b a b a b a b a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b b Signaler occurrence a 24 comparaisons 9 Algorithme naı̈f Coût de l’algorithme au pire Quel est le nombre maximal de comparaisons de l’algorithme naı̈f avec un texte de longueur n et un motif de longueur m ? Donner un exemple pour lequel ce nombre maximal est atteint 10 Algorithme naı̈f Coût de l’algorithme au pire Quel est le nombre maximal de comparaisons de l’algorithme naı̈f avec un texte de longueur n et un motif de longueur m ? (n − m + 1) × m, i.e., une complexité au pire en O(nm) Donner un exemple pour lequel ce nombre maximal est atteint t = an , u = am 10 Algorithme naı̈f Coût moyen de l’algorithme σ dénote le nombre de lettres de l’alphabet Σ. On se place dans le cas simple où toutes les lettres du texte et du mot sont tirées avec une probabilité uniforme. Probabilité que le balayage s’arrête après k comparaisons sur un échec (i.e., u[: k − 1] = t[i : i + k − 1] et u[k − 1] 6= t[i + k − 1]) : Probabilité que le balayage s’arrête sur un succès après m comparaisons : Nombre moyen de comparaisons réalisées lors de chaque balayage : Le coût moyen est linéaire en la taille du texte, i.e., en O(n) 11 Algorithme naı̈f Coût moyen de l’algorithme σ dénote le nombre de lettres de l’alphabet Σ. On se place dans le cas simple où toutes les lettres du texte et du mot sont tirées avec une probabilité uniforme. Probabilité que le balayage s’arrête après k comparaisons sur un échec (i.e., u[: k − 1] = t[i : i + k − 1] et u[k − 1] 6= t[i + k − 1]) : 1 1 1 1 σ k−1 (1 − σ ) = σ k−1 − σ k Probabilité que le balayage s’arrête sur un succès après m 1 comparaisons : σm Nombre moyen de comparaisons réalisées lors de chaque balayage : m m m P P P 1 1 k m k( σk−1 − σ1k ) + σmm = ( σk−1 k−1 − σ k ) + σ m σ k−1 + k=1 k=1 = m−1 P k=0 1 σk = 1−1/σ m 1−1/σ ≤ 1 1−1/σ k=1 ≤2 Le coût moyen est linéaire en la taille du texte, i.e., en O(n) 11 Algorithme naı̈f → Algorithme de Morris-Pratt b a b = 6= Algo naı̈f : on oublie tout Algo de Morris-Pratt : on mémorise les caractères du mot appareillés à ceux du texte a a b a b a b a b a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b b Occurrence a 12 Algorithme naı̈f → Algorithme de Morris-Pratt b a b = 6= Algo naı̈f : on oublie tout Algo de Morris-Pratt : on mémorise les caractères du mot appareillés à ceux du texte a a b a b a b a b a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b b Décalage voué à l’échec Décalage voué à l’échec Occurrence Décalage voué à l’échec a 12 Algorithme naı̈f → Algorithme de Morris-Pratt b a b = 6= Algo naı̈f : on oublie tout Algo de Morris-Pratt : on mémorise les caractères du mot appareillés à ceux du texte a a b a b a b a b a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b a a b a b b Décalage voué à l’échec Tests inutiles Décalage voué à l’échec Occurrence Décalage voué à l’échec a Tests inutiles 12 Algorithme de Morris-Pratt Principe - Le balayage se fait de gauche à droite. - Le décalage de la fenêtre est calculé à partir du motif et de ses bords 6= = t 0 = u i Calculer un “bon” décalage suite à un échec à la position i : Déterminer un préfixe propre de u[: i] qui soit également suffixe de u[: i], et on veut le plus grand. ⇒ notion de bord 13 Bord Un bord d’un mot w est un mot différent de w qui est à la fois préfixe et suffixe de w Le bord maximal de w, noté Bord(w), est le plus long bord de w Exemple w = abaababa L’ensemble des bords de w : Bord(w) = w = aabaabaa L’ensemble des bords de w : Bord(w) = 14 Bord Un bord d’un mot w est un mot différent de w qui est à la fois préfixe et suffixe de w Le bord maximal de w, noté Bord(w), est le plus long bord de w Exemple w = abaababa L’ensemble des bords de w : {ε, a, aba} Bord(w) = aba w = aabaabaa L’ensemble des bords de w : {ε, a, aa, aabaa} Bord(w) = aabaa 14 Calculer le Bord Fait Pour tout mot u ∈ Σ+ et tout caractère a ∈ Σ : ( Bord(u)a si Bord(u)a est un préfixe de u Bord(ua) = Bord(Bord(u)a) sinon u a x a Bord(u) Bord(u) ua x=a a a Bord(u)a Bord(u)a Pourquoi Bord(u)a est maximal ? ua x 6= a x Bord(Bord(u)a) a Bord(Bord(u)a) Bord(Bord(u)a) 15 La table des bords Définition (La table des bords d’un mot w) Un tableau de |w| + 1 entiers, noté TB, et défini par : −1 si i = 0 TB[i] = |Bord(w[: i])| si i > 0 Exemple w = abaababa i w[i-1] TB[i] 0 1 a 2 b 3 a 4 a 5 b 6 a 7 b 8 a 1 a 2 a 3 b 4 a 5 a 6 b 7 a 8 a w = aabaabaa i w[i-1] TB[i] 0 16 La table des bords Définition (La table des bords d’un mot w) Un tableau de |w| + 1 entiers, noté TB, et défini par : −1 si i = 0 TB[i] = |Bord(w[: i])| si i > 0 Exemple w = abaababa i w[i-1] TB[i] 0 -1 1 a 0 2 b 0 3 a 1 4 a 1 5 b 2 6 a 3 7 b 2 8 a 3 1 a 0 2 a 1 3 b 0 4 a 1 5 a 2 6 b 3 7 a 4 8 a 5 w = aabaabaa i w[i-1] TB[i] 0 -1 16 Calculer la table des bords L’algorithme Entrée : Un mot w de longueur m Sortie : la table des bords TB de w TB = [0, ..., 0] TB[0] = -1 # table initialisée avec m+1 0 courant = -1 pour i de 0 à m-1 faire # calculer TB[i+1] tant que courant >= 0 et w[i] != w[courant] faire courant = TB[courant] courant = courant +1 TB[i+1] = courant retourner TB w[ :i] Bord(w[:i]) Bord(w[:i]) Bord(Bord(w[:i])) ? 0 TB[TB[i]] Bord(Bord(w[:i])) ? w[i] TB[i] i 17 Calculer la table des bords Complexité de l’algorithme La complexité au pire est linéaire en la taille m du mot Complexité est linéaire en le nombre de comparaisons entre lettres ≈ Nombre total de fois où la condition courant >=0 et w[i] !=w [cour] est examinée La quantité ∆(i, courant) = 2i − courant augmente de 1 à chaque comparaison • Au début : ∆(0, −1) = 1 • À la fin : ∆(m − 1, courant) ≤ 2m − 2. Donc #comparaisons ≤ 2m − 3. 18 Algorithme de Morris-Pratt Exemple Le motif cherché : ababa 0 i w[i-1] TB[i] Exemple -1 1 a 0 2 b 0 3 a 1 4 b 2 5 a 3 b a b = 6= Le texte : aababbabababb a a a b a b a a b a b a a b 1 − TB[1] 4 − TB[4] b a b a b a a b a 2 − TB[2] a b a b a b a b a a b a 0 − TB[0] a b b Signaler occurrence b a 5 − TB[5] 16 comparaisons À chaque étape, il est inutile de tester les TB[i] premiers caractères du motif 19 Algorithme de Morris-Pratt L’étape recherche Entrée : Un mot u de longueur m La table des bords TB de u Un texte t de longueur n i = 0 j = 0 tant que i < n-m+1 faire tant que j < m et u[j] = t[i+j] faire j = j+1 si j = m alors signaler occurrence à la position j i = i+j-TB[j] # décalage si TB[j] > 0 alors j = TB[j] # ne pas retester les 1ers caracs sinon j = 0 20 Algorithme de Morris-Pratt Complexité de l’algorithme La complexité au pire est linéaire en m+n , somme des tailles du mot et du texte • coût du prétraitement sur le motif : Le calcul de la table des bords a un coût en O(m) • coût de la recherche : O(n) Considérer la quantité ∆0 (2i − j) (croı̂t au moins de 1 à chaque comparaison) Soit un coût en O(n) 21 De Morris-Pratt à Knuth-Morris-Pratt b a b = 6= MP : on mémorise les caractères du mot appareillés à ceux du texte KMP : on mémorise aussi les erreurs a a b a b a b a b a a b a b a a b a b a b a a b a a a b a b a b a a b a b b Occurrence b a 22 De Morris-Pratt à Knuth-Morris-Pratt b a b = 6= MP : on mémorise les caractères du mot appareillés à ceux du texte KMP : on mémorise aussi les erreurs a a b a b a b a b a a b a b a a b a b a a b a a b a b a a b a b a a b a b b Décalage voué à l’échec Décalage voué à l’échec Occurrence b a 22 Algorithme de Knuth-Morris-Pratt Principe - Le balayage se fait de gauche à droite. - Le décalage de la fenêtre est calculé à partir du motif et de ses bords stricts 6= = t i x = 6= 0 u y Calculer un “bon” décalage suite à un échec à la position i : Déterminer un préfixe propre de u[: i] qui soit suffixe de u[: i], et tel que le caractère y suivant ce préfixe est différent du caractère x suivant le suffixe (i.e., le caractère qui a provoqué l’échec) Et on veut le plus grand ⇒ notion de bord strict 23 Bord strict Soit w un mot et v un préfixe de w. b est un bord strict de v relativement à w si • b est un bord de v • v = w ou w[|v|] 6= w[|b|] Le bord strict maximal de v (relativement à w), noté BordStrict(v), est le plus long bord strict de v quand il existe w v x BordStrict(w) x BordStrict(v) Remarque : Le bord strict n’est pas toujours défini. Exemple : Le préfixe ab n’admet pas de bord strict relativement à aba 24 La table des bords stricts Définition (La table des bords stricts d’un mot w) Un tableau de |w| + 1 entiers, noté SB, et défini par : ( −1 si i=0 ou w[:i] n’a pas de bord strict SB[i] = . |BordStrict(w[: i])| si i > 0 Fait SB[0] = −1 SB[|w|] = TB[|w|] TB[i] si w[i] 6= w[TB[i]] SB[i] = SB[TB[i]] sinon 25 La table des bords stricts Exemple w = ababa i w[i-1] TB[i] SB[i] 0 Exemple -1 -1 1 a 0 0 2 b 0 -1 3 a 1 0 −1 0 a 1 a b b 6= = = = w[0] w[0] w[1] w[2] 5 a 3 3 a a w[1] w[2] w[3] w[4] 4 b 2 -1 : : : : SB[1] SB[2] SB[3] SB[4] = = = = 2 a 3 b 4 a 5 b TB[1] = 0 SB[0] = -1 SB[1] = 0 SB[2] = -1 26 La table des bords stricts Exemple w = ababcab Exemple 27 La table des bords stricts Exemple w = ababcab i 0 Exemple -1 -1 1 a 0 0 2 b 0 -1 3 a 1 0 4 b 2 2 5 c 0 -1 6 a 1 0 7 b 2 2 a a −1 0 a b 1 a b c 2 a 3 b 4 c 5 a 6 b 7 b b 27 Algorithme de Knuth-Morris-Pratt Entrée : Un mot u de longueur m et un texte t de longueur n Prétraitement calcul de la table des bords de m calcul de la table des bords stricts de m Recherche Même chose que pour Morris-Pratt hormis le décalage calculé avec les bords stricts : i = i+j-SB[j] coût en O(m) coût en O(m) coût en O(n) KMP offre une garantie supplémentaire par rapport à MP sur le nombre de comparaisons maximal pour un caractère du texte. Ce nombre est borné par : - m pour MP - logφ (1 + m) où φ = √ 1+ 5 2 pour KMP Utile si on veut un algo à délai “constant” entre deux caracs traités 28 Algorithme de Knuth-Morris-Pratt Exemple Le motif cherché : ababa i w[i-1] TB[i] SB[i] Exemple 0 -1 -1 1 a 0 0 2 b 0 -1 3 a 1 0 4 b 2 -1 5 a 3 3 b a b = 6= Le texte : aababbabababb a a a b a b a a b a b 1 − SB[1] b a b a b a a b a b a a b a b b a 4 − SB[4] Signaler occurrence b a 5 − SB[5] 14 comparaisons 29