Le sujet
Cette année le cours d'initiation à la recherche est consacré à la compression de lexiques à l'aide de la réduction d'automates d'états finis acycliques. Nous présentons un algorithme de réduction d'automates acycliques en temps linéaire qui s'appuie sur un tri lexicographique linéaire.Les documents
Le principal article qui a servi à l'élaboration de ce cours est intitulé "Minimisation of Acyclic Deterministic Automata in Linear Time" de Dominique Revuz dans la revue Theoretical Computer Science 92, (1992), pp. 181-189. J'ai également utilisé un survey de J. Berstel, L. Boasson, O. Carton et I. Fagnot intitulé "Minimization of Automata" daté de janvier 2011.Présentation du problème
On se donne un lexique (dans le cas présent le lien pointe sur un lexique contenant près de 400.000 formes fléchies du français, i.e. contenant les singuliers, pluriels, conjugaisons, etc.), c'est-à-dire un ensemble de mots \(L\) sur un alphabet \(\Sigma\) ainsi qu'un mot \(w\in \Sigma^*\). On s'intéresse alors au problème de décision suivant:\(w\) appartient-il ou non à \(L\) ?L'objectif est de trouver une structure de données adéquate pour représenter ce lexique et pour que la recherche du mot \(w\) se fasse le plus rapidement possible. Une solution élégante et efficace à ce problème consiste à représenter le lexique \(L\) à l'aide d'un automate fini déterministe qui reconnaît les mots du lexique, ce que nous expliciterons plus loin. Le cours a pour but de présenter un algorithme de réduction d'automates qui permet de construire l'automate minimal reconnaissant le lexique en temps linéaire par rapport au nombre d'états de l'automate associé à l'arbre lexicographique du lexique.
Quelques rappels sur les graphes
Un graphe orienté \(G=(X,U)\) est un couple constitué d'un ensemble \(X\) de sommets et d'un ensemble d'arcs \(U\subseteq X \times X\). On représente schématiquement un graphe en dessinant des cercles autour des sommets et en reliant ces cercles par des flèches pour matérialiser les arcs, ainsi l'arc \((x,y)\in U\) est représenté par une flèche qui part de \(x\) (le sommet de départ) et qui aboutit en \(y\) (le sommet d'arrivée). L'arc \((x,y)\) est dit incident à \(x\) ainsi qu'à \(y\), on peut préciser vers l'extérieur en \(x\) et vers l'intérieur en \(y\). Quand l'orientation importe peu, on parle d'arêtes plutôt que d'arcs et on les définit à partir de paires de sommets au lieu de couples, on parle alors de graphe non-orienté.Si \(G=(X,U)\) est un graphe, et \(V\subseteq U\) est une partie des arcs de \(G\), le graphe \((X,V)\) est appelé graphe partiel de \(G\). Si on considère une partie \(Y\subseteq X\), et la partie \(V\subseteq U\) qui ne contient plus que les arcs incidents aux sommets \(x\) et \(y\) tels que \((x,y)\in V\), il s'agit du sous-graphe de \(G\) induit par \(V\). Un graphe est dit connexe si pour toute paire de sommets \(x\) et \(y\), il existe une chaîne qui les relie et fortement connexe s'il existe un chemin reliant \(x\) à \(y\) et un chemin reliant \(y\) à \(x\). Quand un graphe n'est pas connexe, on peut considérer ses composantes connexes qui sont les plus grands sous-ensembles de sommets possibles tels que les sous-graphes induits soient connexes.
Le graphe de la figure 1 est un graphe orienté qui n'est pas connexe, mais contient deux composantes connexes \(\{e,g\}\) et \(\{a,b,c,d,f\}\). Il contient deux boucles \((e,e)\) et \((b,b)\) et d'autres cycles comme \((a,f,c,b,a)\) par exemple (qui n'est pas un circuit). La séquence \((a,f,c,d)\) constitue un chemin, la séquence \((b,c,d,c,b)\) un circuit de ce graphe. Les sommets \(c\) et \(a\) sont reliés par la chaîne \((c,b,a)\) qui n'est pas un chemin puisqu'il n'existe pas d'arc \((b,a)\).
Un graphe est dit étiqueté si on lui adjoint une fonction \(\nu:U\rightarrow E\) où \(E\) est un ensemble dont les éléments sont appelés des étiquettes, généralement un alphabet ou un ensemble de mots sur un alphabet et on surmonte les flèches des étiquettes correspondantes.
Automates
Considérons un alphabet fini \(\Sigma\). On appelle mot défini sur \(\Sigma\) toute suite finie de symboles de \(\Sigma\) et on omet de séparer les symboles de la suite comme on le fait pour un mot d'une langue naturelle. La suite vide définit un mot particulier appelé mot vide et noté \(\epsilon\). La fermeture de Kleene d'alphabet fini \(\Sigma\) est l'ensemble des mots définis sur \(\Sigma\) et on note cet ensemble \(\Sigma^*\). Par exemple, pour l'alphabet binaire \(\Sigma=\{0,1\}\), on a \[\Sigma^*=\{\epsilon,0,1,00,01,11,100,\ldots\}.\] et pour l'alphabet latin \(A=\{a,b,c,\ldots,z\}\), \[\Sigma^*=\{\epsilon,a,b,\ldots,z,aa,ab,\ldots\}.\] qui contient en particulier tous les mots de la langue françaiseUn chemin dans le graphe associé à un automate détermine une séquence de transitions telles que l'état d'arrivée d'une transition est l'état de départ de la transition suivante. Ce chemin est appelé un calcul que l'on peut résumer par un triplet \((p,w,q)\in Q\times\Sigma^*\times S\) ou encore \(p\stackrel{w}{\rightarrow} q\) où \(w\in\Sigma^*\) est la concaténation des étiquettes des transitions successives dont la première a pour état de départ \(p\) et la dernière a pour état d'arrivée \(q\).
La représentation d'un automate est celle d'un graphe étiqueté dont les sommets sont les états de l'automate et où chaque transition \((p,a,q)\) de l'automate détermine un arc \((p,q)\) d'étiquette \(a\). On distingue les états initiaux par une flèche entrante et les états terminaux par une flèche sortante ou plus souvent par un double cerclage. L'automate ci-dessous a pour ensemble d'états \(Q=\{1,2,3\}\), deux états initiaux \(I=\{1,2\}\) et un état terminal \(T=\{3\}\).
Dans ce cas toute transition \((p,a,q)\) est uniquement déterminée par la relation \(q=\delta(p,a)\). L'unicité de l'état d'arrivée pour un état et une étiquette donnés justifie l'écriture \(p.a\) pour désigner l'état \(\delta(p,a)\) et ainsi si on a une autre transition \((q,b,r)\), on note avantageusement \(p.ab\) l'état d'arrivée \(\delta(q,\delta(p,a),b)\). Formellement le monoïde libre \(\Sigma^*\) agit à droite sur l'ensemble des états \(Q\).
Dans l'exemple ci-dessous, l'automate a pour alphabet l'alphabet binaire \(\Sigma=\{0,1\}\), pour ensemble d'états \(Q=\{A,B,C\}\) dont \(A\) est l'état initial et l'ensemble des états terminaux est \(T=\{A,C\}\).
On a donc \(L(A)=L(q_0)\). Très concrètement, pour savoir si un mot \(u\in\Sigma^*\) est reconnu par un automate, il suffit de trouver un chemin d'état initial \(q_0\) étiqueté par \(u\) et dont l'état final est un état terminal dans le graphe. Dans l'exemple ci-dessus, les mots 01001 et 0101101 sont reconnus.
Par soucis de simplicité, on s'intéresse plus volontiers aux automates déterministes qu'aux automates non-déterministes, mais ce choix est légitimé par le fait que l'on peut toujours déterminiser un automate non-déterministe, au sens où l'on peut construire un automate déterministe qui reconnaît le même langage. C'est le rôle de l'algorithme des parties qui construit un automate \(A'=(\Sigma,Q',q_0,T',\delta)\), déterministe cette fois, à partir d'un automate non-déterministe \(A=(\Sigma,Q,I,T,F)\).
Le principe de construction de l'automate \(A'\) est simple, son ensemble des états \(Q'\) est l'ensemble \(2^Q\) des parties de l'ensemble \(Q\), l'état initial \(q_0\) est l'ensemble \(I\) des états initiaux de \(A\) et l'ensemble des états terminaux \(T':=\{P\in Q'\mid P\cap T\not=\varnothing\}\) contient toutes les parties qui contiennent un état terminal. La fonction de transition est définie pour toute partie \(P\in 2^Q\) et tout symbole \(a\in\Sigma\) par \[\delta(P,a):=\{q'\in Q\mid \exists q\in Q,\ (q,a,q')\in F\}.\] Cet automate est déterministe et complet par construction.
On dit qu'un automate est complet s'il existe une transition pour tout état de départ \(q\) et tout symbole \(a\), autrement dit si la fonction de transition \(\delta\) est définie partout. On complète facilement un automate qui n'est pas complet en lui adjoignant un état non-terminal appelé puit vers lequel on dirige tous les arcs manquants. Un état \(q\) est accessible s'il existe un chemin partant de l'état initial \(q_0\) menant à \(q\), coaccessible s'il existe un chemin partant de \(q\) et menant à l'un des états terminaux. Si on élimine tous les états d'un automate qui ne sont pas accessibles ou qui ne sont pas coaccessibles, on obtient un nouvel automate qui reconnaît le même langage (à prouver en guise d'exercice), il s'agit de l'automate émondé. Plus généralement on dira qu'un automate est émondé si tous ses états sont à la fois accessibles et coaccessibles.
Supposons que l'on dispose de deux automates \(A\) et \(B\) qui reconnaissent un même langage \(L\) et notons \(A'\) et \(B'\) leurs automates réduits respectifs. Que peut-on dire de \(A'\) et \(B'\) ? Sont-ils isomorphes, i.e. existe-t-il une bijection entre les ensembles des états \(Q_{A'}\) et \(Q_{B'}\) qui préserve les transitions de \(A'\) et dont la réciproque préserve également les transitions de \(B'\) ? De manière surprenante, les automates réduits sont égaux et ne dépendent pas de l'automate initial, autrement dit un automate réduit est nécessairement l'automate minimal.
Travail personnel
Vous devrez me renvoyer une archive .tgz à votre nom contenant les sources de vos programmes, les explications et les réponses aux questions pour le vendredi 19 décembre 2014.