• Aucun résultat trouvé

5 Une autre approche du filtrage

5.1 Langage d´eriv´e

SoitLun langage sur les mots etcun caract`ere. Nous notonsc1·Lle langage d´eriv´e, d´efini comme les suffixesm des mots deL qui sont de la forme c·m.

c1·L={m|c·m∈L}

Dans le cas d’un langage Lr´egulier engendr´e par le motifp, nous allons montrer que le langage c1·L est r´egulier en calculant le motifc1·p qui l’engendre.

On observera d’abord que, en toute rigueur, le langage c1·L peut ˆetre vide, par exemple siL={c} avecc6=c. Or, selon notre d´efinition des langages r´eguliers, le langage vide∅ n’est pas r´egulier. Qu’`a cela ne tienne, nous inventons imm´ediatement un nouveau motif ∅, qui ne filtre aucun mot. En consid´erant les valeurs [[p]], on ´etend facilement les trois op´erateurs des expressions r´eguli`eres.

·p=∅ p·∅=∅ ∅|p=p p|∅=p ∅*=ǫ

Ces r`egles nous permettent d’´eliminer les occurrences internes de ∅, de sorte qu’un motif est d´esormais ∅ou un motif qui ne contient pas∅.

Proposition 15 SiL= [[p]], alors le langagec1·L est r´egulier, engendr´e par le motif c1·p d´efini ainsi :

c1·∅ = ∅ c1·ǫ = ∅ c1·c = ǫ

c1·c = ∅ pour c6=c c1·(p1|p2) = c1·p1|c1·p2

c1·(p1·p2) = (c1·p1)·p2 si p16≺ǫ c1·(p1·p2) = (c1·p1)·p2|c1·p2 si p1ǫ

c1·p* = (c1·p)·p*

Preuve.On montre, par induction sur la structure dep, que pour tout motm, on a l’´equivalence : c1·pm ⇐⇒ pc·m

Seuls les trois derniers cas de la d´efinition dec1·p pr´esentent un int´erˆet.

ˆ Posonsp=p1·p2et supposons en outrep1 6ǫ. En revenant aux d´efinitions, par induction, puis par d´efinition, on a les ´equivalences successives :

p1·p2 c·m ⇐⇒ ^ en pr´efixe vide et suffixe complet. Dans ce cas on a par induction :

^

p1 ǫ

p2 c·m ⇐⇒ ^

p1ǫ c1·p2 m Ce qui conduit `a l’´equivalence :

p1·p2 ≤c·m ⇐⇒ _

En toute rigueur, l’´equivalence r´esulte d’un nombre arbitraire applications de la r`egle Star-Seqpour un pr´efixe vide et d’une application de la mˆeme r`egle pour la d´ecomposition ´ecrite ci-dessus. On peut ensuite conclure par induction.

Par ailleurs, on d´ecide de la validit´e depǫ par une simple induction structurelle.

Lemme 16 On note N(p) le pr´edicat pǫ. Le pr´edicatN(p) se calcule inductivement ainsi : N(∅) = faux Preuve.Induction facile sur la structure des motifs.

5.2 Filtrage par la d´erivation des motifs

Pour savoir si un motifpfiltre un motm, on peut tout simplement it´erer sur les caract`eres du mot, en calculant les d´erivations successives de p par les caract`eres consomm´es. Un fois atteint la fin du mot, il ne reste qu’`a v´erifier si le motif d´eriv´e filtre le mot vide.

Plus pr´ecis´ement, les deux r´esultats de la section pr´ec´edente (proposition 15 et lemme 16) nous permettent d’´ecrire deux nouvelles m´ethodes statiques dans la classe Re.

// Renvoie le motif c1·p ou null si c1·p est ∅ static Re derivate(char c, Re p) ;

// Calculer N(p)

static boolean nullable(Re p) ;

