C1 — FondementsDans le dialogue d’impression, choisissez « Enregistrer au format PDF » comme destination.
Retour

Licence 2 · Théorie des langages

Cours 1Fondements

Manier les mots et les langages comme des objets mathématiques, et se doter des outils de preuve — induction, récurrence — dont dépend tout le cours.

2 chapitres · 10 h de travail estimé

  1. 1. Mots et langages5 h
  2. 2. Rappels mathématiques utiles5 h

Chapitre 1 · 5 h

Mots et langages

Alphabet, mot, longueur, mot vide ; concaténation, préfixe, suffixe, facteur ; le langage comme ensemble de mots ; union, concaténation, étoile de Kleene ; dénombrer les mots.

Un compilateur, un moteur de recherche, un validateur de formulaire, un correcteur orthographique : tous partagent une même question, posée des milliards de fois par seconde. Une suite de caractères appartient-elle à un ensemble décrit à l'avance — les programmes C corrects, les adresses de courriel valides, les nombres bien formés ?

Répondre à cette question, c'est tout le cours. Mais avant de décider si un mot appartient à un langage, il faut définir avec une précision totale ce qu'est un mot, ce qu'est un langage, et ce qu'on a le droit d'en faire. Ce premier chapitre pose ce vocabulaire. Il paraît élémentaire ; il ne l'est pas, et la moitié des erreurs de l'année viennent d'une définition mal assimilée ici — en particulier celle du mot vide.

Alphabet, mot, longueur

Un alphabet, noté Σ\Sigma, est un ensemble fini et non vide de symboles. Ce ne sont pas forcément des lettres : Σ={a,b}\Sigma = \{a, b\}, Σ={0,1}\Sigma = \{0, 1\}, l'ensemble des caractères ASCII, ou même un ensemble de mots entiers d'un langage de programmation traités comme des symboles uniques.

Un mot (ou chaîne) sur Σ\Sigma est une suite finie de symboles de Σ\Sigma. Sur Σ={a,b}\Sigma = \{a, b\}, abba et aaa sont des mots ; abc n'en est pas un, car c n'appartient pas à l'alphabet.

La longueur d'un mot uu, notée u|u|, est le nombre de symboles qui le composent : abba=4|abba| = 4. On peut aussi compter les occurrences d'un symbole donné : abbaa=2|abba|_a = 2.

Le cas particulier qui décide de tout : le mot vide, noté ε\varepsilon. C'est le mot de longueur zéro, ε=0|\varepsilon| = 0. Trois pièges à désamorcer immédiatement :

  • ε\varepsilon est un mot, au même titre que les autres. « De longueur nulle » ne veut pas dire « inexistant ».
  • ε\varepsilon \neq \emptyset. Le mot vide est un objet ; l'ensemble vide est un ensemble sans aucun élément. Confondre les deux est l'erreur la plus fréquente du cours.
  • ε\varepsilon n'est pas le symbole espace. Un espace est un symbole de longueur 1 comme un autre.

Préfixe, suffixe, facteur

Trois façons de « prendre un morceau » d'un mot ww :

NotionDéfinitionExemples sur abba
Préfixeun début de ww : w=uvw = u \cdot v, on garde uuε\varepsilon, a, ab, abb, abba
Suffixeune fin de wwε\varepsilon, a, ba, bba, abba
Facteurun morceau contigu, n'importe oùtous les précédents, plus b, bb

Remarquez que ε\varepsilon et ww lui-même sont toujours à la fois préfixe, suffixe et facteur de ww. Ce ne sont pas des cas dégénérés qu'on écarte : les définitions les incluent, et les preuves du cours s'appuient sur cette inclusion.

La concaténation

L'opération de base sur les mots est la concaténation : mettre bout à bout. On la note par un point, souvent omis :

uv=uvpar exempleabba=abba.u \cdot v = uv \qquad \text{par exemple} \quad ab \cdot ba = abba.

Deux propriétés structurent tout le reste, et méritent d'être énoncées comme telles.

Elle est associative : (uv)w=u(vw)(u \cdot v) \cdot w = u \cdot (v \cdot w). On peut donc écrire uvwuvw sans parenthèses.

Elle admet un élément neutre, et c'est ε\varepsilon : uε=εu=uu \cdot \varepsilon = \varepsilon \cdot u = u. C'est ici que le mot vide gagne son utilité — il joue pour la concaténation le rôle que zéro joue pour l'addition. Sans lui, la théorie serait pleine de cas particuliers.

En revanche, la concaténation n'est pas commutative : abbaab \neq ba en général. L'ordre des symboles est l'information portée par un mot.

Enfin, les longueurs s'ajoutent : uv=u+v|u \cdot v| = |u| + |v|. Cette égalité si simple est la clé des preuves par récurrence sur la longueur du chapitre suivant.

Quiz · 1 question

