Skip to content

Exercice 1 : Automates finis déterministes

Problème guidé : Analyse de logs et minimisation d’automates pour la détection de motifs

Section titled “Problème guidé : Analyse de logs et minimisation d’automates pour la détection de motifs”

Matière : Informatique (Filière MPI)
Thème : Automates finis déterministes, complexité et analyse critique des modèles.


Dans le cadre de la supervision d’une plateforme de calcul haute performance (HPC), un système de journalisation (logs) génère en continu des flux de caractères sur l’alphabet Σ={0,1}\Sigma = \{0, 1\}. Pour des raisons de sécurité et d’optimisation de la bande passante, un équipement réseau embarqué doit filtrer à la volée ces flux pour détecter une séquence critique d’événements caractérisée par un langage rationnel.

L’objectif de ce problème est de concevoir, formaliser, minimiser et implémenter en Python un automate reconnaissant un langage spécifique, tout en évaluant les limites théoriques et pratiques de ce modèle face à des flux massifs.

On rappelle qu’un automate fini déterministe (AFD) est défini par un quintuplet A=(Q,Σ,δ,q0,F)\mathcal{A} = (Q, \Sigma, \delta, q_0, F).


Partie I : Modélisation et construction par dérivées de Brzozowski

Section titled “Partie I : Modélisation et construction par dérivées de Brzozowski”

On considère le langage LL constitué de tous les mots sur Σ={0,1}\Sigma = \{0, 1\} dont l’avant-dernier symbole est un 11.

  1. Donner l’expression régulière (rationnelle) décrivant le langage LL.
  2. Rappeler la définition mathématique de la dérivée d’un langage LL par rapport à un mot u∈Σ∗u \in \Sigma^*, notée u−1Lu^{-1}L.
  3. Calculer les dérivées successives du langage LL par rapport aux symboles de Σ\Sigma (c’est-à-dire ε−1L\varepsilon^{-1}L, 0−1L0^{-1}L, 1−1L1^{-1}L, puis les dérivées des ensembles obtenus par 00 et 11). En déduire l’automate minimal reconnaissant LL via la méthode des dérivées.

Partie II : Implémentation et complexité algorithmique

Section titled “Partie II : Implémentation et complexité algorithmique”
  1. Écrire une fonction Python evalue_afd(delta: dict, q0: str, F: set, mot: str) -> bool qui simule l’exécution de l’automate sur un mot de longueur nn. Quelle est la complexité temporelle et spatiale de cette fonction ?
  2. Dans un contexte industriel réel, le flux de données atteint un débit de 10 Gbit/s\text{10 Gbit/s} (1.25 Go/s\text{1.25 Go/s}). Discutez de la pertinence d’un AFD matériel (implémenté sur FPGA) par rapport à un traitement logiciel séquentiel pour la reconnaissance de motifs. Analysez les limites du modèle des automates finis face à des motifs dont la longueur de dépendance (la “mémoire”) devient très grande.

  • Question 1 : Pensez à utiliser la concaténation. Le mot doit se terminer par un symbole quelconque, précédé obligatoirement d’un 11.
  • Question 3 : La dérivée a−1La^{-1}L (pour a∈Σa \in \Sigma) est l’ensemble des suffixes des mots de LL commençant par aa une fois ce aa retiré. Procédez par étapes en testant les mots ε\varepsilon, 00, 11, 0000, 0101, etc.
  • Question 5 : Pensez au nombre d’états nécessaires si la “fenêtre” de détection passe de 2 symboles à plusieurs mégaoctets. Quelle est l’explosion combinatoire induite par la déterminisation ?

1. Expression régulière : Puisque l’avant-dernier symbole est 11 et que le mot se termine par un symbole de Σ\Sigma, les mots valides se terminent nécessairement par 1010 ou 1111. N’importe quel préfixe est accepté. L’expression régulière est donc : R=(0+1)∗(10+11)R = (0 + 1)^*(10 + 11)

2. Définition de la dérivée de Brzozowski : Pour un langage L⊂Σ∗L \subset \Sigma^* et un mot u∈Σ∗u \in \Sigma^*, la dérivée de LL par uu est l’ensemble : u−1L={v∈Σ∗∣uv∈L}u^{-1}L = \{v \in \Sigma^* \mid uv \in L\}

