Skip to main content Informatique en prépa - Lycée Malherbe 

3.1- TP - Automate des motifs

On s'interesse dans ce TP à "l'automate des motifs", une structure qui permet de rechercher rapidement un motif (= un mot) dans un texte. Le principe de l'automate des motifs n'est pas à retenir, il s'agit simplement de travailler les automates sur une application réelle.

I. Préliminaires : Automates en OCaml

On définit une structure d'automate en OCaml en utilisant un type enregistrement.

Types enregistrement

Ce sont des types qui permettent d'associer plusieurs objets au sein d'une même variable. Pour les déclarer, on utilise la syntaxe suivante :

type nom_enregistrement = {nom1: type1; nom2: type2; nom3: type3};;

Pour créer une variable de type nom_enregistrement, on utilise la syntaxe suivante :

let val_enregistrement = {nom1 = valeur1; nom2 = valeur2; nom3 = valeur3};;

On peut ensuite accéder aux valeurs des champs de la manière suivante :

val_enregistrement.nom1 (*ceci vaut valeur1*)

Il est possible de rendre un champs d'un enregistrement mutable (sa valeur peut être modifiée) en le déclarant avec mutable nom1: typ1 au lieu de simplement nom1: type1.

On va travailler avec l'alphabet , déclaré de la manière suivante :

OCaml

Loading editor...

type lettre = A | B;;
type mot = lettre list;;

Ainsi, un automate sera un type enregistrement avec :

Le type transition est un enregistrement contenant deux champs, "a" et "b", indiquant l'état d'arrivée de la transition pour chaque lettre.

Le type array en OCaml