Parmi ces affirmations sur le mot vide ε sur l'alphabet Σ = {a, b}, laquelle est correcte ?

  • ε est identique à l'ensemble vide ∅mot vs ensemble
  • ε est un mot de longueur 0, et il vérifie u·ε = u pour tout mot ulongueur 0 et élément neutre
  • ε n'est pas un mot, c'est l'absence de motexistence

Réponse : ε est bel et bien un mot — le seul de longueur 0 — et il est l'élément neutre de la concaténation : u·ε = ε·u = u, exactement comme 0 pour l'addition. Il ne faut pas le confondre avec l'ensemble vide ∅, qui est un ensemble sans élément, alors que ε est un objet (un mot). Dire que ε « n'est pas un mot » interdirait de l'accepter dans un automate, ce qui casserait la moitié des constructions du cours.

Σ* : l'ensemble de tous les mots

On note Σ\Sigma^* l'ensemble de tous les mots que l'on peut former sur Σ\Sigma, y compris ε\varepsilon. C'est le terrain de jeu du cours entier.

Σ\Sigma^* est infini — il n'y a pas de mot le plus long — mais il est dénombrable : on peut énumérer ses éléments sans en oublier aucun, en les rangeant par longueur croissante. Sur Σ={a,b}\Sigma = \{a, b\} :

longueur 0 : εlongueur 1 : a, blongueur 2 : aa, ab, ba, bblongueur 3 : aaa, aab, aba, abb, baa, bab, bba, bbb...

Le comptage suit une logique simple : chaque mot de longueur nn s'obtient en plaçant l'une des Σ|\Sigma| lettres devant un mot de longueur n1n-1. Il y a donc exactement Σn|\Sigma|^n mots de longueur nn — 1, 2, 4, 8 sur un alphabet de deux lettres, comme dans la liste ci-dessus. Vous retrouverez cette formule par vous-même dans l'exercice, en la construisant plutôt qu'en la récitant.

Un langage est un ensemble de mots

Voici la définition centrale, et elle est d'une simplicité désarmante :

Un langage LL sur Σ\Sigma est un sous-ensemble de Σ\Sigma^*, c'est-à-dire LΣL \subseteq \Sigma^*.

Rien de plus. Un langage est un ensemble de mots — fini ou infini. Quelques exemples sur Σ={a,b}\Sigma = \{a, b\} :

  • L1={a,ab,abb}L_1 = \{a, ab, abb\} — un langage fini de trois mots ;
  • L2={ε}L_2 = \{\varepsilon\} — le langage qui ne contient que le mot vide (un élément) ;
  • L3=L_3 = \emptyset — le langage vide, aucun mot ;
  • L4={anbnn0}={ε,ab,aabb,aaabbb,}L_4 = \{a^n b^n \mid n \geq 0\} = \{\varepsilon, ab, aabb, aaabb b, \dots\} — un langage infini, qui reviendra hanter le chapitre 6 ;
  • L5L_5 = « tous les mots qui contiennent le facteur aa » — infini lui aussi.

Notez encore la distinction, cruciale et régulièrement ratée en examen : {ε}\{\varepsilon\} et \emptyset sont deux langages différents. Le premier contient un mot (le mot vide) ; le second n'en contient aucun. C'est la même différence qu'entre une boîte contenant une feuille blanche et une boîte vide.

Les opérations sur les langages

Comme les langages sont des ensembles, on hérite des opérations ensemblistes, plus deux opérations propres aux mots.

L'union L1L2L_1 \cup L_2, l'intersection L1L2L_1 \cap L_2 et le complément L=ΣL\overline{L} = \Sigma^* \setminus L sont les opérations ensemblistes habituelles.

La concaténation de langages étend celle des mots à tout l'ensemble :

L1L2={uvuL1, vL2}.L_1 \cdot L_2 = \{\, u \cdot v \mid u \in L_1,\ v \in L_2 \,\}.

On prend chaque mot du premier, chaque mot du second, on les colle. Si L1={a,ab}L_1 = \{a, ab\} et L2={b,c}L_2 = \{b, c\}, alors L1L2={ab,ac,abb,abc}L_1 \cdot L_2 = \{ab, ac, abb, abc\}.

Enfin, l'opération reine de la théorie, l'étoile de Kleene :

L={ε}LL2L3L^* = \{\varepsilon\} \cup L \cup L^2 \cup L^3 \cup \cdots

LnL^n est la concaténation de LL avec lui-même nn fois. Autrement dit, LL^* contient tous les mots obtenus en concaténant zéro, un ou plusieurs mots de LL. Le « zéro » est capital : εL\varepsilon \in L^* toujours, même si εL\varepsilon \notin L. C'est encore le mot vide qui se glisse dans la définition, et l'oublier fausse la moitié des exercices sur les expressions régulières du chapitre 5. La notation Σ\Sigma^* que vous employez depuis le début n'est d'ailleurs rien d'autre que l'étoile de Kleene appliquée à l'alphabet vu comme un langage de mots d'une lettre.

