Calculabilité
On va s'intéresser ici à deux types de choses que peut (ou ne peut pas) calculer un algorithme : des fonctions et des nombres. Cette introduction à ce que l'on appelle calculabilité en informatique théorique doit vous permettre de comprendre qu'un algorithme ne peut pas tout faire.
Vous pouvez consulter ce lien sur l'émergence en mathématiques de la notion de calculabilité.
Algorithmes et nombres
Un réel $x$ est calculable s'il existe un algorithme $A$ tel que :
- $A(0)$ rend la partie entière de $x$
- $A(i)$ rend la $i$-ème décimale de $x$, pour tout $i > 0$
Nombres entiers et rationnels
On a donc immédiatement :
Proposition
Tous les entiers sont calculables.
preuve
preuve
Nom : Entier-e
Entrée :
n : un entier
Programme :
si n vaut 0
rendre e
sinon:
rendre 0
C'est bien un algorithme puisque :
- sa description est finie pour tout e
- son temps d'exécution est fini pour tout n
Ce résultat s'étend trivialement :
Proposition
Tous les rationnels sont calculables.
preuve
preuve
Il suffit d'utiliser l'algorithme de la division de deux entiers décimaux appris en primaire.
En revanche, ça s'arrête là.
Nombres réels
Tous les réels ne sont pas calculables. Ceci est dû au résultat suivant :
Théorème
Il existe strictement plus de nombres réels dans l'intervalle $[0, 1]$ que de nombres entiers strictement positifs.
preuve
preuve
On doit cette preuve magnifique au mathématicien allemand Georg Cantor. Elle est basée sur l'argument s'appelant diagonale de Cantor.
On commence en remarquant que l'on peut associer à tout entier $i$ formé des chiffres $c_1\dots c_k$ le réel de représentation décimale $0.c_1\dots c_k$, ce qui démontre qu'il y a au moins autant de réels dans $[0, 1]$ que de nombres entiers.
On suppose ensuite qu'il existe une injection $f: [0, 1] \rightarrow \mathbb{N}$ entre les réels de l'intervalle $[0, 1]$ et les entiers. On peut alors classer tous les réels avec leurs valeurs selon $f$ :
- on appelle $r_1$ le 1er réel, c'est-à-dire celui tel que $f(r_1) \leq f(x)$, quel que soit $x \in [0, 1]$
- on appelle $r_2$ le second réel, c'est-à-dire celui tel que $f(r_2) \leq f(x)$ pour tout $x \in [0, 1] \backslash \{ r_1 \}$
- ...
- on appelle $r_i$ le $i$ème réel : $f(r_i) \leq f(x)$ pour tout $x \in [0, 1] \backslash \{ r_1, \dots, r_{i-1} \}$
- ...
Chaque réel pouvant s'écrire sous sa représentation décimale (par exemple $0.1034842$), on construit le nombre réel $r$ de $[0, 1]$ tel que son $i$ème chiffre après la virgule soit :
- $1$ si le $i$ème chiffre après la virgule de $r_i$ est différent de $1$
- $2$ si le $i$ème chiffre après la virgule de $r_i$ est $1$
Le nombre $r$ est bien dans $[0, 1]$ mais il ne peut pas être $r_i$ quel que soit $i$ ! Il y a une contradiction (comme notre nombre ne finit ni par 9 ni par 0 il a un unique développement décimal et apparaît donc forcément dans notre liste). Notre hypothèse est fausse : il ne peut exister d'injection entre les réels de l'intervalle $[0, 1]$ et les entiers.
Il y a donc strictement plus de réels dans $[0, 1]$ que d'entiers.
Qui permet de déduire immédiatement que :
Proposition
Il existe des réels non calculables.
preuve
preuve
On a vu qu'il existait au plus un nombre dénombrable de programmes, donc au plus autant de programmes que de nombres entiers. Il ne peut y avoir d'injection associant à chaque réel son algorithme.
Le fait qu'il y ait des infinis plus ou moins gros est un résultat que l'on doit à Cantor et qui est très profond. On note communément $\aleph_0$ le nombre d'entiers qui est strictement plus petit que le nombre de réels, noté $\aleph_1$. Une question reste encore en suspens, mais on n'a pour l'instant toujours pas la réponse, c'est : y a-t-il un infini entre $\aleph_0$ et $\aleph_1$ ? On ne sait pas, mais on pense que non. C'est l'hypothèse du continu.
Pour une introduction en douceur sur ces sujets, consulter cette émission d'Arte, très bien faite.
Trouver de tels nombres est compliqué, car pour y penser il faut le décrire et donc en proposer un algorithme... Mais... ils existent (nous en verrons un plus tard). Attention, ce n'est pas parce qu'un réel a un nombre infini de décimales qu'il n'est pas calculable. Par exemple tous les réels qui sont des limites de suites elles-mêmes calculables :
Proposition
Soit $(u_n)_{n \geq 1}$ une suite réelle.
Si :
- $\lim_{n\rightarrow +\infty}u_n = x$
- il existe deux algorithmes $A$ et $B$ tels que :
- $A(n)$ rende la partie entière de $u_n$
- $B(n)$ rende les $n$ premières décimales de $u_n$
Alors le réel $x$ est calculable.
preuve
preuve
Comme $u_n$ converge vers $x$, pour tout $i> 0$, il existe $N_i$ tel que $\mid x - u_n\mid < 10^{-i}$ pour tout $n > N_i$. Si l'on veut calculer la $i$-ème décimale de $x$, il suffit de calculer $u_{max(i, N_{i})}$ et de prendre sa $i$-ème décimale.
La proposition ci-dessus permet de montrer que la plupart des réels connus sont calculables. Par exemple $\pi$ puisqu'il est la limite de la série de Leibniz de $\pi$.
Contrairement à une croyance largement répandue en Europe, on sait que $\pi$ est calculable depuis bien plus longtemps que ça. Le mathématicien chinois 刘徽 en proposait un algorithme au troisième siècle.
Attention cependant, il faut que le même algorithme soit utilisé pour chaque élément de la suite. Si on utilise un algorithme différent pour chaque $n$, le réel obtenu n'est pas forcément calculable, c'est le cas des suites de Specker par exemple.
Page Wikipédia sur les réels calculables, des nombres calculables.
En conclusion :
La quasi-totalité des nombres réels utilisés en mathématiques en tant que tels ($\pi$, $e$, etc) ou comme résultat de fonctions sont calculables : il existe un algorithme prenant un entier $i$ en paramètre et qui rend sa $i$ème décimale.
Attention cependant à ne pas confondre le réel en tant que tel (non utilisable dans un algorithme puisqu'il possède une infinité de décimales), son symbole utilisé en calcul formel et son approximation que l'on peut utiliser dans les calculs.
Algorithmes et fonctions
On a vu qu'un algorithme et tout ce qu'il manipulait pouvait être considéré comme une suite finie de 0 et de 1. On en déduit immédiatement la proposition suivante :
Proposition
Un algorithme est une fonction :
$$f: \{0, 1\}^\star \rightarrow \{0, 1\}^\star$$
Où $\{0, 1\}^\star$ est l'ensemble des suites finies de $0$ et de $1$.
Comme une suite finie de 0 et de 1 est une écriture binaire d'un entier positif on a aussi :
Proposition
Un algorithme est une fonction :
$$f: \mathbb{N} \rightarrow \mathbb{N}$$
Par exemple la fonction identité est un algorithme :
Nom : identité
Entrées :
n : un entier
Programme :
rendre n
De même, je vous laisse reprendre vos cours de primaire pour le faire, les fonctions $f(n) = 42 \cdot n$ ou encore $f(n) = 2 \cdot n$ sont des algorithmes. On dit que ces fonctions sont calculables :
Une fonction $f: \mathbb{N} \rightarrow \mathbb{N}$ est calculable s'il existe un algorithme qui permet de la calculer.
Montrons tout de suite que cette notion a un sens, c'est-à-dire que l'ensemble des fonctions calculables est strictement inclus dans l'ensemble des fonctions de $\mathbb{N}$ dans $\mathbb{N}$ :
Proposition
Il y a strictement plus de fonctions $f: \mathbb{N} \rightarrow \mathbb{N}$ que de nombres entiers.
preuve
preuve
La preuve est identique à celle du Théorème montrant qu'il y a strictement plus de réels que d'entiers.
Comme les fonctions $\widetilde{k}: \mathbb{N} \rightarrow \mathbb{N}$ définies telles que $\widetilde{k}(x) = k$ pour tout $x$ sont deux à deux différentes lorsque $k$ parcourt $\mathbb{N}$, on en déduit qu'il existe au moins autant de fonctions $f: \mathbb{N} \rightarrow \mathbb{N}$ que d'entiers. On suppose alors qu'il y en a autant, donc qu'il existe une bijection entre les fonctions $f: \mathbb{N} \rightarrow \mathbb{N}$ et les nombres entiers.
On peut alors numéroter chaque fonction $f_0$, $f_1$, $\dots$, $f_n$. Cet ordre nous permet de construire la fonction $g: \mathbb{N} \rightarrow \mathbb{N}$ telle que $g(i) = f_i(i) + 1$ pour tout $i \in \mathbb{N}$. Mais ceci est impossible puisque $g \neq f_i$ pour tout $i$ ($g(i) \neq f_i(i)$ par définition de $g$) : il existe strictement plus de fonctions $f: \mathbb{N} \rightarrow \mathbb{N}$ que d'entiers.
Comme il existe autant d'algorithmes que de nombres entiers :
Il existe des fonctions $f: \mathbb{N} \rightarrow \mathbb{N}$ intraduisibles par un algorithme.
Exemple de fonction calculable
La plupart des fonctions connues sont calculables. Prenons la plus connue d'entre elles, la fonction $\mbox{pgcd}(a, b)$ d'Euclide qui rend le plus grand commun diviseur de deux entiers positifs $a$ et $b$.
Euclide (environ -300) décrit son algorithme permettant de calculer le plus grand commun diviseur ($\operatorname{pgcd}$) de deux nombres ainsi :
- le pgcd de deux entiers identiques est cet entier,
- le pgcd de deux entiers différents est inchangé si on remplace le plus grand d'entre eux par leur différence.
Montrez que l'algorithme d'Euclide trouve bien le $\operatorname{pgcd}$ de deux entiers.
corrigé
corrigé
Soit $k$ le $\operatorname{pgcd}$ de $a$ et $b$ : $k$ est le plus grand entier tel que $a = k \cdot a'$ et $b = k \cdot b'$ avec $a'$ et $b'$ entiers.
Si $a = b$ on a bien $k = a = b$ et si $a > b$ on a :
Ce qui prouve que $\operatorname{pgcd}(a, b) \leq \operatorname{pgcd}(a-b, b)$. Réciproquement :
Donc $\operatorname{pgcd}(a-b, b) \leq \operatorname{pgcd}(a, b)$ ce qui conclut la preuve.
Montrer que l'algorithme d'Euclide peut s'écrire sous la forme d'une équation récurrente ayant un nombre fini d'étapes.
corrigé
corrigé
Si $a$ et $b$ sont deux entiers positifs et tels que $\min(a, b) > 0$ alors : $\max(a, b) - \min(a, b) < \max(a, b) \geq 0$. Il arrivera donc forcément un moment où $\min(a, b) = 0$.
Un cas d'usage classique est une fonction qui admet un développement en séries entières comme quasi toutes les fonctions mathématiques usuelles (comme $x \mapsto \cos(x)$, $x \mapsto \sin(x)$, $x \mapsto \sqrt{x}$, etc) :
Si vous pensez à une fonction il y a toutes les chances qu'elle soit calculable.
Cas limites
Il existe tout un tas de cas limites rigolos. Nous allons en voir deux.
Fonctions calculables sans algorithme connu
Il existe aussi des fonctions que l'on sait calculables mais dont on ne connaît pas l'algorithme pour les calculer. Par exemple :
Nom : 5-consécutifs
Entrées :
n : un entier
Programme :
si il existe n "5" consécutifs dans les décimales de π:
rend 1
sinon:
rend 0
Le texte ci-dessus n'est pas un programme car le "il existe" n'est pas une opération élémentaire que je peux effectuer de tête. De plus, sans connaissance a priori, je suis obligé de tester toutes les décimales de $\pi$ pour répondre à la question du "il existe", ce qui fait que s'il n'existe pas n "5" successifs, le programme ne s'arrêtera pas.
Mais en vrai, le texte ci-dessus peut se réécrire de deux façons.
Soit il existe n "5" consécutifs dans les décimales de $\pi$ quel que soit $n$ (on appelle les nombres qui vérifient cette propriété des nombres univers) et alors le programme devient l'algorithme ci-dessous :
Nom : 5-consécutifs
Entrées :
n : un entier
Programme :
rend 1
Soit il existe au plus N "5" consécutifs dans les décimales de $\pi$ et le programme devient :
Nom : 5-consécutifs
Entrées :
n : un entier
Programme :
si n < N + 1:
rendre 1
sinon:
rendre 0
Dans les deux cas, c'est un algorithme. Le problème est que l'on ne sait pas si π est un nombre univers et donc on ne sait pas lequel des deux algorithmes est le bon.
Savoir qu'on peut créer un algorithme pour calculer une fonction ne signifie pas que c'est facile de le faire. Il faut souvent avoir des connaissances annexes, hors algorithmie, sur le problème à résoudre pour le faire.
Fonction écran de fumée
La fonction de Takeuchi est surprenante, bien malin qui sait ce qu'elle fait juste en la regardant.
La fonction de Takeuchi est définie pour tous entiers positifs $x$, $y$ et $z$ telle que :
Pour prouver que cette fonction est calculable il faut montrer deux choses :
- la véracité de la définition
- que le nombre de récursions n'est pas infini
Faisons la première proposition avec un exercice :
Montrez par récurrence sur $k = x+y+z$ que si la définition de la fonction de Takeuchi est bien définie (le nombre de récursions est fini), alors :
corrigé
corrigé
On suppose que $\tau(x, y, z)$ existe pour tous $x, y, z \in \mathbb{N}$. On montre le résultat par récurrence sur $x+y+z= k$.
Si $x+y+z=0$, on a $x=y=z=0$ et $\tau(0, 0, 0) = 0$, la récurrence est vérifiée. On suppose la récurrence vraie pour $x+y+z=k$.
Pour $x+y+z=k+1$, on analyse tous les cas possibles :
- $x \leq y$ : Ok
- $x > y$ et $y \leq
z$ : On a $\tau(x, y, z) = \tau(\tau(x-1, y, z), \tau(y-1, z, x), \tau(z-1, x, y))$ :
- on a $y-1 \leq z$ donc (par hypothèse de récurrence) $\tau(y-1, z, x) = z$
- soit $x-1 > y$ et $y \leq z$ et alors (par hypothèse de récurrence) $\tau(x-1, y, z) = z$ : $\tau(x, y, z) = \tau(z, z, ?) = z$
- soit $x-1 \leq y$ et alors (par hypothèse de récurrence) $\tau(x-1, y, z) = y$ : $\tau(y, z, ?) = z$ (puisque $y \leq z$)
- $x > y > z$ : On a $\tau(x, y, z) = \tau(\tau(x-1, y, z), \tau(y-1, z, x), \tau(z-1, x, y))$
- on a $z-1 < y< x$ et donc $\tau(x, y, z) = \tau(\tau(x-1, y, z), \tau(y-1, z, x), x)$
- on procède de même que précédemment en analysant tous les cas :
- $x-1 > y$ et $y-1>z$ : $\tau(x, y, z) = \tau(x-1, x, x) = x$
- $x-1 > y$ et $y-1=z$ : $\tau(x, y, z) = \tau(x-1, z, x) = x$
- $x-1 = y$ et $y-1>z$ : $\tau(x, y, z) = \tau(y, x, x) = x$
- $x-1 = y$ et $y-1=z$ : $\tau(x, y, z) = \tau(y, z, x) = x$
Il nous reste à montrer que le nombre d'itérations est bien fini. Ce n'est en effet pas parce que l'équation de récurrence admet une solution qu'on peut la calculer avec un algorithme, c'est-à-dire en temps fini. On utilise pour cela l'exercice précédent et une récurrence :
Proposition
La fonction $\tau(x, y, z)$ de Takeuchi est bien définie en un nombre fini de récursions et sa valeur vaut :
preuve
preuve
On va encore une fois le prouver par récurrence sur $x+y+z= k$.
Si $x+y+z=0$, on a $x=y=z=0$ et $\tau(0, 0, 0) = 0$ en 0 récursion puisque $x \leq y$, la récurrence est vérifiée. On suppose la récurrence vraie pour $x+y+z=k$.
Pour $x+y+z=k+1$, on analyse tous les cas possibles :
-
$x \leq y$ : Ok en 0 récursion
-
$x > y$ et $y \leq z$ : On a $\tau(x, y, z) = \tau(\tau(x-1, y, z), \tau(y-1, z, x), \tau(z-1, x, y))$. Par hypothèse de récurrence $\tau(x-1, y, z)$, $\tau(y-1, z, x)$ et $\tau(z-1, x, y)$ existent et ne peuvent valoir (exercice précédent) que :
- $\tau(y-1, z, x) = z$
- soit $x-1 > y$ et $y \leq z$ et alors (par hypothèse de récurrence) $\tau(x-1, y, z) = z$
- soit $x-1 \leq y$ et alors (par hypothèse de récurrence) $\tau(x-1, y, z) = y$
On a alors soit $\tau(x, y, z) = \tau(z, z, ?)$, soit $\tau(x, y, z) = \tau(y, z, ?)$ ce qui donne sans nouvelle récursion $\tau(x, y, z) = \tau(z, z, ?) = \tau(y, z, ?) = z$ (on a $y \leq z$).
-
$x > y > z$ : On a $\tau(x, y, z) = \tau(\tau(x-1, y, z), \tau(y-1, z, x), \tau(z-1, x, y))$. Par hypothèse de récurrence $\tau(x-1, y, z)$, $\tau(y-1, z, x)$ et $\tau(z-1, x, y)$ existent et ne peuvent valoir (exercice précédent) que :
- $\tau(z-1, x, y) = x$
- $x-1 > y$ et $y-1>z$ : $\tau(x, y, z) = \tau(x-1, x, x)$. Comme $x-1 \leq x$ on a $\tau(x, y, z) = x$ sans nouvelle récursion.
- $x-1 = y$ et $y-1>z$ : $\tau(x, y, z) = \tau(y, x, x)$. Comme $x > y$ on a $\tau(x, y, z) = x$ sans nouvelle récursion
- $x-1 > y$ et $y-1=z$ : $\tau(x, y, z) = \tau(x-1, z, x)$. On a $x-1 > z$ et $x > x-1$, on est ramené au cas précédent ($x > y$ et $y \leq z$) qui converge avec une récursion en plus
- $x-1 = y$ et $y-1=z$ : $\tau(x, y, z) = \tau(y, z, x)$. On a $y > z$ et $x > y$, on est ramené au cas précédent ($x > y$ et $y \leq z$) qui converge avec une récursion en plus.
Cette fonction montre, encore une fois, qu'il est très difficile de déterminer ce que fait un algorithme sans l'analyser finement (voyez-le comme un exemple du théorème de Rice vu précédemment).
La fonction de Takeuchi montre que pour résoudre un problème simple il existe des solutions compliquées.
Lorsque vous essayez de résoudre un problème avec un algorithme, essayez toujours de trouver la solution la plus simple possible. Vous verrez que souvent, sans réfléchir on va produire la version compliquée plutôt que la version simple.
Non calculabilité
Trouver une fonction ou un nombre qu'on ne peut pas calculer est un exercice mental compliqué. En effet, si l'on pense à un nombre précis, on lui associe une définition et donc très souvent un moyen de le construire. Mais ces objets existent puisqu'il y a strictement plus de fonctions et de réels que d'algorithmes.
Nous allons donner un exemple de chaque ci-après.
Un nombre non calculable : $\Omega$ de Chaitin
Nous allons montrer un nombre non calculable, dérivé du célèbre nombre oméga de Chaitin, lui aussi non calculable.
Rangeons, comme on l'a fait pour la complexité de Kolmogorov, tous les programmes sans paramètre dans l'ordre lexicographique. Nommons les programmes selon cet ordre : $P_1$ le premier programme, $P_2$ le second, etc.
Le nombre $\Omega$ est un réel entre 0 et 1 tel que sa $i$-ème décimale soit :
- égale à 1 si le programme $P_i$ s'arrête
- égale à 0 si le programme $P_i$ ne s'arrête pas
Ce nombre existe mais n'est évidemment pas calculable car si on pouvait le faire, le problème de l'arrêt serait décidable.
Une fonction non calculable : la complexité de Kolmogorov
La complexité de Kolmogorov est un exemple classique de fonction non calculable.
La complexité de Kolmogorov est une fonction $k: \mathbb{N} \rightarrow \mathbb{N}$ telle que $k(n)$ soit le nombre de caractères minimum d'un algorithme sans paramètre dont la sortie est l'affichage à l'écran du nombre $n$
La valeur de la fonction va dépendre de la langue utilisée bien sûr. Il est probable que la complexité de Kolmogorov allemande soit plus grande que la complexité de Kolmogorov anglaise ou chinoise.
La définition semble idiote. Pour rendre 5 il suffit d'utiliser l'algorithme trivial qui écrit directement le nombre :
affiche à l'écran la chaîne de caractères "5"
Mais il faut écrire $\log_{10}(n)$ chiffres dans l'algorithme, ce qui donne une taille de $\log_{10}(n) + 42 + 2$ (le nombre en base 10, le texte avant l'affichage et les deux "). Si ce nombre est gros, on peut faire bien mieux.
Par exemple :
affiche à l'écran 1000 caractères "1" consécutifs
Possède 49 caractères et permet d'écrire un nombre de 1000 chiffres ! La question du nombre minimal de caractères est donc une question pertinente, ou au moins légitime.
Proposition
La fonction $k(n)$ existe.
preuve
preuve
En rangeant tous les textes possibles par ordre lexicographique : d'abord les textes à 1 caractère, puis les textes à 2 caractères, etc. on va forcément trouver l'algorithme trivial qui donne une réponse. Parmi tous les textes plus petits ou égaux à l'algorithme trivial (le nôtre possède, on l'a vu $\log_{10}(n) + 42 + 2$ caractères), il y en a un nombre fini, on peut en extraire tous les programmes (facile, ce sont les textes qui veulent dire quelque chose algorithmiquement) et notre algorithme minimum est dedans.
La difficulté réside bien sûr dans le fait de savoir si tel ou tel programme rend la notation binaire de $n$ ou pas (c'est encore une fois le théorème de Rice qui entre en jeu).
On a maintenant assez de billes pour démontrer la non-calculabilité de la complexité de Kolmogorov :
Théorème
La complexité de Kolmogorov n'est pas calculable.
preuve
preuve
Supposons que la complexité de Kolmogorov soit calculable. Notons Kolmogorov(n) un algorithme la calculant et $K$ le nombre de caractères de celui-ci.
On peut alors définir l'algorithme sans paramètre suivant :
n = 0
tant que Kolmogorov(n) < K + 1000:
n = n + 1
affiche n à l'écran
Ce programme (de 75 caractères, caractère "aller à la ligne" compris) est bien un algorithme car :
Kolmogorov(n)est un algorithme- il y a un nombre infini de nombres mais seulement un nombre fini d'algorithmes sans paramètres ayant moins de $K + 1000$ caractères : il existe forcément un nombre qui n'est pas la sortie d'un algorithme sans paramètre de moins de $K + 1000$ caractères.
Le retour de cet algorithme sans paramètre est le plus petit nombre de complexité de Kolmogorov plus grand que $K + 1000$. Mais ceci est impossible puisqu'il est déterminé par notre algorithme qui fait, en lui concaténant l'algorithme de Kolmogorov(n) pour qu'il soit indépendant, bien moins de $K + 1000$ caractères.
Notre hypothèse de départ est donc fausse : la complexité de Kolmogorov n'est pas calculable.