cursus.

Cours 2 · Langages réguliersLeçon 2 sur 4

Automates non déterministes

5 h de lecture8 sections Version PDF

À la fin de cette leçon, vous saurez

AFN et ε-transitions ; déterminisation par construction des sous-ensembles ; équivalence AFD/AFN — le premier point qui coince.

Le chapitre 3 a montré comment construire un AFD, et aussi sa difficulté : son déterminisme force à tout anticiper. Pour reconnaître « les mots qui se terminent par abab », il faut prévoir, à chaque aa lu, qu'il pourrait être l'avant-dernière lettre — sans le savoir encore. Cette gymnastique est pénible et source d'erreurs.

L'automate non déterministe supprime cette gêne : il s'autorise à « deviner ». Il est bien plus facile à écrire — et c'est là qu'est le miracle du chapitre : cette liberté ne coûte aucune puissance. Tout automate non déterministe se transforme mécaniquement en AFD équivalent. La transformation s'appelle la déterminisation, et c'est le premier des deux points qui coincent de l'année. Il devient mécanique dès qu'on l'a fait tourner une fois — ce que fait l'exercice.

L'automate non déterministe

Un automate fini non déterministe (AFN) a la même définition qu'un AFD, à une différence près, mais décisive : la fonction de transition rend un ensemble d'états.

δ:Q×ΣP(Q).\delta : Q \times \Sigma \to \mathcal{P}(Q).

Depuis un état qq en lisant une lettre aa, l'automate peut avoir plusieurs transitions possibles — ou aucune. Concrètement :

  • δ(q,a)={q1,q2}\delta(q, a) = \{q_1, q_2\} : deux choix possibles ;
  • δ(q,a)=\delta(q, a) = \emptyset : aucune transition — ce chemin meurt.

La règle d'acceptation change en conséquence, et c'est le point le plus important à comprendre :

Un AFN accepte un mot s'il existe au moins un chemin menant de l'état initial à un état acceptant.

Un seul chemin gagnant suffit. On peut imaginer l'automate explorant tous les chemins à la fois, en parallèle, et acceptant si l'un d'eux réussit. C'est cette lecture — « il existe un chemin » — qui rend les AFN si commodes : on écrit les transitions « utiles » et on laisse mourir les autres, sans se soucier d'un état puits.

Reprenons « se termine par abab » en non déterministe :

        a, b       ┌──┐       ▼  │   ──▶( q0 )──a──▶( q1 )──b──▶(( q2 ))

En q0q_0, lire aa offre deux choix : boucler sur q0q_0 (« ce aa n'est pas le bon »), ou partir vers q1q_1 (« je parie que le abab final commence ici »). L'automate n'a pas à trancher : si le pari est bon, le chemin q0q1q2q_0 \to q_1 \to q_2 existe et le mot est accepté. Comparez à l'AFD du chapitre 3, où il fallait gérer explicitement chaque cas : l'AFN dit simplement ce qu'on veut reconnaître.

L'animation déroule la lecture de aab. Observez la nouveauté par rapport au chapitre 3 : l'état courant n'est plus unique mais un ensemble — l'automate explore tous les chemins à la fois, et accepte dès que l'un d'eux atteint un état acceptant. À la fin, l'ensemble contient q2 : le mot est accepté. C'est déjà, en germe, l'idée de la déterminisation.

Animation · étape 1 / 50:00 / 0:11

L'automate démarre dans l'état {q0}. Mot à lire : « aab ». En non déterministe, on suit tous les chemins à la fois.

Prêt à lancer · 0:00 / 0:11
Étapes

Les ε-transitions

Les AFN se dotent souvent d'un raccourci supplémentaire : les ε-transitions, des flèches étiquetées par le mot vide ε\varepsilon. Elles permettent de changer d'état sans lire aucune lettre.

( q1 )──ε──▶( q2 )

Leur intérêt est purement pratique : elles servent à assembler des automates comme des pièces de Lego — brancher la sortie de l'un sur l'entrée d'un autre par une ε-transition, sans se soucier de raccorder les transitions. C'est exactement ce dont le chapitre 5 aura besoin pour construire un automate à partir d'une expression régulière (construction de Thompson).

Pour raisonner avec elles, on introduit l'ε-fermeture d'un état : l'ensemble de tous les états atteignables en ne suivant que des ε-transitions (y compris l'état lui-même). On l'intègre à la déterminisation ; l'idée générale reste la même, on ajoute simplement « et tout ce qu'on peut atteindre gratuitement par des ε\varepsilon ».

Quiz · vérifiez votre compréhension Sans réponse