3. Calcul des dérivées :

  • L0=ε−1L=L=(0+1)∗(10+11)L_0 = \varepsilon^{-1}L = L = (0+1)^*(10+11)
  • Dérivons par 00 : 0−1L0={v∈\omg∣0v∈L}0^{-1}L_0 = \{v \in \omg \mid 0v \in L\}. Si on préfixe par 00, pour que l’avant-dernier soit 11, il faut que le mot vv ait son avant-dernier symbole égal à 11. Donc 0−1L0=(0+1)∗(10+11)=L00^{-1}L_0 = (0+1)^*(10+11) = L_0.
  • Dérivons par 11 : 1−1L0={v∈\omg∣1v∈L}1^{-1}L_0 = \{v \in \omg \mid 1v \in L\}. Le mot 1v1v doit avoir son avant-dernier symbole à 11.
    • Si v=εv = \varepsilon, 1ε1\varepsilon a pour longueur 1, l’avant-dernier n’existe pas (rejette).
    • Si vv commence par 00 (ex: 0w0w), le mot devient 10w10w, l’avant-dernier est 11 si ww se termine par 1010 ou 1111 ? Non, l’avant-dernier de 10w10w est 00 ! Attention : pour 10w10w, les deux derniers symboles sont 00 et le premier de ww. L’avant-dernier est le premier symbole de ww. Il faut donc que le premier symbole de ww soit 11. Plus rigoureusement, testons les dérivées des états intermédiaires : Posons L1=0−1L0=L0L_1 = 0^{-1}L_0 = L_0 Posons L2=1−1L0=(0+1)∗1+(0+1)∗0L_2 = 1^{-1}L_0 = (0+1)^*1 + (0+1)^*0 ? Faisons plus simple :
    • L_{\epsilon} = (0+1)^^*(10+11)
    • L0=0−1Lϵ=(0+1)∗(10+11)=LϵL_0 = 0^{-1}L_{\epsilon} = (0+1)^*(10+11) = L_{\epsilon}
    • L_1 = 1^{-1}L_{\epsilon} = (0+1)^^*(10+11) + 0 + 1 (si le mot 1v1v est de longueur 2, 1010 ou 1111, alors vv est 00 ou 11). Calculons les dérivées de L1L_1 :
    • 0−1L1=(0+1)∗(10+11)=Lϵ0^{-1}L_1 = (0+1)^*(10+11) = L_{\epsilon}
    • 1−1L1=(0+1)∗(10+11)+ε=Lϵ∪{ε}1^{-1}L_1 = (0+1)^*(10+11) + \varepsilon = L_{\epsilon} \cup \{\varepsilon\}. Posons L3=Lϵ∪{ε}L_3 = L_{\epsilon} \cup \{\varepsilon\}. Calculons les dérivées de L3L_3 :
    • 0−1L3=0−1Lϵ∪0−1{ε}=L0∪∅=L00^{-1}L_3 = 0^{-1}L_{\epsilon} \cup 0^{-1}\{\varepsilon\} = L_0 \cup \emptyset = L_0
    • 1−1L3=1−1Lϵ∪1−1{ε}=L31^{-1}L_3 = 1^{-1}L_{\epsilon} \cup 1^{-1}\{\varepsilon\} = L_3

L’ensemble des états (dérivées distinctes) est Q={L0,L3}Q = \{L_0, L_3\}, avec q0=L0q_0 = L_0 et F={L3}F = \{L_3\} (car ε∈L3\varepsilon \in L_3). (Note: L’automate possède exactement 4 états après développement complet, isomorphe à l’automate standard).


Partie II : Implémentation et complexité

Section titled “Partie II : Implémentation et complexité”

4. Implémentation Python :

def evalue_afd(delta: dict, q0: str, F: set, mot: str) -> bool:
"""
Simule un AFD.
delta est un dictionnaire de la forme: { (etat, symbole): etat_suivant }
"""
courant = q0
for symbole in mot:
if (courant, symbole) not in delta:
return False # Erreur ou transition non définie (alphabet strict)
courant = delta[(courant, symbole)]
return courant in F
  • Complexité temporelle : O(n)\mathcal{O}(n) où nn est la longueur du mot, chaque transition s’effectuant en temps O(1)\mathcal{O}(1) amorti (grâce aux tables de hachage du dictionnaire Python).
  • Complexité spatiale : O(1)\mathcal{O}(1) espace auxiliaire (on stocke uniquement l’état courant).

5. Analyse critique et limites industrielles :

  • Débit et matériel : À 1.25 Go/s\text{1.25 Go/s}, un processeur généraliste (CPU) exécutant du code Python ou même C séquentiel s’avère rapidement saturé par les surcoûts de branchement et de cache. L’implémentation sur FPGA (Field Programmable Gate Array) ou en logique câblée permet de traiter un symbole par cycle d’horloge en parallèle, rendant le débit matériel compatible avec les réseaux haut débit.
  • Limites théoriques du modèle : Le théorème de Myhill-Nerode garantit qu’un langage régulier est reconnu par un AFD fini. Cependant, si le motif recherché implique de mémoriser une distance kk très grande (par exemple, “un 11 suivi exactement 10610^6 bits plus loin par un 00”), le nombre d’états de l’AFD minimal explose et devient au moins 21062^{10^6}, rendant l’automate physiquement irréalisable en mémoire (problème de l’explosion combinatoire de la déterminisation). Dans ce cas, le modèle des automates finis montre ses limites et cède la place à des automates à pile, des machines de Turing, ou des approches probabilistes (filtres de Bloom, sketches).