En plus des listes, le langage OCaml a un type array. Il s'agit de tableau indexables (donc on peut prendre directement l'élément n°i directement), mutables (on peut changer la valeur de l'élément n°i), mais non redimensionnables : on les déclare avec une taille, et ils ne changent jamais de taille !

Comme les listes, le type d'un tableau d'entiers s'écrit int array, de booléens bool array, etc.

On les utilise de la manière suivante :

  • création :
    • let tab = Array.make n x créé un tableau tab de longueur n rempli de x
    • let tab = [|1; 2; 3; 10|] créé un tableau contenant 1, 2, 3 et 10.
  • accès à un élément
    • tab.(i) lis l'élément i.
  • modification
    • tab.(i) <- x écrit x dans la case i de tab. Cette opération renvoie unit, on la succède donc en général d'un simple ;.
Question 1

Complétez le type dfa (pour "deterministic finite automaton") correspondant à un automate déterministe.

OCaml

Loading editor...

type dfa_transition = {a: (*compléter*); b: (*compléter*)};;

type dfa = {q: (*compléter*); q0: (*compléter*); f: bool array; delta: (*compléter*) array};;
type dfa_transition = {a: int; b: int};;

type dfa = {q: int; q0: int; f: bool array; delta: dfa_transition array};;
Question 2

Dans une variable, définir l'automate déterministe représenté par ce dessin :

start 0 0 start->0 0->0 B 1 1 0->1 A 1->0 A 1->1 B
OCaml

Loading editor...

Dessiner un automate

Le site fournit une fonction dessine aut, qui affiche un automate. Testez-la sur l'automate de la question précédente !

OCaml

Loading editor...

let dessine (aut: dfa) =
     let finals = List.filter (fun q -> aut.f.(q)) (List.init aut.q Fun.id) in
     let transitions = List.concat (List.init aut.q (fun q ->
         [(q, "A", aut.delta.(q).a); (q, "B", aut.delta.(q).b)])) in
     afficher_automate aut.q [aut.q0] finals transitions;;
OCaml

Loading editor...

Question 3

Ecrivez une fonction delta_f de type dfa -> int -> lettre -> int qui correspond à la fonction .

OCaml

Loading editor...

Question 4

Ecrivez une fonction delta_star de type dfa -> int -> mot -> int qui correspond à la fonction .

OCaml

Loading editor...

Question 5

Ecrivez une fonction accepte de type dfa -> mot -> bool qui renvoie true si l'automate accepte le mot, false sinon. Testez votre fonction sur quelques mots exemples.

OCaml

Loading editor...

II. L'automate des motifs

L'idée de l'automate des motifs, c'est d'avoir un automate qui, lorsqu'on recherche un mot dans un texte, dans lis les lettres du texte une par une, et est dans un état acceptant à chaque fois que le mot est reconnu.

1. Construction

L'automate des motifs est construit par rapport au mot à chercher : il ne dépend pas du texte.

L'idée est que, à tout moment, l'état de l'automate correspond à l'endroit où, au maximum, on est dans le mot à l'état actuel. Voici un exemple sur le mot aba et le texte abbaaababa : l'automate à 4 états, et est dans les états suivants :

   a b b a a a b a b a
0  1 2 0 1 1 1 2 3 2 3
                 ^   ^

Pour formaliser cela, on défini

Dans l'exemple ci-dessus, on a :

Question 6

Dessinez l'automate correspondant au motif aba, puis détaillez le chemin parcouru en lisant le mot aabaabba. Quand est-ce que l'automate est dans un état acceptant ?

OCaml

Loading editor...

Question 7

Ecrivez une fonction prefixe m i de type mot -> int -> mot qui renvoie le préfixe de taille i de m.

OCaml

Loading editor...

Question 8

Ecrivez une fonction suffixe_max p m de type mot -> mot -> int qui calcule la taille du plus grand suffixe de p qui est aussi préfixe de m. Vous pouvez vous aider d'une fonction auxiliaire est_prefixe p m.

OCaml

Loading editor...

Question 9

Ecrivez une fonction sigma m i x qui calcule la valeur de pour le mot m.

OCaml

Loading editor...

Question 10

Enfin, écrivez une fonction automate_motif m de type mot -> dfa qui calcule l'automate des motifs pour un mot m.

OCaml

Loading editor...

2. Utilisation de l'automate

Question 11

On prend comme exemple le mot aba. Votre automate accepte-il aba ? abbababa ? abaaa ?

OCaml

Loading editor...

let m1 = [A; B; A];;
let m2 = [A; B; B; A; B; A; B; A];;
let m3 = [A; B; A; A; A];;
Question 12

Ecrivez une fonction recherche automate texte de type dfa -> mot -> int list qui renvoie une liste de tous les tels que l'automate accepte . Testez-la sur l'automate de la question précédente et le texte suivant :

OCaml

Loading editor...

let texte = [A; A; B; A; B; A; B; A; A; B; B; A; A; B; A; B; B];;
OCaml

Loading editor...

Question 13

Quelle est la complexité de la création de l'automate ? Et celle de la recherche dans un texte une fois l'automate créé ?

OCaml

Loading editor...

3. Reconnaitre plusieurs mots ?

On aimerait maintenant reconnaitre plusieurs mots, au choix. On propose pour cela d'utiliser l'automate union.

Question 14

Ecrivez une fonction union a1 a2 de type dfa -> dfa -> dfa qui renvoie l'automate union de a1 et a2.

Indication : ici, on a que des automates deterministes. L'idée est de faire l'union et la determinisation en une seule étape.

OCaml

Loading editor...

Les modules Queue et Hashtbl

OCaml fournit des files et des tables de hachage mutables : les fonctions qui les modifient renvoient unit.

Files (module Queue), de type 'a Queue.t :

  • let f = Queue.create () crée une file vide ;
  • Queue.add x f ajoute x à la fin de la file f ;
  • Queue.pop f retire l'élément en tête de la file et le renvoie (exception Queue.Empty si la file est vide) ;
  • Queue.is_empty f teste si la file est vide, Queue.length f renvoie son nombre d'éléments.

Tables de hachage (module Hashtbl), de type ('a, 'b) Hashtbl.t (clés de type 'a, valeurs de type 'b) :

  • let t = Hashtbl.create 16 crée une table vide (16 est une taille initiale indicative, la table s'agrandit toute seule) ;
  • Hashtbl.replace t k v associe la valeur v à la clé k (en remplaçant l'ancienne valeur s'il y en avait une) ;
  • Hashtbl.find t k renvoie la valeur associée à k (exception Not_found si k n'est pas dans la table) ;
  • Hashtbl.find_opt t k renvoie Some v si k est associée à v, None sinon ;
  • Hashtbl.mem t k teste si la clé k est dans la table ;
  • Hashtbl.remove t k supprime la clé k ;
  • Hashtbl.length t renvoie le nombre de clés.

N'importe quelle valeur peut servir de clé, par exemple un couple d'entiers : Hashtbl.replace t (2, 3) 7.

Attention : Hashtbl.add t k v existe aussi, mais il masque l'ancienne valeur de k au lieu de la remplacer (elle réapparaît après un Hashtbl.remove).

Question 15

Dessinez l'automate union de la question précédente : beaucoup de ses états ne sont pas accessibles depuis l'état initial, ils ne servent à rien. Ecrivez une fonction union_accessible a1 a2, de type dfa -> dfa -> dfa, qui ne construit que les états accessibles de l'automate union.

Indication : faites un parcours (en largeur, par exemple) depuis le couple d'états initiaux, en numérotant les couples dans l'ordre où on les découvre. Une file (Queue) contient les couples à traiter, et une table de hachage (Hashtbl) permet de retrouver le numéro d'un couple déjà vu.

OCaml

Loading editor...


Entrez le code donné en cours pour accéder à la solution :