Un AFN, sur le mot w, possède trois chemins possibles depuis l'état initial : deux se bloquent (δ vide en cours de route) et un seul atteint un état acceptant. Le mot w est-il accepté ?

La déterminisation : construction des sous-ensembles

Comment exécuter un automate qui « devine » sur une machine réelle, qui elle ne devine pas ? En le transformant en AFD. L'idée est d'une élégance qu'il faut avoir comprise une fois pour toutes :

Un état de l'AFD représente l'ensemble de tous les états où l'AFN pourrait se trouver après avoir lu le préfixe courant.

Le non-déterminisme « où suis-je ? — plusieurs réponses possibles » devient un déterminisme « je suis dans cet ensemble d'états — une seule réponse ». La question redevient à réponse unique, donc déterministe. La construction, dite des sous-ensembles, procède ainsi :

  1. L'état initial de l'AFD est {q0}\{q_0\} (avec son ε-fermeture s'il y a des ε-transitions).
  2. Depuis un état-ensemble EE, en lisant une lettre aa, on va dans l'union des δ(e,a)\delta(e, a) pour tous les eEe \in E : « tous les états où l'on peut arriver ».
  3. Un état-ensemble est acceptant dès qu'il contient au moins un état acceptant de l'AFN — parce qu'il suffit qu'un chemin possible soit gagnant.
  4. On ne construit que les ensembles réellement atteignables, en partant de {q0}\{q_0\} et en suivant les transitions.

Le point 3 est le plus souvent raté : on accepte dès qu'un des états possibles est acceptant, pas quand ils le sont tous. C'est le reflet direct de la règle existentielle de l'AFN.

Le coût, et l'équivalence

Combien d'états peut avoir le déterminisé ? Ses états sont des sous-ensembles de QQ. Si l'AFN a nn états, il y a au plus 2n2^n sous-ensembles — c'est le 2n2^n de l'ensemble des parties du chapitre 2, qui se manifeste enfin. C'est le prix théorique du non-déterminisme : la déterminisation peut faire exploser le nombre d'états.

Deux nuances tempèrent cette borne. En pratique, on ne construit que les ensembles atteignables, et ils sont presque toujours bien moins nombreux que 2n2^n — dans l'exercice, 3 sur 8. Mais le pire cas existe réellement : certains langages exigent bel et bien un nombre exponentiel d'états une fois déterminisés, et c'est pourquoi on garde parfois l'AFN tel quel.

Au-delà du coût, la conséquence est le théorème central du chapitre :

Tout AFN peut être transformé en un AFD reconnaissant le même langage. AFD et AFN reconnaissent donc exactement la même classe de langages : les langages réguliers.

Le non-déterminisme est plus commode à écrire, jamais plus puissant. C'est un confort de conception, pas une extension du modèle — et c'est un résultat profond, car on aurait pu croire le contraire.

Quiz · vérifiez votre compréhension Sans réponse

Un AFN a 4 états. Après déterminisation par construction des sous-ensembles, combien d'états l'AFD obtenu peut-il avoir au maximum, et pourquoi ne les atteint-on presque jamais tous ?

À vous

L'exercice fait tomber le blocage en rendant l'algorithme mécanique : vous implémentez la construction des sous-ensembles, puis vous la faites tourner sur l'AFN de « se termine par abab ». Vous voyez les états du déterminisé apparaître comme des ensembles {q0}\{q_0\}, {q0,q1}\{q_0, q_1\}, {q0,q2}\{q_0, q_2\} — et la règle « acceptant = contient un acceptant » cesse d'être abstraite.

Codez-le, exécutez-le, relisez la trace : la déterminisation n'est plus un mystère mais une procédure que vous savez dérouler à la main.

Exercice · JavaScript · à vous de jouer

Implémentez la déterminisation par construction des sous-ensembles : chaque état de l'AFD est l'ensemble des états où l'AFN peut se trouver. Faites-la tourner sur l'AFN de « se termine par ab » et lisez le résultat — c'est le point qui coince, il devient mécanique une fois codé.

En attente
// Un AFN reconnaît L = { mots sur {a,b} se terminant par 'ab' }.
// Non déterminisme : depuis q0, lire 'a' peut RESTER en q0 (boucle) OU aller
// en q1 (parier que le 'ab' final commence ici). δ rend un ENSEMBLE d'états.

const afn = {
  etats: ["q0", "q1", "q2"],
  alphabet: ["a", "b"],
  initial: "q0",
  acceptants: ["q2"],
  // delta[etat][lettre] = LISTE d'états (peut être vide, ou à plusieurs)
  delta: {
    q0: { a: ["q0", "q1"], b: ["q0"] },   // le choix est ici
    q1: { a: [],           b: ["q2"] },   // depuis q1, un 'b' complète "ab"
    q2: { a: [],           b: []      },
  },
};

// ── Outil : δ étendu à un ENSEMBLE d'états ──────────────────────────────────
// Depuis un ensemble E d'états, en lisant 'lettre', où peut-on être ?
// Réponse : l'union des δ(e, lettre) pour tout e dans E.
function transitionEnsemble(afn, ensemble, lettre) {
  const arrivee = new Set();
  for (const e of ensemble)
    for (const cible of afn.delta[e][lettre])
      arrivee.add(cible);
  return [...arrivee].sort();
}

// ── À VOUS : la construction des sous-ensembles ─────────────────────────────
// Construire l'AFD dont les états sont des ENSEMBLES d'états de l'AFN.
//   - état initial de l'AFD = { initial de l'AFN }
//   - depuis un état-ensemble, δ_AFD(E, lettre) = transitionEnsemble(...)
//   - un état-ensemble est acceptant s'il CONTIENT un acceptant de l'AFN
//   - on n'explore que les ensembles ATTEIGNABLES (pas les 2^n en aveugle)
function determiniser(afn) {
  const nom = (E) => "{" + E.join(",") + "}";
  const initial = [afn.initial];
  const aTraiter = [initial];
  const vus = new Set([nom(initial)]);
  const deltaAFD = {};
  const acceptantsAFD = [];

  while (aTraiter.length > 0) {
    const E = aTraiter.shift();
    // à compléter :
    //  1. si E contient un état de afn.acceptants, ajouter nom(E) aux acceptants
    //  2. pour chaque lettre, calculer l'ensemble d'arrivée A
    //     enregistrer deltaAFD[nom(E)][lettre] = nom(A)
    //     si nom(A) jamais vu, l'ajouter à 'vus' et 'aTraiter'
  }
  return { initial: nom(initial), acceptants: acceptantsAFD, delta: deltaAFD };
}

// ── Vérification ────────────────────────────────────────────────────────────
const afd = determiniser(afn);
console.log("État initial :", afd.initial);
console.log("Acceptants   :", afd.acceptants.join(" "));
console.log("Transitions :");
for (const [E, trans] of Object.entries(afd.delta))
  for (const [l, A] of Object.entries(trans))
    console.log("  " + E + " --" + l + "--> " + A);

Console de sortie
Le résultat s'affiche dans la console

Ce que la suite en fait

Vous disposez maintenant de deux descriptions équivalentes des langages réguliers : l'AFD (exécutable, efficace) et l'AFN (facile à écrire), reliés par la déterminisation.

Le chapitre 5 en ajoute une troisième, purement textuelle : les expressions régulières, celles que vous croisez déjà dans les éditeurs et les outils de recherche. Le théorème de Kleene établira qu'elles décrivent exactement les mêmes langages que les automates — et la construction de Thompson, qui traduit une expression en automate, s'appuiera précisément sur les ε-transitions vues ici pour assembler les pièces.

À retenir

Flashcards · 1 / 4Toucher pour retourner

Exercices d'entraînement

Exercice 1 · cherchez avant de lire la correction

Déterminiser un AFN

Soit l'AFN sur Σ={a,b}\Sigma = \{a, b\} reconnaissant « les mots contenant le facteur ab » : états q0 (initial), q1, q2 (acceptant), avec δ(q0,a)={q0,q1},δ(q0,b)={q0},δ(q1,b)={q2},δ(q2,a)=δ(q2,b)={q2}.\delta(q_0, a) = \{q_0, q_1\},\quad \delta(q_0, b) = \{q_0\},\quad \delta(q_1, b) = \{q_2\},\quad \delta(q_2, a) = \delta(q_2, b) = \{q_2\}. Déterminiser par la construction des sous-ensembles. Quels états-ensembles sont acceptants ?

Exercice 2 · cherchez avant de lire la correction

ε-fermeture

Un AFN possède les états A, B, C et les transitions AεBA \xrightarrow{\varepsilon} B, BεCB \xrightarrow{\varepsilon} C, AaAA \xrightarrow{a} A. Donner l'ε-fermeture de A.

Exercice 3 · cherchez avant de lire la correction

Le non-déterminisme, plus concis

Donner un AFN à 33 états pour « l'avant-dernière lettre du mot est a » sur Σ={a,b}\Sigma = \{a, b\}. Combien d'états son AFD déterminisé possède-t-il ?

Fin de la leçon

Vous avez parcouru les 8 sections.

Marquez-la terminée pour faire avancer votre parcours, ou revenez sur un point avant de passer à la suite.