Automates non déterministesDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Théorie des langages · C2 Langages réguliers · Chapitre 2 · 5 h

Automates non déterministes

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 :

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 · 5 étapes

Un AFN lit « aab » : se termine par ab ?

  1. État initialL'automate démarre dans l'état {q0}. Mot à lire : « aab ». En non déterministe, on suit tous les chemins à la fois.
  2. Lecture de « a » (1/3)Depuis {q0}, la lettre « a » mène à {q0, q1}.
  3. Lecture de « a » (2/3)Depuis {q0, q1}, la lettre « a » mène à {q0, q1}.
  4. Lecture de « b » (3/3)Depuis {q0, q1}, la lettre « b » mène à {q0, q2}.
  5. Mot acceptéTout le mot est lu et l'état d'arrivée {q0, q2} contient un état acceptant (q2) : le mot « aab » appartient au langage.

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 · 1 question

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é ?

  • Non : deux chemins sur trois échouent, la majorité l'emportemajorité
  • Oui : il suffit qu'il EXISTE un chemin menant à un état acceptantexistence d'un chemin
  • Cela dépend de l'ordre dans lequel on explore les cheminsordre d'exploration

Réponse : La règle d'acceptation d'un AFN est existentielle : le mot est accepté dès qu'IL EXISTE au moins un chemin de l'état initial vers un état acceptant. Les chemins qui se bloquent ou finissent hors de F ne comptent pas — un seul chemin gagnant suffit. L'ordre d'exploration est sans effet sur le résultat (il n'affecte que la manière de le calculer). C'est cette souplesse « il existe un chemin » qui rend les AFN faciles à écrire.

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 · 1 question

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 ?

  • 4 états, car la déterminisation préserve le nombre d'étatspréservation
  • 2⁴ = 16 au maximum (les sous-ensembles des 4 états), mais on ne construit que les ensembles atteignables, souvent bien moins nombreux2ⁿ sous-ensembles, atteignables seulement
  • 8 états, soit le double, à cause du non-déterminismele double

Réponse : Les états de l'AFD sont les sous-ensembles de l'ensemble des états de l'AFN : au plus 2⁴ = 16, la taille de l'ensemble des parties (chapitre 2). Mais la construction ne crée que les ensembles réellement atteignables depuis {q0} en suivant les transitions ; les autres n'apparaissent jamais. En pratique on en obtient souvent une poignée. Le pire cas exponentiel existe cependant pour certains langages — d'où l'intérêt de parfois conserver l'AFN.

À 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 de code

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é.

Point de départ

// 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);

Solution

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();
    deltaAFD[nom(E)] = {};
    // 1. acceptant si E contient AU MOINS un acceptant de l'AFN
    if (E.some((e) => afn.acceptants.includes(e))) acceptantsAFD.push(nom(E));
    // 2. une transition par lettre, vers l'ensemble atteignable
    for (const lettre of afn.alphabet) {
      const A = transitionEnsemble(afn, E, lettre);
      deltaAFD[nom(E)][lettre] = nom(A);
      if (!vus.has(nom(A))) { vus.add(nom(A)); aTraiter.push(A); }
    }
  }
  return { initial: nom(initial), acceptants: acceptantsAFD, delta: deltaAFD };
}

// ── Résultat, lu comme un AFD ───────────────────────────────────────────────
//   {q0}      --a--> {q0,q1}   --b--> {q0}
//   {q0,q1}   --a--> {q0,q1}   --b--> {q0,q2}   <- acceptant (contient q2)
//   {q0,q2}   --a--> {q0,q1}   --b--> {q0}
//
// L'AFN avait 3 états ; le déterminisé en a 3 ATTEIGNABLES sur 2^3 = 8
// possibles. On n'a exploré que les ensembles réellement atteints — c'est ce
// qui évite l'explosion dans la pratique.
//
// ── La clé pour ne plus être bloqué ─────────────────────────────────────────
//
// 1. Un état de l'AFD = « l'ENSEMBLE de tous les états où l'AFN pourrait se
//    trouver après avoir lu ce préfixe ». Le non-déterminisme « où suis-je ?
//    plusieurs réponses » devient un déterminisme « je suis dans CET ensemble,
//    une seule réponse ». C'est toute l'idée.
//
// 2. Acceptant = l'ensemble contient AU MOINS un acceptant de l'AFN. Car
//    l'AFN accepte s'il EXISTE un chemin acceptant : il suffit qu'un des états
//    possibles soit acceptant.
//
// 3. Au pire 2^n états (l'ensemble des parties, chapitre 2), mais on ne
//    construit que les ATTEIGNABLES — souvent bien moins. Le pire cas existe
//    pourtant réellement, et c'est pourquoi on préfère parfois garder l'AFN.
//
// 4. Conséquence théorique majeure : AFN et AFD reconnaissent EXACTEMENT les
//    mêmes langages. Le non-déterminisme est plus COMMODE à écrire, jamais
//    plus PUISSANT. C'est l'équivalence AFD/AFN.

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 · 4 cartes

