diff options
author | David A. Madore <david+git@madore.org> | 2017-11-08 15:02:53 +0100 |
---|---|---|
committer | David A. Madore <david+git@madore.org> | 2017-11-08 15:02:53 +0100 |
commit | 9bc4d34e3a51d321e8a1f4946e83417fd79ac65a (patch) | |
tree | 5b0261eef3d643f19af8c609cb584992cfe6cebf | |
parent | 6bd9d61fc12a22378c8d103d092a3cf4d80ed972 (diff) | |
download | inf105-9bc4d34e3a51d321e8a1f4946e83417fd79ac65a.tar.gz inf105-9bc4d34e3a51d321e8a1f4946e83417fd79ac65a.tar.bz2 inf105-9bc4d34e3a51d321e8a1f4946e83417fd79ac65a.zip |
Add more white space to make text less dense.
-rw-r--r-- | notes-inf105.tex | 294 |
1 files changed, 260 insertions, 34 deletions
diff --git a/notes-inf105.tex b/notes-inf105.tex index 939abe7..21d4d82 100644 --- a/notes-inf105.tex +++ b/notes-inf105.tex @@ -1,6 +1,6 @@ %% This is a LaTeX document. Hey, Emacs, -*- latex -*- , get it? \documentclass[12pt,a4paper]{article} -\usepackage[a4paper,hmargin=2cm,vmargin=3cm]{geometry} +\usepackage[a4paper,hmargin=2.5cm,vmargin=3cm]{geometry} \usepackage[francais]{babel} \usepackage[utf8]{inputenc} \usepackage[T1]{fontenc} @@ -29,7 +29,7 @@ \theoremstyle{definition} \newtheorem{comcnt}{Tout}[subsection] \newcommand\thingy{% -\refstepcounter{comcnt}\smallskip\noindent\textbf{\thecomcnt.} } +\refstepcounter{comcnt}\medskip\noindent\textbf{\thecomcnt.} } \newtheorem{defn}[comcnt]{Définition} \newtheorem{prop}[comcnt]{Proposition} \newtheorem{lem}[comcnt]{Lemme} @@ -88,6 +88,7 @@ Git: \input{vcline.tex} \pretolerance=8000 \tolerance=50000 +\linepenalty=5 % Default is supposedly 10 % @@ -121,6 +122,8 @@ une application informatique pratique à l'analyse de textes ou de chaînes de caractères (qu'on appellera par la suite « mots », cf. §\ref{subsection-introduction-and-words}). +\smallbreak + Après des définitions générales (sections \ref{subsection-introduction-and-words} à \ref{subjection-languages}), ces notes sont divisées en grandes parties (inégales) de la manière @@ -139,6 +142,8 @@ suivante : théoriques sur ce qu'un algorithme peut faire. \end{itemize} +\smallbreak + À ces parties seront associées la définition de différentes classes de « langages » (voir §\ref{subjection-languages} pour la définition de ce terme) qu'il s'agit d'étudier : @@ -209,6 +214,8 @@ de caractères), mais cette structure supplémentaire ne nous intéressera pas ici. Dans tous les cas, il est important pour la théorie que l'alphabet soit \emph{fini}. +\smallskip + L'alphabet sera généralement fixé une fois pour toutes dans la discussion, et désigné par la lettre $\Sigma$ (sigma majuscule). @@ -228,6 +235,8 @@ caractères : on écrira donc \texttt{\char`\"foobar\char`\"} pour parler du mot en question. Dans ces notes, nous utiliserons peu cette convention.) +\medskip + L'ensemble de tous les mots sur un alphabet $\Sigma$ sera désigné $\Sigma^*$ (on verra en \ref{kleene-star} ci-dessous cette notation comme un cas particulier d'une construction « étoile » plus @@ -236,6 +245,8 @@ l'ensemble (infini !) dont les éléments sont toutes les suites finies binaires (= suites finies de $0$ et de $1$). Ainsi, écrire « $w \in \Sigma^*$ » signifie « $w$ est un mot sur l'alphabet $\Sigma$ ». +\medskip + {\footnotesize\thingy Typographiquement, on essaiera autant que possible de désigner des mots par des variables mathématiques telles que $u,v,w$, tandis que $x,y,z$ désigneront plutôt des lettres @@ -369,6 +380,8 @@ fois du mot $w$. Formellement, on définit par récurrence : peut constater que $w^r w^s = w^{r+s}$ quels que soient $r,s\in\mathbb{N}$.) On a bien sûr $|w^r| = r|w|$. +\smallskip + Cette définition sert notamment à désigner de façon concise les mots comportant des répétitions d'une même lettre : par exemple, le mot $aaaaa$ peut s'écrire tout simplement $a^5$, et le mot $aaabb$ peut @@ -405,6 +418,8 @@ produire que le préfixe et le suffixe de longueur $k$ soient égaux pour d'autres $k$ que $0$ et $|w|$, comme le montre l'exemple qui suit.) +\smallskip + À titre d'exemple, le mot $abbcab$ sur l'alphabet $\Sigma=\{a,b,c,d\}$ a les sept préfixes suivants, rangés par ordre croissant de longueur : $\varepsilon$ (le mot vide), $a$, $ab$, $abb$, $abbc$, $abbca$ et @@ -421,11 +436,15 @@ et si $w = u_0 v u_1$ est leur concaténation, on dira que $v$ est un est déterminé simplement par sa longueur, un facteur est déterminé par sa longueur et l'emplacement à partir duquel il commence. +\smallskip + À titre d'exemple, les facteurs du mot $abbcab$ sont : $\varepsilon$ (le mot vide), $a$, $b$, $c$, $ab$, $bb$, $bc$, $ca$, $abb$, $bbc$, $bca$, $cab$, $abbc$, $bbca$, $bcab$, $abbca$, $bbcab$ et $abbcab$ lui-même. +\smallskip + Dans un contexte informatique, ce que nous appelons ici « facteur » est souvent appelé « sous-chaîne [de caractères] ». Il ne faut cependant pas confondre ce concept avec celui de sous-mot défini @@ -439,6 +458,8 @@ certaines lettres du mot $w$, dans le même ordre, mais en en effaçant d'autres ; à la différence du concept de facteur, celui de sous-mot n'exige pas que les lettres gardées soient consécutives. +\smallskip + À titre d'exemple, le mot $acb$ est un sous-mot du mot $abbcab$ (obtenu en gardant les lettres soulignées ici : $\underline{a}bb\underline{c}a\underline{b}$ ; pour se rattacher à la @@ -475,6 +496,8 @@ d'exemple, $(ababb)^{\textsf{R}} = bbaba$. On remarquera que $(w_1 w_2)^{\textsf{R}} = w_2^{\textsf{R}} w_1^{\textsf{R}}$ si $w_1,w_2$ sont deux mots quelconques. +\smallskip + Un mot $w$ est dit \defin{palindrome} lorsque $w = w^{\textsf{R}}$. Par exemple, $abba$ est un palindrome sur $\{a,b,c,d\}$ (ou bien le mot « ressasser » sur l'alphabet du français). @@ -563,11 +586,15 @@ langage qu'on vient d'associer l'un à l'autre (par exemple, le langage des mots commençant par $a$ et la propriété « commencer par $a$ »), un langage pourrait être considéré comme une propriété des mots. -{\footnotesize(Ceci n'a rien de spécifique aux langages : une partie - d'un ensemble $E$ quelconque peut être identifiée à une propriété - que les éléments de $E$ peuvent ou ne pas avoir, à savoir, +\smallskip + +{\footnotesize(Ce qui précède n'a rien de spécifique aux langages : + une partie d'un ensemble $E$ quelconque peut être identifiée à une + propriété que les éléments de $E$ peuvent ou ne pas avoir, à savoir, appartenir à la partie en question.)\par} +\smallskip + On évitera de faire cette identification pour ne pas introduire de complication, mais il est utile de la garder à l'esprit : par exemple, dans un langage de programmation fonctionnel, un « langage » au sens @@ -583,6 +610,8 @@ $L_1,L_2 \subseteq \Sigma^*$), on peut former les langages sont simplement les opérations ensemblistes usuelles (entre parties de $\Sigma^*$). +\smallskip + Les opérations correspondantes sur les propriétés de mots sont respectivement le « ou logique » (=disjonction) et le « et logique » (=conjonction) : à titre d'exemple, sur $\Sigma = \{a,b\}$ si $L_1$ @@ -600,6 +629,8 @@ simplement l'ensemble des mots sur $\Sigma$ \emph{n'appartenant pas} à $L$. L'opération correspondante sur les propriétés de mots est la négation logique. +\smallskip + À titre d'exemple, sur $\Sigma=\{a,b\}$, si $L$ est le langage des mots commençant par $a$, alors $\overline{L}$ est le langage des mots ne commençant pas par $a$, c'est-à-dire, la réunion de @@ -620,6 +651,8 @@ L_1 L_2 &:= \{w_1 w_2 : w_1 \in L_1,\, w_2 \in L_2\}\\ \end{aligned} \] +\smallskip + À titre d'exemple, sur l'alphabet $\Sigma = \{a,b,c,d\}$, si on a $L_1 = \{a,bb\}$ et $L_2 = \{bc, cd\}$ alors $L_1 L_2 = \{abc, acd, bbbc, bbcd\}$. @@ -635,10 +668,14 @@ récurrence : \item $L^{r+1} = L^r L$. \end{itemize} +\smallskip + À titre d'exemple, sur l'alphabet $\Sigma = \{a,b,c,d\}$, si on a $L = \{a,bb\}$, alors $L^2 = \{aa, abb, bba, bbbb\}$ et $L^3 = \{aaa, aabb, abba, abbbb, \penalty-100 bbaa, bbabb, bbbba, bbbbbb\}$. +\medskip + \emph{Attention}, $L^r$ n'est pas le langage $\{w^r : w\in L\}$ constitué des répétitions $r$ fois ($w^r$) des mots $w$ de $L$ : c'est le langage des concaténations de $r$ mots appartenant à $L$ \emph{mais @@ -661,17 +698,23 @@ L^* &:= \bigcup_{r=0}^{+\infty} L^r = \bigcup_{r\in\mathbb{N}} L^r\\ \end{aligned} \] +\smallskip + À titre d'exemple, sur l'alphabet $\Sigma = \{a,b,c,d\}$, si on a $L = \{a,bb\}$, alors on a $L^* = \{\varepsilon, a, bb, \penalty-200 aa, abb, bba, bbbb, \penalty-200 aaa, aabb, abba, abbbb, \penalty-100 bbaa, bbabb, bbbba, bbbbbb, \ldots\}$. +\smallskip + Comme ci-dessus, il faut souligner que les mots $w_1,\ldots,w_r$ concaténés n'ont pas à être égaux : notamment, $\{a,b\}^*$ est le langage constitué de tous les mots sur l'alphabet $\{a,b\}$, pas le langage $\{a\}^* \cup \{b\}^*$ constitué des mots obtenus en répétant la lettre $a$ ou en répétant la lettre $b$. +\smallskip + On remarquera que la définition de $L^*$ ci-dessus redonne bien, lorsqu'on l'applique à l'alphabet $\Sigma$ lui-même (considéré comme langage des mots de longueur $1$), l'ensemble $\Sigma^*$ de tous les @@ -697,7 +740,7 @@ langage sur l'alphabet $\Sigma$, on définit le langage miroir $L^{\mathsf{R}}$ comme l'ensemble des mots miroirs des mots de $L$, c'est-à-dire $L^{\mathsf{R}} = \{w^{\mathsf{R}} : w \in L\}$. -\medbreak +\bigbreak \thingy\label{set-of-languages} De même que l'ensemble des mots sur un alphabet $\Sigma$ admet une notation, à savoir $\Sigma^*$, on peut @@ -712,6 +755,8 @@ synonyme de « $L\subseteq \Sigma^*$ » ou de « $L$ est un langage sur $\Sigma$ » ; on évitera cependant de le faire, car cette notation est plus lourde qu'utile. +\smallskip + {\footnotesize Il sera marginalement question dans ces notes de « classes de langages » : une classe de langages est un ensemble de langages (c'est-à-dire une partie de $\mathscr{P}(\Sigma^*)$, ou si @@ -769,6 +814,8 @@ cf. \ref{concatenation-of-languages}), et l'étoile de Kleene (représentant une répétition quelconque d'un certain motif, cf. \ref{kleene-star}). +\medskip + L'importance des langages rationnels, et des expressions rationnelles (=régulières) qui les décrivent, vient : \begin{itemize} @@ -786,6 +833,8 @@ L'importance des langages rationnels, et des expressions rationnelles une chaîne de caractères. \end{itemize} +\smallskip + Passons maintenant à une définition plus précise. \bigbreak @@ -821,6 +870,8 @@ concaténation de deux langages rationnels, et l'étoile de Kleene d'un langage rationnel, sont rationnels ; et les langages rationnels sont exactement ceux qu'on obtient ainsi à partir des langages de base. +\smallskip + À titre d'exemple, sur l'alphabet $\{a,b,c,d\}$, comme le langage $\{c\}$ (constitué du seul mot $c$) est rationnel, son étoile de Kleene, c'est-à-dire $\{c\}^* = \{\varepsilon, c, cc, ccc, @@ -854,6 +905,8 @@ ensembles $\mathscr{C}$ vérifiant tous ces propriétés, est la classe $\mathscr{R}$ des langages rationnels (et un langage rationnel est simplement un élément de $\mathscr{R}$). +\medskip + \emph{Attention !}, le fait que la classe $\mathscr{R}$ des langages rationnels soit stable par concaténation signifie que si $L_1$ et $L_2$ sont rationnels alors le langage $L_1 L_2$ (constitué de tous @@ -876,6 +929,8 @@ langage « dénoté par l'expression rationnelle $dc{*}$ ». Ceci fournit du même coup une nouvelle définition des langages rationnels : ce sont les langages dénotés par une expression rationnelle. +\smallskip + Plus exactement, une expression rationnelle (sur un alphabet $\Sigma$) est un mot sur l'alphabet $\Sigma \cup \{\bot, \underline{\varepsilon}, {(}, {)}, {|}, {*}\}$, où $\bot, @@ -949,7 +1004,8 @@ $\Sigma = \{a,b,c,d\}$ : \item l'expression rationnelle $(bc){*}$ dénote le langage $\{bc\}^* = \{\varepsilon, bc, bcbc, bcbcbc, \ldots\}$ ; \item l'expression rationnelle $(a|(bc){*})$ dénote le langage $\{a\} - \cup \{bc\}^* = \{a, \varepsilon, bc, bcbc, bcbcbc, \ldots\}$ ; + \cup \{bc\}^* = \{a,\penalty0 \varepsilon,\penalty1000 + bc,\penalty1000 bcbc,\penalty1000 bcbcbc, \ldots\}$ ; \item l'expression rationnelle $(a|(bc){*})d$ dénote le langage $\{a, d, bcd, bcbcd, bcbcbcd, \ldots\}$ ; \item l'expression rationnelle $\bot d$ dénote le langage @@ -1364,6 +1420,8 @@ se trouve l'automate une fois qu'il a consommé le mot $w$, on dira que l'automate \emph{acepte} ou \emph{rejette} le mot selon que $q_n \in F$ ou que $q_n \not\in F$. +\smallskip + Graphiquement, on peut présenter la procédure de la manière suivante : on part de l'état $q_0$ (sommet du graphe représentant l'automate) indiqué par la flèche entrante (pointant de nulle part), et pour @@ -1419,11 +1477,15 @@ $\delta^*(q_0,w) =: q_n \in F$ ; dans le cas contraire, on dira qu'il \textbf{langage accepté}, ou \textbf{reconnu}, ou \textbf{défini}, par l'automate $A$. +\smallskip + Un langage $L \subseteq \Sigma^*$ qui peut s'écrire sous la forme du langage $L(A)$ accepté par un DFA $A$ s'appelle \defin[reconnaissable (langage)]{reconnaissable} (sous-entendu : par automate déterministe fini). +\smallskip + On dit que deux DFA $A,A'$ sont \defin[équivalents (automates)]{équivalents} lorsqu'ils reconnaissent le même langage, i.e., $L(A) = L(A')$. @@ -1474,6 +1536,8 @@ certain mot). Dans le cas contraire, l'état est dit modifier) les états inaccessibles dans un DFA ne change rien au langage reconnu (on obtient des automates équivalents). +\smallskip + Par exemple, dans le DFA qui suit, l'état $2$ est inaccessible (l'automate est donc équivalent à celui représenté en \ref{discussion-example1}). On remarquera qu'il ne change rien que @@ -1538,6 +1602,8 @@ en \ref{definition-dfa} est que la fonction $\delta$ est partielle, ce qui signifie qu'elle n'est pas obligatoirement définie sur tout couple $(q,x) \in Q\times\Sigma$. +\smallskip + Un DFA est considéré comme un DFAi particulier où la fonction de transition $\delta$ se trouve être définie partout. @@ -1546,6 +1612,8 @@ différence près que pour chaque $q\in Q$ et chaque $x\in \Sigma$, il y a maintenant \emph{au plus une} (et non plus exactement une) arête partant de $q$ et étiquetée par $x$. +\smallskip + L'intérêt informatique des DFAi est de ne pas s'obliger à stocker inutilement des transitions et des états inutiles au sens où ils ne permettront jamais d'accepter le mot (voir la notion d'automate @@ -1564,6 +1632,8 @@ fonctionner : l'automate n'a plus d'état, n'effectue plus de transition, et n'acceptera pas le mot quelles que soient les lettres ultérieures. +\smallskip + Cela revient une fois de plus à dire que le mot $w$ est accepté lorsqu'il existe un chemin orienté dans l'automate, reliant l'état $q_0$ initial à un état $q_n$ final, et tel que le mot $w = x_1 \cdots @@ -1595,6 +1665,8 @@ Enfin, l'automate $A$ accepte un mot $w$ lorsque $\delta^*(q_0,w)$ soit parce que $\delta^*(q_0,w)$ n'est pas défini ou parce qu'étant défini il n'appartient pas à $F$), l'automate rejette le mot. +\smallskip + Le langage accepté $L(A)$ et l'équivalence de deux automates sont définis de façon analogue aux DFA (cf. \ref{definition-recognizable-language}). @@ -1707,6 +1779,8 @@ DFAi représenté en \ref{discussion-example2b} : accessible d'un DFAi comme pour un DFA (cf. \ref{definition-dfa-accessible-state}). +\smallskip + On dira en outre d'un état $q$ d'un DFAi qu'il est \defin[co-accessible (état)]{co-accessible} lorsqu'il existe un mot $w \in \Sigma^*$ tel que $\delta(q,w)$ soit défini et soit final, @@ -1720,6 +1794,8 @@ DFAi elle présente l'intérêt qu'on peut supprimer les états non co-accessibles dans un DFAi (ainsi, bien sûr, que toutes les transitions qui y conduisent). +\smallskip + Un DFAi dont tous les états sont à la fois accessibles et co-accessibles (on les dit aussi \defin[utile (état)]{utiles}) est parfois appelé \defin[émondé (automate)]{émondé}. On peut émonder un @@ -1818,6 +1894,8 @@ lorsqu'\emph{il existe} $q_0,\ldots,q_n \in Q$ tels que $q_0 \in I$ et $q_n\in F$ et $(q_{i-1},x_i,q_i) \in \delta$ pour chaque $1\leq i\leq n$. +\smallskip + La différence cruciale avec les DFAi est donc que, maintenant, il pourrait exister plusieurs chemins possibles partant d'un état initial dont les transitions sont étiquetées par les lettres du même mot. @@ -1835,6 +1913,8 @@ un chemin orienté conduisant de $q$ à $q'$ et tel que le mot $w$ soit obtenu en lisant dans l'ordre les étiquettes des différentes arêtes de ce chemin. +\smallskip + Formellement : si $A = (Q,I,F,\delta)$ est un NFA sur l'alphabet $\Sigma$, on définit une relation $\delta^* \subseteq Q \times \Sigma^* \times Q$ par $(q,w,q') \in \delta^*$ lorsque $w = @@ -1850,9 +1930,12 @@ de $w$) : \end{itemize} Enfin, l'automate $A$ accepte un mot $w$ lorsqu'il existe $q_0\in I$ -et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. Le -langage accepté $L(A)$ et l'équivalence de deux automates sont définis -de façon analogue aux DFA +et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. + +\smallskip + +Le langage accepté $L(A)$ et l'équivalence de deux automates sont +définis de façon analogue aux DFA (cf. \ref{definition-recognizable-language}). \thingy\label{discussion-example4} Pour illustrer le fonctionnement @@ -1889,7 +1972,7 @@ l'état $0$ et qu'on lui fait consommer un $a$, si ce $a$ sera l'avant-dernière lettre, et, dans ce cas, passe dans l'état $1$ pour pouvoir accepter le mot. -\medbreak +\bigbreak Comme les DFAi avant eux, les NFA sont en fait équivalents aux DFA ; mais cette fois-ci, le coût algorithmique de la transformation peut @@ -1942,6 +2025,8 @@ se voir à travers sa fonction indicatrice, qui est une fonction $Q \to procédure décrite dans la démonstration de cette proposition en ne gardant que les états accessibles. +\smallskip + Algorithmiquement, la déterminisation de $A$ s'obtient par la procéduire suivante : \begin{itemize} @@ -2065,17 +2150,22 @@ est la donnée \item d'une relation de transition $\delta \subseteq Q \times (\Sigma\cup\{\varepsilon\}) \times Q$. \end{itemize} + Autrement dit, on autorise maintenant des transitions étiquetées par le mot vide $\varepsilon$ plutôt que par une lettre $x \in\Sigma$ : ces transitions sont dites \defin[spontanée (transition)]{spontanées}, ou \index{epsilon-transition@$\varepsilon$-transition|see{spontanée}}\textbf{ε-transitions}. +\smallskip + Soulignons qu'on ne définit les ε-transitions \emph{que} pour les automates non-déterministes : ou, pour dire les choses autrement, \emph{un automate qui possède des ε-transitions est par nature même non-déterministe}. +\smallskip + La représentation graphique des εNFA est évidente (on utilisera le symbole « $\varepsilon$ » pour étiqueter les transitions spontanées). Un NFA est considéré comme un εNFA particulier pour lequel il n'y a @@ -2089,6 +2179,8 @@ pourquoi un automate à transition spontanée est forcément non-déterministe : ces transitions spontanées ne sont qu'une \emph{possibilité}, ce qui sous-entend le non-déterminisme.) +\smallskip + De façon plus précise, un εNFA accepte un mot $w$ lorsqu'\emph{il existe} un chemin orienté conduisant d'un état initial $q_0$ à un état final $q_n$ et tel que $w$ coïncide avec le mot obtenu en lisant @@ -2117,9 +2209,12 @@ $(q_{i-1},t_i,q_i) \in\delta$ pour chaque $1\leq i\leq n$, et enfin $w = t_1\cdots t_n$. Enfin, l'automate $A$ accepte un mot $w$ lorsqu'il existe $q_0\in I$ -et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. Le -langage accepté $L(A)$ et l'équivalence de deux automates sont définis -de façon analogue aux DFA +et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. + +\smallskip + +Le langage accepté $L(A)$ et l'équivalence de deux automates sont +définis de façon analogue aux DFA (cf. \ref{definition-recognizable-language}). \thingy\label{discussion-example5} Voici un exemple de εNFA @@ -2161,6 +2256,8 @@ l'exemple \ref{discussion-example5} ci-dessus, on a $C(0) = \{0,1,2\}$ et $C(1) = \{1,2\}$ et $C(2) = \{2\}$. Dans tout NFA sans ε-transitions, on a $C(q) = \{q\}$ pour tout état $q$.) +\smallskip + Il est clair qu'on peut calculer algorithmiquement $C(q)$ (par exemple par un algorithme de Dijkstra / parcours en largeur, sur le graphe orienté dont l'ensemble des sommets est $Q$ et l'ensemble des arêtes @@ -2322,6 +2419,8 @@ un DFA $A$ tel que $L = L(A)$. D'après \ref{completion-of-dfai}, on peut remplacer « DFA » dans cette définition par « DFAi », « NFA » ou « εNFA » sans changer la définition. +\smallskip + Nous allons maintenant montrer que les langages reconnaissables sont stables par différentes opérations. Dans cette section, nous traitons le cas des opérations booléennes (complémentaire, union, intersection) @@ -2464,6 +2563,8 @@ en \ref{rational-languages-are-recognizable} que les langages rationnels sont reconnaissables (la réciproque faisant l'objet de la section \ref{subsection-rnfa-and-kleenes-algorithm}). +\smallskip + Pour établir ces stabilités, on va travailler sur les NFA et utiliser la construction parfois appelée « de Glushkov » ou « automate standard » ; ceci fournira un « automate de Glushkov » pour chaque @@ -2529,7 +2630,7 @@ $q_0$ vers chacun des états qui étaient initiaux dans $A$, puis en résultat que ce qui vient d'être dit.) \end{proof} -\medbreak +\bigbreak On a vu en \ref{dfa-union-and-intersection} une preuve, à base de DFA, que $L_1 \cup L_2$ est reconnaissable lorsque $L_1$ et $L_2$ le sont. @@ -2889,6 +2990,8 @@ de base décrits en \ref{trivial-standard-automata} et en appliquant les constructions décrites dans les démonstrations de \ref{nfa-union}, \ref{nfa-concatenation} et \ref{nfa-star}. +\medskip + Plus exactement, on associe à chaque expression rationnelle $r$ (sur un alphabet $\Sigma$ fixé) un automate $A_r$ standard, appelé \defin[Glushkov (construction d'automate de)]{automate de Glushkov}, @@ -2911,6 +3014,8 @@ définie en \ref{regular-expressions}) : de \ref{nfa-star}. \end{itemize} +\smallskip + Cette automate de Glushkov $A_r$ possède les propriétés suivantes : \begin{itemize} \item c'est un NFA reconnaissant le langage $L(r)$ dénoté par @@ -3071,6 +3176,8 @@ Elle possède pour sa part les propriétés suivantes : concaténation implicite). \end{itemize} +\smallskip + Dans les dessins qui suivent, on symbolisera de la manière suivante un automate de Thompson $A$ quelconque : \begin{center} @@ -3193,11 +3300,13 @@ très simple à appliquer ; mais elle conduit à des automates rapidement énormes, comportant un nombre considérable d'états et de transitions spontanées « stupides ». +\medskip + À titre d'exemple, voici l'automate de Thompson, déjà gros, de l'expression rationnelle $(a|b){*}b$ : \begin{center} -\scalebox{0.75}{% +\scalebox{0.70}{% %%% begin example9 %%% \begin{tikzpicture}[>=latex,line join=bevel,automaton] @@ -3237,6 +3346,7 @@ dans $(a|b){*}b$.) Pour comparaison, voici son automate de Glushkov : \begin{center} +\scalebox{0.85}{% %%% begin example9b %%% \begin{tikzpicture}[>=latex,line join=bevel,automaton] @@ -3265,6 +3375,7 @@ Pour comparaison, voici son automate de Glushkov : \end{tikzpicture} %%% end example9b %%% +} \end{center} Il a $4$ états puisqu'il y a $3$ lettres dans $(a|b){*}b$. Ces états @@ -3314,6 +3425,7 @@ alphabet $\Sigma$ est la donnée $(\mathrm{regexp}(\Sigma))$ désigne l'ensemble des expressions rationnelles sur $\Sigma$. \end{itemize} + Autrement dit, on autorise maintenant des transitions étiquetées par des expressions rationnelles quelconques sur $\Sigma$. Remarquons qu'on doit maintenant demander \emph{explicitement} que l'ensemble @@ -3336,9 +3448,12 @@ transitions ($w = v_1\cdots v_n$), chacun vérifiant l'expression rationnelle qui étiquette la transition (soit $v_i \in L(r_i)$). Enfin, l'automate $A$ accepte un mot $w$ lorsqu'il existe $q_0\in I$ -et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. Le -langage accepté $L(A)$ et l'équivalence de deux automates sont définis -de façon analogue aux DFA +et $q_\infty\in F$ tels que $(q_0,w,q_\infty) \in \delta^*$. + +\smallskip + +Le langage accepté $L(A)$ et l'équivalence de deux automates sont +définis de façon analogue aux DFA (cf. \ref{definition-recognizable-language}). \thingy Un εNFA (ou \textit{a fortiori} un NFA, DFAi ou DFA) est @@ -3347,12 +3462,16 @@ considéré comme un RNFA particulier dont les transitions sont rationnelle) soit par le symbole $\underline{\varepsilon}$ (dénotant le langage $\{\varepsilon\}$) dans le cas des transitions spontanées. +\smallskip + Une expression rationnelle $r$ peut aussi être considérée comme un RNFA particulier comportant un unique état initial, un unique état final, et une unique transition de l'un vers l'autre, étiquetée par l'expression $r$ elle-même. Il est évident que ce RNFA reconnaît exactement le langage dénoté par $r$. +\smallskip + La représentation graphique des RNFA ne pose pas de problème particulier (voir en \ref{example-of-state-elimination} pour différents exemples). @@ -3369,6 +3488,8 @@ S'il n'y a \emph{aucune} transition de $q$ vers $q'$, on peut toujours choisir d'en ajouter une $(q,\bot,q')$ (qui ne peut pas être empruntée !) si c'est commode. +\medskip + Comme les εNFA, les NFA et les DFAi avant eux, les RNFA peuvent se ramener aux automates précédemment définis : @@ -3423,6 +3544,8 @@ chemin dans ce dernier, suivi d'une transition spontanée depuis un état final de $A_{r_j}$. \end{proof} +\medskip + Mais la surprise des RNFA est qu'ils peuvent aussi se ramener à des expressions rationnelles ! @@ -3617,7 +3740,7 @@ conduit à l'automate suivant : \noindent et finalement à l'expression rationnelle $(0|11|10(1|00){*}01){*}$, qui est équivalente à la précédente. -\medbreak +\bigbreak \thingy Donnons encore l'exemple du DFAi suivant : @@ -3683,6 +3806,8 @@ reconnaissables coïncident. (On pourra donc considérer ces termes comme synonymes.) \end{thm} +\smallskip + Il faut cependant retenir que s'il y a, mathématiquement, équivalence entre ces deux classes de langages, cette équivalence \emph{a un coût algorithmique}, c'est-à-dire que la conversion d'une expression @@ -3705,6 +3830,8 @@ d'expressions rationnelles $r_1,r_2$, de fabriquer algorithmiquement une expression rationnelle $r''$ (« conjonction » de $r_1$ et $r_2$) qui dénote le langage intersection de ceux dénotés par $r_1$ et $r_2$. +\smallskip + Le coût de ces opérations, cependant, est astronomique : doublement exponentiel, puisqu'il s'agit de convertir l'expression en NFA, de déterminiser le NFA en DFA (à un premier coût exponentiel), @@ -3864,6 +3991,8 @@ langage $L$ n'est pas rationnel est donc quelque chose comme ceci : être). \end{itemize} +\smallskip + Donnons maintenant un exemple d'utilisation du lemme : \begin{prop}\label{example-of-pumping-lemma} @@ -3909,6 +4038,8 @@ n'avons pas donné de réponse : comment savoir si deux automates \emph{donnés} ou deux expressions rationnelles données (ou un de chaque) sont équivalents ? +\smallskip + Pour cela, on va introduire un DFA particulier, \emph{canonique}, associé à un langage rationnel, qu'on pourra calculer algorithmiquement, et qui sera véritablement associé au langage, @@ -4099,8 +4230,9 @@ chaque classe d'équivalence pour $\equiv$. \thingy L'algorithme décrit par la proposition \ref{dfa-minimization} porte le nom d'algorithme \index{Moore (algorithme de)|see{minimisation}}\textbf{de Moore} ou \defin[minimisation - (algorithme de)]{de minimisation} ou \textbf{de réduction}. Voici -comment on peut le mettre en œuvre de façon plus concrète : + (algorithme de)]{de minimisation} ou \textbf{de réduction}. + +Voici comment on peut le mettre en œuvre de façon plus concrète : \begin{itemize} \item s'assurer qu'on a affaire à un DFA \underline{\emph{complet sans état inaccessible}} (si nécessaire, déterminiser l'automate s'il @@ -4126,6 +4258,8 @@ comment on peut le mettre en œuvre de façon plus concrète : du représentant). \end{itemize} +\smallskip + La dernière étape (construction de l'automate) permet de vérifier qu'on a correctement terminé l'étape précédente (raffinement de la partition) : si deux états dans la même classe ont une transition @@ -4201,6 +4335,8 @@ $\{2,3\}$ et $\{4,5\}$, et à l'automate minimal suivant : %%% end example7m %%% \end{center} +\medskip + Il est intéressant de voir comment des petits changements sur l'automate initial modifient la minimisation. Si on fait pointer la transition étiquetée par $c$ de l'état $1$ vers lui-même (au lieu @@ -4340,6 +4476,8 @@ l'analyse des langues naturelles ; mais c'est plus en informatique qu'en linguistique qu'elles ont trouvé leur utilité, à commencer surtout par la définition de la syntaxe du langage ALGOL 60. +\smallskip + Cette fois-ci, on ne s'intéressera pas simplement au langage défini (par la grammaire hors contexte, dit langage « algébrique »), mais aussi à la manière dont ces mots s'obtiennent par la grammaire, et @@ -4369,6 +4507,8 @@ d'une nouvelle instruction, et enfin un $\mathtt{fi}$ ; pour définir un bloc ($\mathit{Block}$), on peut soit ne rien mettre du tout, soit mettre une instruction suivi d'un nouveau bloc ». +\smallskip + Notre but va être d'expliquer quel genre de règles de ce genre on peut autoriser, comment elles se comportent, quels types de langages elles définissent, et comment on peut analyser (essentiellement, retrouver @@ -4429,6 +4569,8 @@ lorsqu'ils appartiennent à $N$. Un mot sur $\Sigma\cup N$ désigner un mot sur $\Sigma$ (autrement dit, un mot est un pseudo-mot ne comportant que des symboles terminaux). +\smallskip + Pour redire les choses autrement, les symboles terminaux sont les lettres des mots du langage qu'on cherche à définir ; les symboles nonterminaux sont des symboles qui servent uniquement à titre @@ -4437,6 +4579,8 @@ disparaître finalement. Un « pseudo-mot » est un mot pouvant contenir des nonterminaux, tandis qu'un « mot » sans précision du contraire ne contient que des terminaux. +\medskip + {\footnotesize Typographiquement, on aura tendance à utiliser des lettres minuscules pour désigner les symboles terminaux, et majuscules pour désigner les symboles nonterminaux ; et on aura @@ -4463,6 +4607,8 @@ $T \mathrel{\rightarrow_G} \alpha$, ou simplement $T \rightarrow \alpha$ (lorsque $G$ est clair) pour signifier que $(T,\alpha)$ est une règle de $G$. +\smallskip + On définit une relation $\Rightarrow$ en posant $\gamma T \gamma' \Rightarrow \gamma\alpha\gamma'$ pour toute règle $(T,\alpha)$ et tous pseudo-mots $\gamma,\gamma'$ : autrement dit, formellement, on définit @@ -4494,6 +4640,8 @@ précisera la grammaire appliquée en écrivant $\lambda \mathrel{\Rightarrow_G} \xi$ au lieu de simplement $\lambda\Rightarrow\xi$. +\smallskip + Une suite de pseudo-mots $(\lambda_0,\ldots,\lambda_n)$ telle que \[ \lambda_0 \Rightarrow \lambda_1 \Rightarrow \cdots \Rightarrow \lambda_n @@ -4517,6 +4665,8 @@ qu'on peut passer de $\lambda$ à $\xi$ en effectuant une suite chaque étape un nonterminal $T$ par la partie droite $\alpha$ d'une règle $T \rightarrow \alpha$ de la grammaire $G$. +\smallskip + Il va de soi qu'un pseudo-mot qui ne comporte que des terminaux, i.e., qui est en fait un mot (sur $\Sigma$), ne peut pas être dérivé plus loin. Ceci justifie au moins en partie la terminologie de @@ -4530,11 +4680,15 @@ de l'axiome $S$ de $G$, autrement dit : L(G) = \{w \in \Sigma^* : S \mathrel{\Rightarrow^*} w\} \] +\smallskip + Un langage qui peut s'écrire sous la forme $L(G)$ où $G$ est une grammaire hors contexte est appelé \index{hors contexte (langage)|see{algébrique}}\textbf{langage hors contexte} ou \defin[algébrique (langage)]{algébrique}. +\smallskip + Deux grammaires hors contexte $G$ et $G'$ sont dites \defin[faiblement équivalentes (grammaires)]{faiblement équivalentes} ou \index{langage-équivalentes (grammaires)|see{faiblement @@ -4575,6 +4729,8 @@ S b^n \Rightarrow a^n b^n Le langage $L(G)$ défini par la grammaire est donc $\{a^n b^n : n\in\mathbb{N}\}$. +\smallskip + On a vu en \ref{example-of-pumping-lemma} que ce langage n'est pas rationnel : il existe donc des langages algébriques qui ne sont pas rationnels. En revanche, pour ce qui est de la réciproque, on verra @@ -4599,6 +4755,8 @@ langage défini par la grammaire est l'ensemble de tous les mots (sans nonterminaux) qui peuvent s'obtenir par application des règles de remplacement à partir de l'axiome. +\smallskip + Les grammaires de types 0 et 1, avec celles de type 2 c'est-à-dire hors contexte, et celles de type 3 (= régulières) qui seront définies en \ref{regular-grammar} ci-dessous, forment une hiérarchie (plus le @@ -4611,7 +4769,7 @@ classe de langages définie est petite) appelée \defin[Chomsky \begin{prop}\label{rational-languages-are-algebraic} Tout langage rationnel est algébrique. Mieux, on peut déduire -algorithmiquement une grammaire hors contexte $G$ d'un εNFA $A$ de +algo\-ri\-thmi\-quement une grammaire hors contexte $G$ d'un εNFA $A$ de façon à avoir $L(G) = L(A)$. \end{prop} \begin{proof} @@ -4785,6 +4943,8 @@ en \ref{example-of-pumping-lemma-for-algebraic-languages}. En conséquence, il n'est pas non plus vrai en général que le complémentaire d'un langage algébrique soit algébrique. +\smallskip + En revanche, le fait suivant, que nous admettons sans démonstration, peut s'avérer utile : @@ -5003,6 +5163,8 @@ suivantes : \end{itemize} \end{itemize} +\smallskip + On dit de plus que l'arbre est \textbf{complet}, ou simplement qu'il s'agit d'un arbre d'analyse, lorsqu'il vérifie la propriété supplémentaire suivante : @@ -5166,10 +5328,14 @@ une dérivation dans laquelle le symbole réécrit est toujours \emph{le chaque dérivation immédiate la constituant ne comporte que des symboles terminaux. +\smallskip + À titre d'exemple, les deux dérivations données en \ref{example-of-derivations} sont respectivement une dérivation gauche et une dérivation droite. +\smallskip + À chaque arbre d'analyse est associée une et une seule dérivation gauche : on l'obtient de façon évidente en réécrivant à chaque étape le symbole nonterminal le plus à gauche en suivant la règle indiquée @@ -5192,6 +5358,8 @@ L(G)$ a un unique arbre d'analyse ; il revient au même de dire que tout mot de $L(G)$ a une unique dérivation droite, ou encore que tout mot de $L(G)$ a une unique dérivation gauche. +\smallskip + Les grammaires des langages informatiques réels sont évidemment (presque ?) toujours inambiguës : on souhaite qu'un programme (c'est-à-dire, dans la terminologie mathématique, un mot du langage) @@ -5314,6 +5482,8 @@ en \ref{trivial-example-ambiguity}). L'ambiguïté est donc une caractéristique de la \emph{grammaire} hors contexte et non du \emph{langage} algébrique qu'elle engendre. +\smallskip + Cependant, certains langages algébriques ne sont définis \emph{que} par des grammaires hors contexte ambiguës. De tels langages sont dits \defin[intrinsèquement ambigu (langage algébrique)]{intrinsèquement @@ -5353,6 +5523,8 @@ où : \end{itemize} \end{prop} +\smallskip + Donnons maintenant un exemple d'utilisation du lemme : \begin{prop}\label{example-of-pumping-lemma-for-algebraic-languages} @@ -5382,6 +5554,8 @@ peut s'avérer utile pour montrer qu'un langage n'est pas algébrique, en permettant de simplifier le langage auquel on va appliquer le lemme de pompage. +\smallskip + À titre d'exemple, montrons que le langage $L$ formé des mots sur $\{a,b,c\}$ ayant le même nombre total de $a$, de $b$ et de $c$ (autrement dit $\{w \in \{a,b,c\}^* : |w|_a = |w|_b = |w|_c\}$ où @@ -5421,6 +5595,8 @@ au sommet de la pile (jusqu'à une profondeur bornée), et une fois cette transition effectuée, décider de rajouter, retirer ou remplacer des symboles au sommet de la pile. +\medskip + {\footnotesize De façon plus formelle, un \index{automate à pile}automate à pile non déterministe est la @@ -5438,6 +5614,8 @@ mot $w$ lorsqu'il existe une suite de transitions d'un état initial avec pile vide vers un état final avec pile vide qui consomme les lettres de $w$. +\smallskip + De façon plus précise, l'automate accepte $w$ lorsqu'il existe $q_0,\ldots,q_n \in Q$ (les états traversés) et $t_1,\ldots,t_n \in (\Sigma\cup\{\varepsilon\})$ (les symboles consommés) et @@ -5458,6 +5636,8 @@ des langages acceptés.) \par} +\medskip + On peut montrer qu'il y a équivalence entre grammaires hors contexte et automates à pile non déterministes au sens où tout langage engendré par une grammaire hors contexte est le langage accepté par un automate @@ -5488,6 +5668,8 @@ hors contexte $G$ (absolument quelconque) est la suivante : s'arrêter dès qu'on dépasse la longueur $|w|$ à atteindre. \end{itemize} +\smallskip + Énonçons précisément le résultat en question : \begin{thm}\label{algebraic-languages-are-decidable} @@ -5570,6 +5752,8 @@ de reconnaître si $w \in L(G)$, et fournir une autre démonstration du théorème \ref{algebraic-languages-are-decidable}, tout en continuant à ne faire aucune hypothèse sur la grammaire hors contexte $G$. +\smallskip + Il s'agit de travailler en deux étapes : \begin{itemize} \item D'abord, trouver algorithmiquement une grammaire $G'$ et un $E @@ -5585,6 +5769,8 @@ Il s'agit de travailler en deux étapes : savoir si $S \mathrel{\Rightarrow^*} w$). \end{itemize} +\smallskip + Détaillons un peu plus chacune de ces étapes. Pour transformer la grammaire $G$ en une grammaire $G'$ sous forme @@ -5623,6 +5809,8 @@ normale de Chomsky, on effectue les transformations suivantes : L'ordre de ces transformations peut être légèrement varié, mais celui proposé ci-dessus est sans doute le meilleur. +\smallskip + Une fois la grammaire $G'$ en forme normale de Chomsky connue, lorsqu'on a un mot $w$ dont on cherche à tester s'il appartient à $L(G')$, on calcule, pour chaque facteur $u$ de $w$ (identifié par @@ -5651,6 +5839,8 @@ rechercher toutes les dérivations $Y \Rightarrow X_1 X_2 donné $v_1$ et $X_2$ a donné $v_2$. Une fois les $\Lambda(u)$ connus, tester si $w \in L(G')$ revient à tester si $S \in \Lambda(w)$. +\smallskip + L'algorithme qu'on vient de décrire (pour tester si $w \in L(G')$ une fois $G'$ sous forme normale de Chomsky) porte le nom d'\defin[Cocke-Younger-Kasami (algorithme de)]{algorithme de @@ -5680,6 +5870,8 @@ engendre) ; ces contraintes sont assez techniques et difficiles à décrire : dans la pratique, elles consistent essentiellement à essayer de fabriquer l'analyseur et à constater si l'algorithme échoue. +\smallskip + Il existe deux principales approches pour construire un analyseur pour une grammaire hors contexte (sujette à diverses contraintes supplémentaires) ; dans les deux cas, on construit une sorte @@ -5706,12 +5898,16 @@ les deux cas. De façon très simplifiée : feuilles, et qui restent encore à regrouper. \end{itemize} +\smallskip + On peut écrire un analyseur LL ou (plus difficilement) LR à la main dans un cas simple, mais en général ces analyseurs sont fabriqués par des algorithmes systématiques, implémentés dans des programmes tels que YACC ou Bison (qui produit des analyseurs LR, même si Bison peut dépasser ce cadre) ou JavaCC (qui produit des analyseurs LL). +\smallskip + L'idée générale à retenir est que les analyseurs LR sont strictement plus puissants que les analyseurs LL (ils sont capables d'analyser strictement plus de grammaires, cf. \ref{example-lr-non-ll-grammar}), @@ -5735,6 +5931,8 @@ productions $\varepsilon$ ; on peut imaginer, si on veut, qu'il s'agit d'une forme extrêmement primitive de XML où $a$ représente une balise ouvrante, $b$ une balise fermante, et $c$ une balise vide). +\medskip + L'approche la plus évidente, si on doit écrire une fonction « analyser un mot comme dérivant de $S$ dans cette grammaire » consiste à coder deux fonctions mutuellement récursives, « chercher un préfixe qui @@ -5786,6 +5984,8 @@ $S\rightarrow TS$ et $S\rightarrow c$, on va écrire : \end{itemize} \end{itemize} +\smallskip + Cette approche réussit sur cette grammaire très simple (où on peut notamment se convaincre que l'éventuel préfixe dérivant de $S$ ou de $T$ est toujours défini de façon unique). L'analyseur qu'on vient de @@ -5806,7 +6006,7 @@ C'est ici l'approche « descendante » : l'arbre se construit à partir de la racine et la pile sert à retenir les règles qu'on a commencé à reconnaître. -\smallbreak +\medbreak L'approche « ascendante » de la même grammaire serait plutôt la suivante : on parcourt le mot de gauche à droite en gardant de côté @@ -5867,6 +6067,8 @@ fastidieux que programmer un ordinateur en assembleur, donc s'il s'agit d'exhiber un algorithme, c'est probablement une mauvaise idée de l'écrire sous forme de machine de Turing). +\smallskip + Néanmoins, il est essentiel de savoir que ces formalisations existent : on peut par exemple évoquer le paradigme du $\lambda$-calcul de Church (la première formalisation rigoureuse de la @@ -5888,6 +6090,8 @@ formelles d'algorithmes, qu'on peut rassembler sous le nom commun de \defin[calculable (fonction)]{calculabilité au sens de Church-Turing}, ou « calculabilité » tout court. +\smallskip + Notamment, quasiment tous les langages de programmation informatique\footnote{C, C++, Java, Python, JavaScript, Lisp, OCaml, Haskell, Prolog, etc. Certains langages se sont même révélés @@ -5906,7 +6110,7 @@ entiers de taille arbitraire, de les comparer et de calculer les opérations arithmétiques dessus, et d'effectuer des tests et des boucles. -\medbreak +\bigbreak \thingy Il faut souligner qu'on s'intéresse uniquement à la question de savoir ce qu'un algorithme peut ou ne peut pas faire @@ -5919,6 +6123,8 @@ produits $pq$ avec $2\leq p,q\leq n-1$ et tester si l'un d'eux est égal à $n$, peu importe que cet algorithme soit absurdement inefficace. +\smallskip + De même, nos algorithmes sont capables de manipuler des entiers arbitrairement grands : ceci permet de dire, par exemple, que toute chaîne binaire peut être considérée comme un entier, peu importe le @@ -5963,9 +6169,11 @@ considérer qu'au lieu de mots on a affaire à des entiers naturels. Il va de soi que la concaténation de deux mots, la longueur d'un mot, le miroir d'un mot, sont tous calculables algorithmiquement. -On peut considérer que, dans cette partie, le terme de -\index{langage}« langage » désigne non plus une partie de $\Sigma^*$ -mais une partie de $\mathbb{N}$. +\smallskip + +Grâce au codage de Gödel, on peut considérer que, dans cette partie, +le terme de \index{langage}« langage » désigne non plus une partie de +$\Sigma^*$ mais une partie de $\mathbb{N}$. {\footnotesize (Le remplacement des mots par des entiers naturels en utilisant un codage comme on vient de le dire est assez standard en @@ -5976,7 +6184,7 @@ mais une partie de $\mathbb{N}$. d'importance ; comme $\mathbb{N}$ est un objet mathématiquement plus simple, c'est surtout pour cela qu'il est utilisé à la place.)\par} -\medbreak +\bigbreak \thingy\textbf{Terminaison des algorithmes.} Un algorithme qui effectue un calcul utile doit certainement terminer en temps fini. @@ -6015,6 +6223,8 @@ On dit qu'une fonction $f\colon\mathbb{N}\to\mathbb{N}$ est algorithme qui prend en entrée $n\in\mathbb{N}$, termine toujours en temps fini, et calcule (renvoie) $f(n)$. +\smallskip + On dit qu'un ensemble $A \subseteq \mathbb{N}$ (un « langage », cf. \ref{computability-all-data-are-integers}) est \defin{décidable} (ou \index{calculable (langage)|see{décidable}}« calculable » ou @@ -6026,6 +6236,8 @@ $n\in\mathbb{N}$, termine toujours en temps fini, et renvoie « oui » ($1$) si $n\in A$, « non » ($0$) si $n\not\in A$ (on dira que l'algorithme « décide » $A$). +\smallskip + On dit qu'une fonction partielle $f\colon\mathbb{N}\dasharrow\mathbb{N}$ (c'est-à-dire une fonction définie sur une partie de $\mathbb{N}$, appelé ensemble de définition @@ -6041,10 +6253,12 @@ On utilisera la notation $f(n)\downarrow$ pour signifier le fait que la fonction calculable partielle $f$ est définie en $n$, c'est-à-dire, que l'algorithme en question termine. +\smallskip + On dit qu'un ensemble $A \subseteq \mathbb{N}$ est -\defin{semi-décidable} (ou \index{semi-calculable - (langage)|see{semi-décidable}}« semi-calculable » ou -\index{semi-récursif (langage)|see{semi-décidable}}« semi-récursif ») +\defin{semi-décidable} (ou +\index{semi-calculable|see{semi-décidable}}« semi-calculable » ou +\index{semi-récursif|see{semi-décidable}}« semi-récursif ») lorsque la fonction partielle $\mathbb{N}\dasharrow\mathbb{N}$ définie exactement sur $A$ et y valant $1$, est calculable partielle. Autrement dit : lorsqu'il existe un algorithme qui prend en entrée @@ -6056,6 +6270,8 @@ et renvoie « oui » ($1$) dans ce cas\footnote{En fait, la valeur « semi-décide » $A$). \end{defn} +\smallskip + On s'est limité ici à des fonctions d'une seule variable (entière), mais il n'y a pas de difficulté à étendre ces notions à plusieurs variables, et de parler de fonction calculable $\mathbb{N}^k \to @@ -6221,6 +6437,8 @@ sont pas importants\footnote{Par exemple, ceux qui aiment le langage ce programme est valable (remplacer Java par tout autre langage préféré).}. +\medskip + Un point crucial dans cette numérotation des algorithmes est l'existence d'une \defin[universelle (machine)]{machine universelle}, c'est-à-dire d'un algorithme $U$ qui prend en entrée un entier $e$ @@ -6229,6 +6447,8 @@ que $T$ sur l'entrée $n$ (i.e., $U$ termine sur les entrées $e$ et $n$ si et seulement si $T$ termine sur l'entrée $n$, et, dans ce cas, renvoie la même valeur). +\smallskip + Informatiquement, ceci représente le fait que les programmes informatiques sont eux-mêmes représentables informatiquement : dans un langage de programmation Turing-complet, on peut écrire un @@ -6248,6 +6468,8 @@ qui, donnée une description (formelle !) d'un algorithme et une entrée à laquelle l'appliquer, effectue l'exécution de l'algorithme fourni sur l'entrée fournie. +\smallskip + On ne peut pas démontrer ce résultat ici faute d'une description rigoureuse d'un modèle de calcul précis, mais il n'a rien de conceptuellement difficile (même s'il peut être fastidieux à écrire @@ -6283,12 +6505,14 @@ programmation demande un minimum d'efforts). précisément comment le codage standard est fait pour une formalisation de la calculabilité).\par} +\smallskip + La machine universelle n'a rien de « magique » : elle se contente de suivre les instructions de l'algorithme $T$ qu'on lui fournit, et termine si et seulement si $T$ termine. Peut-on savoir à l'avance si $T$ terminera ? C'est le fameux « problème de l'arrêt ». -\smallbreak +\medbreak Intuitivement, le « problème de l'arrêt » est la question « l'algorithme suivant termine-t-il sur l'entrée suivante » ? @@ -6390,6 +6614,8 @@ semi-décidable, son complémentaire ne l'est pas. $h(e, n)$ la fonction qui n'est pas définie si $\varphi_e(n)$ l'est et qui vaut $42$ si $\varphi_e(n)$ n'est pas définie.\par} +\medbreak + La non-décidabilité du problème de l'arrêt est un résultat fondamental, car très souvent les résultats de non-décidabilité soit sont démontrés sur un modèle semblable, soit s'y ramènent @@ -6439,7 +6665,7 @@ construire un algorithme résolvant le problème de l'arrêt. i\leq n\}$ domine asymptotiquement n'importe quelle fonction calculable mais c'est un peu plus difficile.\par} -\medbreak +\bigbreak {\footnotesize\thingy\textbf{Application à la logique :} Sans rentrer dans les détails de ce que signifie un « système formel », on peut |