Exercice 6 (Non corrig´e, vu en TP) Programmer ces deux m´ethodes. On fera attention `a la pr´esence du motif ∅ qui sera repr´esent´e par null et ne se trouvera jamais `a l’int´erieur des arbresRe. C’est-`a-dire que le r´esultat deRe.derivate est null ou un motif standard.

On peut alors ´ecrire par exemple la m´ethode matches (simplifi´ee, sans tenir compte de mStartet mEnd) de la classeMatcherainsi :

public boolean matches() { Re d = pat ;

for (int k = 0 ; k < text.length() ; k++) { d = Re.derivate(text.charAt(k), d) ;

i f (d == null) return false ; }

return Re.nullable(d) ; }

Exercice 7 R´ecrire la m´ethode find de la classeMatcher (figure 6) en utilisant cette fois la d´erivation de motifs. On s’efforcera de limiter le nombre des d´erivations de motif effectu´ees, tout en identifiant la sous-chaˆıne filtr´ee la plus `a gauche et la plus longue possible.

Solution.Une solution possible est d’introduire une m´ethode findLongestPrefix qui cherche le plus long pr´efixe filtr´e `a partir de la position start. En cas de succ`es, la m´ethode renvoie la premi`ere position non-filtr´ee ; en cas d’´echec, la m´ethode renvoie -1.

private int findLongestPrefix(int start) { Re d = pat ;

int found = -1 ;

i f (Re.nullable(d)) found = start ; // Trouv´e le pr´efixe vide for (int k = start ; k < text.length() ; k++) {

d = Re.derivate(text.charAt(k), d) ; i f (d == null) return found ;

i f (Re.nullable(d)) found=k+1 ; // Trouv´e le pr´efixe de longueur k+1-start }

return found ; }

La m´ethode findLongestPrefix calcule simplement les motifs d´eriv´es par tous les caract`eres de text `a partir de la positionstart, en se souvenant (dans found) du filtrage le plus long. La recherche s’arrˆete quand la chaˆıne est lue en totalit´e ou quand le motif d´eriv´e est∅.

Ecrire´ find est ensuite imm´ediat : chercher un pr´efixe filtr´e dans tous les suffixes possibles de text.

public boolean find() {

for (int start = regStart ; start <= text.length() ; start++) { int end = findLongestPrefix(start) ;

i f (end >= 0) {

mStart = start ; mEnd = end ; regStart = mEnd ;

return true ; }

}

mStart = mEnd = -1 ; regStart = 0 ;

return false ; }

On observe que, pour une positionstart donn´ee, la nouvelle m´ethode findtrouve bien la plus longue sous-chaˆıne filtr´ee. Une implantation qui donnerait la plus petite sous-chaˆıne filtr´ee est plus simple.

private int findShortestPrefix(int start) { Re d = pat ;

i f (Re.nullable(d)) return start ; // Trouv´e le pr´efixe vide for (int k = start ; k < text.length() ; k++) {

d = Re.derivate(text.charAt(k), d) ; i f (d == null) return -1 ;

i f (Re.nullable(d)) return k+1 ; }

return -1 ; // Aucun pr´efixe ne convient }

La mesure des temps d’ex´ecution de la nouvelle classe Matcherfait apparaˆıtre de meilleurs performances dans les deux premi`eres exp´eriences de la section 4.4 et une consommation tr`es importante de la m´emoire dans la derni`ere exp´erience.

Exercice 8 Calculer la succession des motifs d´eriv´es pour le motif X(.+)+Xet le mot XX=· · ·= et justifier le r´esultat de la derni`ere exp´erience.

Solution. Notonsp0,p1 etc. la suite des motifs d´eriv´es Il faut d’abord d´eriver deux fois par X.

p0 =X(.+)+X p1 =(.+)+X p2 =.*(..*)*X

Pour calculerp2on a exprim´ep+commepp*. Si on suit la d´efinition de la d´erivation on a en toute rigueur des r´esultat diff´erents — par exemple,p1 =()(.+)+X. Mais on enl`eve les motifs ()des s´equences, les motifs sont d´ej`a bien assez compliqu´es comme cela. Soit le motif q =.*(..*)*, on a p2 =qX. Par ailleurs la d´erivation =1·q vaut q|q. Le motif p filtre le mot vide, mais la d´erivation de Xpar=vaut ∅. On a donc :

p3 = (q|q)·X Et en posant q1 =q etqn+1 =qn|qn il est clair que l’on a :

pn+2 =qn+1·X Motif dont la taille est exponentielle enn.