Quiz · 1 question

Soit L = {ab}. Lequel de ces mots n'appartient PAS à L* ?

  • ε (le mot vide)zéro copie de ab
  • abababtrois copies de ab
  • abales symboles vont-ils par paires ab ?

Réponse : L* contient tous les mots formés en concaténant zéro, un ou plusieurs exemplaires de ab : ε (zéro copie), ab, abab, ababab… Le mot vide en fait toujours partie, même si ε ∉ L. En revanche aba ne s'écrit pas comme une suite de blocs « ab » — il faudrait un a final orphelin. Il n'appartient donc pas à L*. Retenez que l'étoile inclut toujours ε, mais n'autorise que des concaténations entières de mots de L.

À vous

L'exercice est votre premier contact avec ces objets, en code. Vous implémentez les opérations de base — longueur, concaténation, préfixe — puis vous énumérez tous les mots de longueur nn sur un alphabet donné, et vous vérifiez que leur nombre vaut bien Σn|\Sigma|^n.

Le but n'est pas la programmation mais la définition : en écrivant concatener(u, ε), on comprend une fois pour toutes pourquoi ε\varepsilon est l'élément neutre, et en comptant les mots, on construit la formule au lieu de l'apprendre.

Exercice de code

Implémentez les opérations de base sur les mots (longueur, concaténation, préfixe), puis énumérez tous les mots de longueur n sur un alphabet donné. Vérifiez que leur nombre vaut |Σ|^n — et retrouvez pourquoi.

Point de départ

// Un mot est une suite finie de symboles pris dans un alphabet. En code, on
// le représente par une chaîne, et l'alphabet par un tableau de symboles.
const SIGMA = ["a", "b"];        // alphabet à 2 lettres
const MOT_VIDE = "";             // le mot vide, noté ε en cours (longueur 0)

// ── À VOUS (1) : les opérations de base ─────────────────────────────────────
function longueur(u) {
  return 0; // à compléter
}
function concatener(u, v) {
  return ""; // à compléter — attention : concatener(u, MOT_VIDE) doit rendre u
}
function estPrefixe(u, w) {
  // u est-il un préfixe de w ? (w commence-t-il par u ?)
  return false; // à compléter
}

// ── À VOUS (2) : dénombrer ──────────────────────────────────────────────────
// motsDeLongueur(n) doit rendre TOUS les mots de longueur n sur SIGMA.
// Combien y en a-t-il ? Vérifiez que |resultat| = |SIGMA|^n.
function motsDeLongueur(n) {
  return []; // à compléter (récursion ou boucle)
}

// ── Vérification ────────────────────────────────────────────────────────────
console.log("longueur('abba') =", longueur("abba"), "(attendu 4)");
console.log("concatener('ab','ba') =", concatener("ab", "ba"), "(attendu abba)");
console.log("concatener('ab', ε) =", "'" + concatener("ab", MOT_VIDE) + "'", "(attendu ab)");
console.log("estPrefixe('ab','abba') =", estPrefixe("ab", "abba"), "(attendu true)");
console.log("");
for (let n = 0; n <= 3; n++) {
  const m = motsDeLongueur(n);
  console.log("mots de longueur " + n + " : " + m.length + " -> [" + m.join(", ") + "]");
  console.log("   |SIGMA|^" + n + " = " + Math.pow(SIGMA.length, n));
}

Solution

function longueur(u) {
  return u.length;
}
function concatener(u, v) {
  return u + v;              // le mot vide est l'élément neutre : u·ε = ε·u = u
}
function estPrefixe(u, w) {
  return w.slice(0, u.length) === u;
}

function motsDeLongueur(n) {
  if (n === 0) return [MOT_VIDE];              // un seul mot de longueur 0 : ε
  const petits = motsDeLongueur(n - 1);        // les mots de longueur n-1
  const resultat = [];
  for (const m of petits)                      // devant chacun,
    for (const lettre of SIGMA)                // on place chaque lettre
      resultat.push(lettre + m);
  return resultat;
}

// ── Ce que l'exercice montre ────────────────────────────────────────────────
//
// 1. Le mot vide ε n'est PAS "rien" : c'est un mot, de longueur 0, et il est
//    l'élément neutre de la concaténation (u·ε = u). L'oublier fausse
//    récurrences et automates — la moitié des erreurs du cours viennent de là.
//
// 2. Le dénombrement suit une récurrence : chaque mot de longueur n s'obtient
//    en ajoutant UNE des |SIGMA| lettres devant un mot de longueur n-1. D'où
//        (nb de longueur n) = |SIGMA| × (nb de longueur n-1),  avec 1 pour n=0.
//    La solution de cette récurrence est |SIGMA|^n. On ne l'a pas récitée :
//    on l'a construite, et le code la vérifie (1, 2, 4, 8 sur un alphabet de 2).
//
// 3. Σ* — l'ensemble de TOUS les mots — est donc infini, mais DÉNOMBRABLE :
//    on peut les énumérer longueur par longueur, sans en oublier aucun. C'est
//    la première brique de tout le cours : un langage sera un sous-ensemble
//    de ce Σ*.

