Calculabilité

On a vu qu'il y a plus de nombres réels que d'algorithmes : il existe donc forcément des choses que ne peut pas calculer un algorithme. On va s'intéresser ici à deux types de choses que peut (ou ne peut pas) calculer un algorithme : des fonctions et des nombre.

Cette introduction à ce 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

Définition

Un nombre $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

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

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

Tous les réels ne sont pas calculables. Ceci est du 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

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)$, quelque soit $x \in [0, 1]$
  • on appelle $r_2$ le second réel $r_2$ , 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 sont $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$ quelque 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, il apparaît forcément dans notre liste). Notre hypothèse était donc 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

On a vu qu 'il existait au plus un nombre dénombrable de programmes, donc au plus autant de programme 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 suspend, mais on 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 sais 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).

Enfin, certains réels sont calculables, même si leurs nombres de décimales sont infinis. 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

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 rependue en europe, on sait que $\pi$ est calculable depuis bien plus longtemps que ça. La 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 suite de speker par exemple.

En conclusion :

À retenir

La quasi-totalité des nombres réels utilisés en mathématiques en tant que tel ($\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 calculable puisqu'il possède une infinité de décimale) son symbole utilisation 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 :

Définition

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 inclue 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

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$ 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 :

À retenir

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 elle la fonction $\mbox{pgcd}(a, b)$ d'Euclide qui rend le plus grand commun diviseur de deux entier positifs $a$ et $b$.

Euclide (environ -300) décrit son algorithme permettant de calculer le plus grand commun diviseur (pgcd) de deux nombres ainsi :

le pgcd de deux nombres n'est pas changé si on remplace le plus grand d'entre eux par leur différence.

Montrer que l'algorithme d'Euclide peut s'écrire sous la forme d'une équation récurrente ayant un nombre fini d'étape.

corrigé

$$ \begin{equation} \mbox{pgcd}(a, b) = \begin{cases} \max(a, b) & \text{si $\min(a, b) = 0$}\\ \mbox{pgcd}(\max(a, b) - \min(a, b), \min(a, b)) & \text{sinon}. \end{cases} \end{equation} $$

Si $a$ et $b$ sont deux entiers positifs et tel que $\min(a, b) > 0$ alors : $\max(a, b) - \min(a, b) < \max(a, b) \geq 0$. Il arrivera donc forcément un moment ou $\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) :

À retenir

Si vous pensez à une fonction il y a toute 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 calculable 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 re-écrire de deux façons.

Soit existe n "5" consécutifs dans les décimales de $\pi$ quelque 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.

À retenir

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

On va montrer deux exemples de fonctions calculables. Ces deux fonctions sont parfois utilisées pour des tests de performance d'ordinateurs car est sont très gourmandes en temps de calcul.

Fonction écran de fumée

La fonction de Takeuchi est surprenante, bien malin qui sait ce qu'elle fait juste en la regardant.

Définition

La fonction de Takeuchi est définie pour tous entiers positifs $x$, $y$ et $z$ telle que :

$$ \tau(x, y, z) = \left\{ \begin{array}{ll} y & \mbox{si } x \leq y\\ \tau(\tau(x-1, y, z), \tau(y-1, z, x), \tau(z-1, x, y)) & \mbox{sinon.} \end{array} \right. $$

Pour prouver que cette fonction est calculable il faut montrer deux choses :

  1. la véracité de la définition
  2. que le nombre de récursion 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écursion est fini), alors :

$$ \tau(x, y, z) = \left\{ \begin{array}{ll} y & \mbox{si } x \leq y\\ z & \mbox{si } x > y \mbox{ et } y \leq z\\ x & \mbox{si } x > y \mbox{ et } y > z\\ \end{array} \right. $$

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ération 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 utiliser 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écursion et sa valeur vaut :

$$ \tau(x, y, z) = \left\{ \begin{array}{ll} y & \mbox{si } x \leq y\\ z & \mbox{si } x > y \mbox{ et } y \leq z\\ x & \mbox{si } x > y \mbox{ et } y > z\\ \end{array} \right. $$

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

À retenir

La fonction de Takeuchi montre que pour résoudre un problème simple il existe des solutions compliquée.

Lorsque vous essayer de résoudre un problème avec un algorithme essayer 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 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 fonction 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 en montrer un nombre non calculable, dérivé du célèbre nombre oméga de Chaitin, lui aussi non dénombrable.

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écimal soit :

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.

Définition

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 sur. 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 fait 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

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 forcement trouver l'algorithme trivial qui donne une réponse. Parmi tous les textes plus petits ou égal à l'algorithme trivial (le notre 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 programme (facile, c'est les texte qui veulent dire quelque chose algorithmiquement) et notre algorithme minimum est dedans.

La difficulté réside bien sur 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

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.