En quoi un AFN diffère-t-il d'un AFD, et quelle est sa règle d'acceptation ?
La transition rend un ENSEMBLE d'états : δ : Q×Σ → P(Q). Depuis un état, une lettre peut mener à plusieurs états, ou à aucun (le chemin meurt). Un AFN accepte un mot s'il EXISTE au moins un chemin de l'état initial vers un état acceptant — un seul chemin gagnant suffit. Cette souplesse existentielle rend les AFN faciles à écrire.
À quoi servent les ε-transitions ?
Ce sont des flèches étiquetées par ε : elles changent d'état SANS lire de lettre. Leur usage est pratique — assembler des automates comme des pièces (brancher la sortie de l'un sur l'entrée d'un autre), ce dont la construction de Thompson (chapitre 5) a besoin. Pour raisonner, on utilise l'ε-fermeture : tous les états atteignables en ne suivant que des ε-transitions.
Sur quel principe repose la déterminisation par construction des sous-ensembles ?
Un état de l'AFD = l'ENSEMBLE de tous les états où l'AFN pourrait se trouver après le préfixe lu. Initial : {q0}. Transition : union des δ(e,a) pour e dans l'ensemble. Acceptant : l'ensemble CONTIENT au moins un acceptant de l'AFN (règle existentielle). On ne construit que les ensembles atteignables. Le non-déterminisme « plusieurs réponses » devient « je suis dans cet ensemble », donc déterministe.
Quel est le coût de la déterminisation, et qu'établit l'équivalence AFD/AFN ?
Au pire 2ⁿ états (les sous-ensembles des n états — l'ensemble des parties), mais en pratique on ne crée que les atteignables, souvent bien moins ; le pire cas exponentiel existe cependant pour certains langages. Équivalence : tout AFN se transforme en AFD reconnaissant le même langage. AFN et AFD reconnaissent exactement les langages réguliers — le non-déterminisme est plus commode, jamais plus puissant.

Exercices d'entraînement

Exercice 1

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 ?

Correction

On part de {q0}\{q_0\} et on ne construit que les ensembles atteignables :

ensembleab
{q0}\{q_0\}{q0,q1}\{q_0, q_1\}{q0}\{q_0\}
{q0,q1}\{q_0, q_1\}{q0,q1}\{q_0, q_1\}{q0,q2}\{q_0, q_2\}
{q0,q2}\{q_0, q_2\}{q0,q1,q2}\{q_0, q_1, q_2\}{q0,q2}\{q_0, q_2\}
{q0,q1,q2}\{q_0, q_1, q_2\}{q0,q1,q2}\{q_0, q_1, q_2\}{q0,q2}\{q_0, q_2\}

L'AFD a 44 états atteignables (sur 23=82^3 = 8 possibles). Sont acceptants ceux qui contiennent q2 : {q0,q2}\{q_0, q_2\} et {q0,q1,q2}\{q_0, q_1, q_2\} — car un ensemble accepte dès qu'un état acceptant y figure.

Exercice 2

ε-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.

Correction

L'ε-fermeture d'un état est l'ensemble des états atteignables en ne suivant que des ε-transitions, l'état lui-même inclus. Depuis A : on s'y trouve, on atteint B par ε\varepsilon, puis C par ε\varepsilon. La transition AaAA \xrightarrow{a} A n'est pas une ε-transition et ne compte pas. ε-fermeture(A)={A,B,C}.\varepsilon\text{-fermeture}(A) = \{A, B, C\}.

Exercice 3

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 ?

Correction

AFN : état q0 (initial) qui boucle sur a et b, une transition q0aq1q_0 \xrightarrow{a} q_1 (on devine que ce a est l'avant-dernière lettre), puis q1aq2q_1 \xrightarrow{a} q_2 et q1bq2q_1 \xrightarrow{b} q_2, avec q2 acceptant. Trois états suffisent — c'est le pari commode du non-déterminisme.

Le déterminisé a 44 états atteignables (les sous-ensembles {q0}\{q_0\}, {q0,q1}\{q_0,q_1\}, {q0,q1,q2}\{q_0,q_1,q_2\}, {q0,q2}\{q_0,q_2\}). C'est l'illustration du coût de la déterminisation : ici modéré, mais en généralisant à « la kk-ième lettre avant la fin », l'AFN garde k+1k+1 états quand l'AFD en exige 2k2^k.