Ce que la suite en fait

Ce vocabulaire est le socle de tout. Le chapitre 2 se dote des outils pour prouver des propriétés sur ces objets — l'induction et la récurrence sur la longueur d'un mot, qui reposent directement sur l'égalité uv=u+v|uv| = |u| + |v| vue ici.

Ensuite, tout le cours consistera à décrire des langages — d'abord les plus simples, les langages réguliers, par des automates (chapitre 3) et des expressions régulières (chapitre 5) — et à comprendre ce que chaque outil peut et ne peut pas décrire. La question « ce mot appartient-il à ce langage ? » de l'introduction ne vous quittera plus.

À retenir

Flashcards · 4 cartes

Quelle est la différence entre ε, ∅ et {ε} ?
ε est le mot vide : un mot de longueur 0, élément neutre de la concaténation (u·ε = u). ∅ est le langage vide : un ensemble sans aucun mot. {ε} est le langage qui contient exactement un mot, le mot vide. ∅ et {ε} sont donc deux langages différents — l'un a zéro élément, l'autre en a un. Les confondre est l'erreur la plus fréquente du cours.
Qu'est-ce qu'un langage sur un alphabet Σ ?
Un sous-ensemble de Σ* : L ⊆ Σ*, c'est-à-dire un ensemble de mots, fini ou infini. Σ* est l'ensemble de TOUS les mots formables sur Σ (y compris ε) : il est infini mais dénombrable, et compte |Σ|^n mots de longueur n. Tout le cours consiste à décrire des langages et à cerner ce que chaque outil de description peut exprimer.
Que contient l'étoile de Kleene L*, et quel piège faut-il retenir ?
L* = {ε} ∪ L ∪ L² ∪ L³ ∪ … : tous les mots obtenus en concaténant zéro, un ou plusieurs mots de L. Le piège : ε ∈ L* TOUJOURS (la concaténation de zéro mot), même quand ε ∉ L. Oublier ce cas « zéro copie » fausse beaucoup d'exercices sur les expressions régulières.
Quelles sont les deux propriétés clés de la concaténation de mots ?
Elle est associative — (uv)w = u(vw), donc on écrit uvw sans parenthèses — et admet ε pour élément neutre — u·ε = ε·u = u. Elle n'est PAS commutative : ab ≠ ba en général. Et les longueurs s'ajoutent : |uv| = |u| + |v|, égalité sur laquelle reposent les preuves par récurrence sur la longueur du chapitre suivant.

Exercices d'entraînement

Exercice 1

Dénombrer des mots

On travaille sur l'alphabet Σ={a,b,c}\Sigma = \{a, b, c\}.

  1. Combien y a-t-il de mots de longueur exactement 33 ?
  2. Combien de mots de longueur au plus 33 (le mot vide compris) ?

Correction

  1. Chaque position se choisit indépendamment parmi Σ=3|\Sigma| = 3 lettres, donc il y a 33=273^3 = 27 mots de longueur 33.
  2. On additionne les mots de chaque longueur, sans oublier ε\varepsilon (longueur 00) : 30+31+32+33=1+3+9+27=40.3^0 + 3^1 + 3^2 + 3^3 = 1 + 3 + 9 + 27 = 40. Le terme 30=13^0 = 1 compte le seul mot de longueur nulle, le mot vide.

Exercice 2

Préfixes, suffixes, facteurs

Soit le mot w=abbaw = abba.

  1. Donner tous ses préfixes.
  2. Combien ww possède-t-il de facteurs distincts ?

Correction

  1. Un mot de longueur nn a exactement n+1n + 1 préfixes (on coupe avant chaque lettre, plus le mot entier). Ici : ε\varepsilon, a, ab, abb, abba — soit 55 préfixes.

  2. On compte les facteurs par longueur, en éliminant les doublons :

    • longueur 00 : ε\varepsilon11 ;
    • longueur 11 : a, b22 ;
    • longueur 22 : ab, bb, ba33 ;
    • longueur 33 : abb, bba22 ;
    • longueur 44 : abba11.

    Total : 1+2+3+2+1=91 + 2 + 3 + 2 + 1 = 9 facteurs distincts. La lettre a n'est comptée qu'une fois, bien qu'elle apparaisse deux fois dans ww — un facteur est un mot, pas une position.

Exercice 3

Opérations sur les langages

Soit L1={a,ab}L_1 = \{a, ab\} et L2={b,c}L_2 = \{b, c\}.

  1. Donner tous les mots de L1L2L_1 \cdot L_2.
  2. Le mot vide ε\varepsilon appartient-il à L1L_1^* ? Justifier.

Correction

  1. On concatène chaque mot de L1L_1 avec chaque mot de L2L_2 : L1L2={ab, ac, abb, abc}={ab, ac, abb, abc}.L_1 \cdot L_2 = \{a\cdot b,\ a\cdot c,\ ab\cdot b,\ ab\cdot c\} = \{ab,\ ac,\ abb,\ abc\}.
  2. Oui. Par définition, L1L_1^* contient la concaténation de zéro mot de L1L_1, qui vaut ε\varepsilon. C'est vrai pour tout langage, même quand εL1\varepsilon \notin L_1 — le piège classique de l'étoile de Kleene.

Chapitre 2 · 5 h

Rappels mathématiques utiles

Ensembles et relations, induction structurelle, récurrence sur la longueur d'un mot, et la notion de fonction de transition dont dépendent les automates.

Le chapitre 1 a défini les objets ; celui-ci fournit les outils pour raisonner dessus. Ce ne sont pas des rappels décoratifs : sans induction ni récurrence, on ne peut prouver aucun théorème du cours, et sans la notion de fonction, on ne peut pas définir un automate. Ce chapitre est court parce qu'il suppose des bases acquises — mais il isole précisément les points que la théorie des langages sollicite sans cesse, et où l'imprécision se paie plus tard.

Ensembles, un rappel ciblé

Un langage est un ensemble ; les opérations du chapitre 1 sont des opérations d'ensembles. Trois points méritent d'être fixés, parce qu'ils reviendront tels quels.

L'inclusion ABA \subseteq B signifie : tout élément de AA est élément de BB. Pour prouver ABA \subseteq B, on prend un élément quelconque de AA et on montre qu'il est dans BB. Pour prouver une égalité A=BA = B, la méthode standard est la double inclusion : ABA \subseteq B et BAB \subseteq A. C'est ainsi qu'on démontrera l'équivalence de deux automates, ou d'un automate et d'une expression régulière.

Le cardinal A|A| est le nombre d'éléments de AA. Un ensemble peut être fini, infini dénombrable (ses éléments peuvent être énumérés en liste, comme Σ\Sigma^*) ou non dénombrable. Cette distinction n'est pas anodine : elle est la clé d'un résultat surprenant vu plus bas.

L'ensemble des parties P(A)\mathcal{P}(A) est l'ensemble de tous les sous-ensembles de AA. Si AA a nn éléments, P(A)\mathcal{P}(A) en a 2n2^n. Retenez ce 2n2^n : il expliquera, au chapitre 4, pourquoi la déterminisation d'un automate peut faire exploser son nombre d'états.

Relations

Une relation sur un ensemble EE est un sous-ensemble de E×EE \times E : elle dit quels couples sont « en relation ». Une relation peut être réflexive, symétrique, transitive.

Le cas important pour le cours est la relation d'équivalence : réflexive, symétrique et transitive à la fois. Une telle relation partitionne EE en classes d'équivalence — des paquets disjoints qui recouvrent tout EE, où deux éléments sont dans le même paquet exactement quand ils sont en relation. Cette idée, abstraite pour l'instant, sera l'outil exact de la minimisation d'un automate au chapitre 6 : on regroupera les états « indistinguables » en une seule classe.

L'induction structurelle

Beaucoup d'objets du cours sont définis inductivement : on donne des cas de base, puis des règles pour construire des objets plus gros à partir d'objets plus petits. Le mot lui-même se définit ainsi :

  • base : ε\varepsilon est un mot ;
  • règle : si uu est un mot et aΣa \in \Sigma une lettre, alors aua \cdot u est un mot.

Tout mot s'obtient par un nombre fini d'applications de la règle à partir de la base. Les expressions régulières (chapitre 5) et les grammaires (chapitre 7) sont définies exactement de la même manière.

Quand un objet est défini inductivement, on le raisonne par induction structurelle : pour prouver qu'une propriété PP vaut pour tous les objets, il suffit de la prouver sur les cas de base, puis de montrer qu'elle se transmet par chaque règle de construction. C'est le même principe que la récurrence sur les entiers, appliqué à la structure de l'objet plutôt qu'à un nombre.

La récurrence sur la longueur d'un mot

C'est le schéma de preuve le plus employé du cours, et celui de l'exercice. Pour établir qu'une propriété P(u)P(u) est vraie pour tout mot uu, on procède par récurrence sur u|u| :

  1. Base : on prouve P(ε)P(\varepsilon) — la propriété pour le mot vide, de longueur 0.
  2. Hérédité : on suppose PP vraie pour tout mot de longueur nn (hypothèse de récurrence), et on en déduit PP pour un mot quelconque de longueur n+1n+1, généralement écrit u=awu = a \cdot w avec w=n|w| = n.

Comme tout mot a une longueur finie, ces deux étapes suffisent à couvrir Σ\Sigma^* tout entier. L'égalité uv=u+v|u \cdot v| = |u| + |v| du chapitre 1 est l'ingrédient qui fait fonctionner presque toutes ces récurrences.

Un point de méthode qui sépare les copies : le cas de base ne se néglige jamais. Oublier de traiter ε\varepsilon — parce qu'il « paraît évident » — est l'erreur classique, et souvent c'est précisément là que la propriété est la plus subtile à établir.

Quiz · 1 question

On veut prouver qu'une propriété P(u) est vraie pour tout mot u de Σ*, par récurrence sur |u|. Que doit contenir la preuve ?

  • Uniquement l'hérédité : montrer que si P(w) est vraie, alors P(a·w) l'esthérédité seule
  • Le cas de base P(ε), et l'hérédité : de P(w) pour |w| = n, déduire P(a·w) pour |w|+1base + hérédité
  • Vérifier P sur un grand nombre de mots choisis au hasardtests

Réponse : Une preuve par récurrence sur la longueur exige DEUX étapes : le cas de base P(ε), sans lequel rien n'est ancré, et l'hérédité qui transmet la propriété d'un mot de longueur n à un mot de longueur n+1. L'hérédité seule ne prouve rien — elle « suppose » P(w) sans jamais l'avoir établie quelque part. Et tester sur des exemples, même nombreux, ne couvre qu'un nombre fini de cas : cela peut suggérer une propriété, jamais la démontrer sur Σ*, qui est infini.

La fonction de transition

Dernier outil, et le plus tourné vers la suite. Une fonction f:ABf : A \to B associe à chaque élément de AA (le domaine) un élément de BB (le codomaine). « Un », pas « au moins un » ni « au plus un » : à chaque entrée correspond exactement une sortie.

L'objet central du cœur du cours est la fonction de transition d'un automate, qu'on notera δ\delta. Elle prendra un état et une lettre, et rendra un état :

δ:Q×ΣQ,δ(q,a)=q.\delta : Q \times \Sigma \to Q, \qquad \delta(q, a) = q'.

Lue à voix haute : « depuis l'état qq, en lisant la lettre aa, on va dans l'état qq' ». Toute la mécanique d'un automate déterministe (chapitre 3) tiendra dans cette fonction. Et c'est justement l'exigence de fonction — une seule sortie par entrée — qui distinguera le déterminisme du non-déterminisme : au chapitre 4, on relâchera cette contrainte, δ\delta rendra un ensemble d'états, et l'on ne parlera plus de fonction au sens strict mais de relation. Toute la difficulté de la déterminisation viendra de ce basculement.

Quiz · 1 question

Un ensemble A a 5 éléments. Combien d'états, au maximum, l'automate déterminisé issu d'un automate à 5 états peut-il avoir — et où lit-on ce nombre ?

  • 5 : la déterminisation ne change pas le nombre d'étatsinchangé
  • 25, car on considère les couples d'étatscouples
  • 2⁵ = 32, car les états du déterminisé sont les sous-ensembles de l'ensemble des étatsensemble des parties

Réponse : La déterminisation (chapitre 4) construit un automate dont les états sont les SOUS-ENSEMBLES de l'ensemble des états de départ. L'ensemble des parties d'un ensemble à n éléments en compte 2ⁿ — ici 2⁵ = 32. C'est exactement le 2ⁿ de l'ensemble des parties rappelé dans ce chapitre, et c'est lui qui explique l'explosion potentielle du nombre d'états lors de la déterminisation. En pratique on n'atteint presque jamais ce maximum, mais la borne est bien 2ⁿ.

À vous

L'exercice met la récurrence en pratique sur un objet concret : le miroir d'un mot. Vous définissez la fonction miroir par récursion sur la structure du mot — un cas de base pour ε\varepsilon, un cas récursif pour awa \cdot w —, puis vous testez la propriété miroir(uv)=miroir(v)miroir(u)\text{miroir}(u \cdot v) = \text{miroir}(v) \cdot \text{miroir}(u).

L'important est ce que la solution révèle : la structure de la fonction récursive est exactement celle de la preuve par récurrence. Définir par récursion et prouver par récurrence sont le même geste — celui que vous répéterez tout le reste de l'année.

Exercice de code

Définissez la fonction miroir par récursion sur la structure d'un mot, puis testez la propriété miroir(u·v) = miroir(v)·miroir(u). Les tests suggèrent — la solution vous donne la vraie preuve par récurrence, dont la structure calque exactement celle de la fonction.

Point de départ

// Le miroir d'un mot : miroir(abc) = cba. On le définit PAR RÉCURSION sur la
// structure du mot — exactement comme on le prouverait par induction.
//
//   miroir(ε)      = ε                      (cas de base)
//   miroir(a · u)  = miroir(u) · a          (cas récursif : a est la 1re lettre)
//
// C'est la traduction en code d'une définition inductive. Le "cas de base" et
// le "cas récursif" sont exactement les deux cas d'une preuve par récurrence.

// ── À VOUS (1) : définir miroir par récursion ───────────────────────────────
function miroir(u) {
  if (u === "") return "";        // cas de base : miroir(ε) = ε
  // cas récursif : première lettre = u[0], reste = u.slice(1)
  return ""; // à compléter avec miroir(u.slice(1)) et u[0]
}

// ── À VOUS (2) : vérifier une propriété par la pratique ─────────────────────
// PROPRIÉTÉ à établir : pour tous mots u, v :  miroir(u·v) = miroir(v)·miroir(u)
// (l'ordre s'inverse !). Testez-la sur de nombreux couples : si elle tient
// partout, c'est bon signe — mais SEULE une preuve par récurrence la garantit.
function proprieteTient(u, v) {
  return miroir(u + v) === miroir(v) + miroir(u);
}

// ── Vérification ────────────────────────────────────────────────────────────
console.log("miroir('abc') =", miroir("abc"), "(attendu cba)");
console.log("miroir('') =", "'" + miroir("") + "'", "(attendu ε)");
console.log("");
const mots = ["", "a", "ab", "abba", "aabb", "xyz"];
let toutesOk = true;
for (const u of mots) for (const v of mots) {
  if (!proprieteTient(u, v)) { console.log("CONTRE-EXEMPLE : u=" + u + " v=" + v); toutesOk = false; }
}
console.log(toutesOk ? "La propriété tient sur tous les tests." : "Propriété fausse !");

Solution

function miroir(u) {
  if (u === "") return "";
  return miroir(u.slice(1)) + u[0];   // on renvoie le miroir du reste, PUIS
                                       // la première lettre — qui passe au bout
}

// La propriété miroir(u·v) = miroir(v)·miroir(u) tient sur tous les tests.
// Les tests NE la prouvent PAS — ils ne couvrent qu'un nombre fini de cas.
// Voici la preuve, qui est le vrai objet du chapitre :
//
// ── Preuve par récurrence sur |u| ──────────────────────────────────────────
//
// On veut : ∀u ∀v, miroir(u·v) = miroir(v)·miroir(u).
// On raisonne par récurrence sur la longueur de u.
//
// BASE (|u| = 0, donc u = ε) :
//     miroir(ε·v) = miroir(v)              car ε·v = v
//                 = miroir(v)·ε            car ε est neutre
//                 = miroir(v)·miroir(ε)    car miroir(ε) = ε
//     ✓ la propriété est vraie pour u = ε.
//
// HÉRÉDITÉ : supposons la propriété vraie pour tout mot de longueur n
// (hypothèse de récurrence). Soit u de longueur n+1 ; on l'écrit u = a·w
// avec a une lettre et |w| = n. Alors :
//     miroir(u·v)   = miroir(a·w·v)
//                   = miroir(w·v)·a           (définition de miroir)
//                   = (miroir(v)·miroir(w))·a (hypothèse de récurrence sur w)
//                   = miroir(v)·(miroir(w)·a) (associativité)
//                   = miroir(v)·miroir(a·w)   (définition de miroir, à rebours)
//                   = miroir(v)·miroir(u).
//     ✓ la propriété se transmet de n à n+1.
//
// Par le principe de récurrence, elle est vraie pour TOUT u. CQFD.
//
// ── Ce qu'il faut retenir ───────────────────────────────────────────────────
// La STRUCTURE de la fonction récursive (cas de base ε, cas récursif a·w) est
// exactement la structure de la preuve (base ε, hérédité de w à a·w). Définir
// par récursion et prouver par récurrence, c'est le même geste. C'est le
// schéma de raisonnement de TOUT le cours — les automates, Kleene, le lemme
// de pompage s'en servent tous.

Ce que la suite en fait

Vous disposez maintenant du vocabulaire (chapitre 1) et des outils de preuve (ce chapitre). Le bloc II peut commencer, et c'est le cœur du cours.

Le chapitre 3 introduit l'objet vers lequel tout ce qui précède tendait : l'automate fini déterministe, entièrement bâti sur la fonction de transition δ\delta définie ici. La double inclusion servira à prouver des équivalences, la récurrence sur la longueur à établir qu'un automate reconnaît bien le langage voulu, et le 2n2^n de l'ensemble des parties reviendra dès le chapitre 4 pour expliquer le coût de la déterminisation.

À retenir

Flashcards · 4 cartes

Quelles sont les deux étapes d'une preuve par récurrence sur la longueur d'un mot ?
La BASE — prouver P(ε), la propriété pour le mot vide — et l'HÉRÉDITÉ — supposer P vraie pour tout mot de longueur n, et en déduire P pour un mot de longueur n+1 (écrit u = a·w avec |w| = n). Comme tout mot a une longueur finie, ces deux étapes couvrent Σ* entier. Le cas de base ne se néglige jamais : c'est souvent là que la difficulté se cache.
Comment prouve-t-on l'égalité de deux langages (ou l'équivalence de deux descriptions) ?
Par DOUBLE INCLUSION : montrer A ⊆ B et B ⊆ A. Pour A ⊆ B, on prend un élément quelconque de A et on montre qu'il est dans B. C'est la méthode qui servira à prouver qu'un automate et une expression régulière décrivent le même langage (théorème de Kleene), ou qu'un AFD et un AFN sont équivalents.
Qu'est-ce qu'une fonction de transition δ, et quel rôle joue-t-elle dans le cours ?
δ : Q × Σ → Q associe à un état q et une lettre a un unique état δ(q,a) = q' : « depuis q, en lisant a, on va en q' ». C'est le cœur d'un automate déterministe. L'exigence « une seule sortie par entrée » DÉFINIT le déterminisme ; la relâcher (δ rend un ensemble d'états) donne le non-déterminisme du chapitre 4.
Pourquoi le nombre 2ⁿ (ensemble des parties) est-il important pour la suite ?
L'ensemble des parties d'un ensemble à n éléments compte 2ⁿ sous-ensembles. Or la déterminisation (chapitre 4) construit un automate dont les états sont les sous-ensembles des états de départ : d'où au plus 2ⁿ états, et l'explosion potentielle du nombre d'états. Le même 2ⁿ relie aussi une relation d'équivalence à la minimisation (chapitre 6), qui regroupe les états indistinguables en classes.

Exercices d'entraînement

Exercice 1

Récurrence sur la longueur

Pour un mot uu et un entier n0n \geq 0, on note unu^n la concaténation de nn copies de uu (avec u0=εu^0 = \varepsilon). Démontrer par récurrence sur nn que un=nu.|u^n| = n \cdot |u|.

Correction

Base (n=0n = 0) : u0=εu^0 = \varepsilon, donc u0=0=0u|u^0| = 0 = 0 \cdot |u|. Vrai.

Hérédité : supposons un=nu|u^n| = n\,|u| pour un nn donné. Alors un+1=unuu^{n+1} = u^n \cdot u, et comme les longueurs s'ajoutent à la concaténation (chapitre 1) : un+1=unu=un+u=nu+u=(n+1)u.|u^{n+1}| = |u^n \cdot u| = |u^n| + |u| = n\,|u| + |u| = (n+1)\,|u|. La propriété se transmet de nn à n+1n+1 ; par récurrence, elle vaut pour tout n0n \geq 0.

Exercice 2

Involution du miroir

On admet la propriété miroir(uv)=miroir(v)miroir(u)\text{miroir}(u \cdot v) = \text{miroir}(v) \cdot \text{miroir}(u). Démontrer par récurrence sur u|u| que miroir(miroir(u))=u\text{miroir}(\text{miroir}(u)) = u pour tout mot uu.

Correction

Base (u=εu = \varepsilon) : miroir(ε)=ε\text{miroir}(\varepsilon) = \varepsilon, donc miroir(miroir(ε))=ε\text{miroir}(\text{miroir}(\varepsilon)) = \varepsilon. Vrai.

Hérédité : soit u=awu = a \cdot w avec aa une lettre et w=n|w| = n, en supposant miroir(miroir(w))=w\text{miroir}(\text{miroir}(w)) = w. On a miroir(aw)=miroir(w)a\text{miroir}(a \cdot w) = \text{miroir}(w) \cdot a (car miroir(a)=a\text{miroir}(a) = a et la propriété admise). Donc miroir(miroir(aw))=miroir(miroir(w)a)=miroir(a)miroir(miroir(w))=aw.\text{miroir}(\text{miroir}(a \cdot w)) = \text{miroir}(\text{miroir}(w) \cdot a) = \text{miroir}(a) \cdot \text{miroir}(\text{miroir}(w)) = a \cdot w. La dernière égalité utilise l'hypothèse de récurrence. La propriété vaut donc pour tout uu.

Exercice 3

Parties et relation d'équivalence

  1. Un ensemble EE a 44 éléments. Combien P(E)\mathcal{P}(E) a-t-il d'éléments ?
  2. Sur Σ\Sigma^*, on pose uvu \sim v lorsque u=v|u| = |v|. Est-ce une relation d'équivalence ? Combien a-t-elle de classes ?

Correction

  1. P(E)\mathcal{P}(E) a 2E=24=162^{|E|} = 2^4 = 16 éléments : chacun des 44 éléments est, indépendamment, dans le sous-ensemble ou non.
  2. Oui : \sim est réflexive (u=u|u| = |u|), symétrique (u=vv=u|u| = |v| \Rightarrow |v| = |u|) et transitive (u=v|u| = |v| et v=wu=w|v| = |w| \Rightarrow |u| = |w|). Ses classes sont les ensembles de mots de même longueur : une classe par entier n0n \geq 0, donc une infinité dénombrable de classes. (C'est ce type de partition que la minimisation d'automate exploitera au chapitre 6.)