• Aucun résultat trouvé

Une équationdiophantienneest une équation à coefficients entiers dont on s’intéresse aux solutions entières (si elles existent), comme par exemple celle-ci :

(x−1)! + 1 =xy (1.1)

Elles ont été étudiées depuis l’antiquité notamment par Diophante d’Alexandrie, un mathématicien grec due siècle. Par exemple, le théorème de Wilson établit que l’équa-tion (1.1) possède une solul’équa-tion avecx >1 si et seulement sixest premier. Dit autrement l’ensemble des x > 1 qui font parties des solutions décrit exactement l’ensemble des nombres premiers. Par exemple, six= 5, alors l’équation implique (5−1)! + 1 = 25 = 5y, soity= 5. Mais six= 6, alors l’équation implique (6−1)! + 1 = 121 = 6y qui n’a pas de solution entière.

Ces équations, souvent très simples, sont parfois extrêmement difficiles à résoudre.

Le dernier théorème de Fermat en est un exemple (cf. figure1.4). Il aura fallut 357 ans d’efforts pour démontrer en, grâce à Andrew Wiles, que l’équation

xp+yp = zp (1.2)

n’a pas de solution entière strictement positive dès quep >2. Pourp= 2, les solutions (x, y, z) sont appelées « triplets pythagoriciens », comme (3,4,5). Ce n’est pas plus facile pour les systèmes d’équations diophantiennespolynomiales7comme

y

7. C’est-à-dire dont les variables ont des exposants qui sont des naturels.

1.2. DES PROBLÈMES INDÉCIDABLES 7 Figure 1.4 – Édition de de l’ou-vrage de Diophante. Le texte reprend la note de  (traduite ici en la-tin) de Pierre Fermat concernant le problème II.VIII à propos de l’équa-tion diophantiennexp+yp =zp :« Au contraire, il est impossible de partager soit un cube en deux cubes, soit un bi-carré en deux bibi-carrés, soit en général une puissance quelconque supérieure au carré en deux puissances de même degré : j’en ai découvert une démonstration vé-ritablement merveilleuse que cette marge est trop étroite pour contenir. » Source Wikipédia.

On ne sait pas si ce système, qui exprime les contraintes de longueurs et de diagonales d’une brique8, possède ou non de solutions entières non nulles.

En fait, c’est même pire pour les systèmes. Le problème de savoir si un système d’équations diophantiennes polynomiales avec au plus 11 variables possède ou non une solution (entière) est indécidable. Remarquons qu’on peut toujours se ramener à une seule équation diophantienne polynomiale, qui donnerait pour le système précédent :

(a2x2y2)2+ (b2y2z2)2+ (c2z2x2)2+ (d2x2y2z2)2 = 0. (1.3) Il faut bien distinguer les problèmes indécidables avec les problèmes sans solution.

On mélange souvent les notions d’instance et de problème. Une équation diophan-tienne, comme l’équation (1.2) ou (1.3), est ici une instance. Elle possède ou ne possède pas de solution entière. Et pour certaines d’entre elles, c’est facile de le décider : il suffit d’appliquer un théorème. Mais le problème est de trouver une procédure systématique qui, pourtouteéquation diophantienne (soit toute instance), détermine s’il existe ou pas de solution entière. Personne ne peut prétendre avoir trouvé un tel algorithme, car cet algorithme n’existe pas ! Et on sait prouver qu’il n’existe pas.

Parenthèse. La quadrature du cercle, qui consiste à trouver la construction d’un carré de surface égale à celle d’un cercle donné avec une règle et un compas, est un exemple de problème qui, du point de vue algorithmique, est inintéressant ou plutôt « trivial ». En effet, il n’y a pas d’entrées. L’ensemble des instances sont vides et le problème se résume donc à la

« question ». Il suit qu’il existe un algorithme trivial (et même un programme) :

8. Cettebrique parfaite d’Euler, si elle existe, doit avoir ses arêtes de longueur au moins 5×1011. En

, il a été trouvé la plus petite solution satisfaisant seulement les trois premières équations : (x, y, z) = (44,117,240) et (a, b, c) = (125,244,267).

8 CHAPITRE 1. INTRODUCTION bool quadrature_du_cercle(void){ return false; }

La justification de cette ligne a nécessité deux millénaires de recherches et peut être trouvée par exemple dans la vidéo 2 000 Years Unsolvedde Mathologer. Pour que les notions de complexités (associées aux algorithmes) aient un sens, il faut pouvoir définir la taille des instances et qu’il y en ait une infinité (cf. page1.4). Sans quoi tout devient « trivial » dans le sens où les algorithmes solutions existent et sont de complexité constante.

Prouver qu’un algorithme n’existe pas. On va expliquer comment prouver qu’un al-gorithme n’existe pas avec le problème suivant, indécidable donc, et qui est cher aux informaticiens et informaticiennes.

Halte

Instance: Un programmef avec une entréex.

Question: Est-ce que l’évaluation def(x) s’arrête ou boucle indéfiniment ?

Encore une fois, il est clair que chaque programme sur une entrée donnée s’arrête au bout d’un moment ou alors boucle indéfiniment9. Il n’y a pas d’intermédiaire. Seule-ment, il n’existe pas d’algorithme qui à coup sûr peut déterminer pour tout programme f et entréex, si l’évaluation def(x) s’arrête.

Le point commun de ces problèmes indécidables, et ce qui les rend si difficiles à résoudre automatiquement, c’est qu’on arrive pas à dire si tous les cas ont été examinés et donc à dire s’il finira par s’arrêter sur la bonne décision. On peut parfaitement lister les suites d’entiers (x, y, z, p) avec p >2 ou simuler l’exécution du programme f(x). Si l’équation (1.2) est satisfaite ou si le programme s’arrête, on pourra décider car on va s’en apercevoir. Mais sinon, comment décider ? Faut-il continuer la recherche ou bien s’arrêter et répondre qu’il y a pas de solution ou que le programme boucle ? En fait, on a la réponse pour l’équation (1.2) grâce à un théorème (Andrew Wiles). Mais on n’a pas de théorème pour chaque équation diophantienne possible !

Mais comment montrer qu’un problème n’a pas d’algorithme ? Supposons qu’on dis-pose d’une fonction halte(f,x) permettant de dire si une fonction f écrite en C du typevoid f(int x) s’arrête pour l’entierx (=true) ou boucle pour toujours (=false). La fonctionhalte(), aussi compliquée qu’elle soit, implémente donc un certain algorithme censé être correct qui termine toujours sur la bonne réponse. Son prototype serait10:

bool halte(void (*f)(int),int)

9. Il s’agit d’une position de principe : il est clair qu’un programme, lorsqu’il est exécuté sur un vrai ordinateur, s’arrêtera toujours au bout d’un moment, ne serait-ce qu’à cause du vieillissement de ses composants et de la finitude de la quantité d’énergie électrique consommable.

10. Dans une déclaration du prototype d’une fonction, dans un.hpar exemple, il n’est pas nécessaire de préciser le nom des paramètres, sauf pour les paramètres qui sont eux-mêmes des fonctions.

1.2. DES PROBLÈMES INDÉCIDABLES 9 Considérons le programme loop() ci-dessous faisant appel à la fonction hypothé-tiquehalte():

bool halte(void (*f)(int),int); // fonction définie quelque part void loop(int x){

if(halte(loop,x)) for(;;); // ici loop(x) va boucler

} // ici loop(x) se termine

Parenthèse.

• Le détournement de l’instructionfor en for(;;); permet de boucler indéfiniment.

On aurait aussi pu mettre while(true);ouwhile(1);qui ont le même effet, mais qui sont plus long à écrire.

• EnCle nom des fonctions, commefouloop, est vu comme un pointeur représentant l’adresse mémoire où elles sont stockées et codées en machine, un peu comme le nom d’un tableau. On peut donc passer en paramètre une fonction simplement en spéci-fiant son nom sans le préfixer avec &, la marque de référencement qui permet d’avoir l’adresse où est stocké un objet. Mais ce n’est pas faux de le mettre ! Ainsi on peut écrire indifféremmenthalte(loop,x)ouhalte(&loop,x).

La question est de savoir ce qu’il se passe lorsqu’on fait un appel à loop(0) par exemple. Est-ce loop(0) termine ou boucle ? D’après son code, loop(0) terminera si et seulement sihalte(loop,0)est faux, c’est-à-dire si et seulement siloop(0)boucle ! C’est clairement une contradiction, montrant que la fonctionhalte(f,x)ne peut pas être cor-recte pour toute fonction f() et tout paramètre x. Le problème de la Halte n’a pas d’algorithme. C’est donc un problème indécidable.

Notons que l’argument utilisé n’est rien d’autre que celui de l’impossibilité de l’oracle du futur. Si un oracle pouvait prédire le futur, alors on pourrait faire le contraire et contredire son existence. (À supposer, bien évidemment, que la prédiction intervienne avant le dît futur et qu’on dispose suffisamment de liberté pour agir contre la prédic-tion.) Les algorithmes ont trop de puissance (et leur concepteur trop de liberté) pour qu’on prédise correctement leurs futurs sans avoir à les exécuter...

Parenthèse. Dans la preuve on remarque que l’on aurait pu se passer complètement de l’argumentx. L’indécidabilité s’applique donc aussi aux programmes sans paramètre. Elle s’applique aussi aux programmes ayant un nombre arbitraire de paramètres en se ramenant au cas d’un seul paramètre. Pour des paramètres entiers non nuls par exemple, il suffit d’utiliser une transformation11(x1, x2, x3, . . .)7→x= 2x1·3x2·5x3· · ·=Q

i=1pxii,piétant le inombre premier. Enfin, il existe d’autres preuves (par diagonalisation) qui évite d’utiliser loopdans le corps de la fonctionloop(), ce qui suppose un langage qui le supporte, comme leC.

Un autre exemple bien connu de problème indécidable est lacomplexité de Kolmogo-rov. Cet exemple n’utilise pas d’auto-référence. NotéeK(n), elle est définie pour toutn∈N 11. Transformation bijective d’après le Théorème fondamental de l’arithmétique de décomposition en produits de facteurs premiers.

10 CHAPITRE 1. INTRODUCTION comme le nombre de caractères du plus court programme, disons écrit12 enC, qui affiche l’entiernet qui s’arrête. La fonctionK(n)n’est pas calculable par un algorithme.

Pourquoi ? Supposons qu’il existe un tel algorithme capable de calculer la fonctionK(n).

Cet algorithme est une suite finie d’instructions, et donc peut-être codé par une fonctionK() écrites enCdont le code comprend un total de, disons,kcaractères. Ce programme est ainsi capable de renvoyer la valeurK(i)pour tout entieri.

Considérons le programmeP()ci-dessous faisant appel à la fonctionK()et qui affiche le plus petit entier de complexité de Kolmogorov au moinsn:

int K(int); // fonction dont le code est défini quelque part void P(int n){

for(int i=0; K(i)<n; i++);

printf("%d",i); // ici K(i)>n }

Même si cela semble assez clair, montrons que ce programme s’arrête toujours. Il s’agit d’un argument de comptage. Soit ρ(n) le nombre de programmes C ayant moins de n ca-ractères13. Par définition deK(i), chaque entieripossède un programme deK(i)caractères qui afficheiet s’arrête. Ces programmes sont tous différents14. Siidépasseρ(n), alors tous les entiers de l’intervalle [0, ρ(n)] auront été examinées. Il y en a ρ(n) + 1, et donc tous ne peuvent prétendre avoir un programme différent qui fasse moins dencaractères. Donc K(i)>npour au moins un certain entieri∈[0, ρ(n)]ce qui montre bien queP(n)s’arrête toujours (à cause du testK(i)<nqui va devenir faux). L’entier affiché parP(n), disonsin, est le plus petit d’entre eux. Et bien évidemmentK(in)>npuisque le test est faux.

La fonction P() à proprement parlée fait 53 caractères, sans compter les retours à la ligne qui ne sont pas nécessaires enC. Il faut ajouter à cela le code de la fonctionK()qui par hypothèse est dekcaractères. Notons que la fonctionP()dépend den, mais la taille du code deP()ne dépend pas den. Idem pour le paramètre de la fonctionK(). Il s’agit de paramètres formels. Pour s’en convaincre, il faut imaginer que chaqueintaurait pu être représenté par une chaîne de caractèreschar* donnant la liste de ses chiffres. Donc le paramètre n et la variableipeuvent être vus comme des « pointeurs » dont la taille ne dépend pas de ce qu’ils pointent. (D’ailleurs si on désassemblait de code deP(), on constaterait quenetisont des adresses mémoires de la pile.) Dans notre calcul de la taille du programme, ils ne font qu’un seul caractère, ce qui ne dépend en rien de la valeur qu’ils représentent. Donc au total, le code qui permet de d’afficher l’entierP(n)fait53+kcaractères, une constante qui ne dépend pas den. Quen= 7oun= 123456789, la taille deP()est exactement la même.

12. On peut montrer que la complexitéK(n) ne dépend qu’à une constante additive près du langage considéré (la taille d’un compilateur par exemple).

13. Bien que la valeur exacte deρ(n) n’a ici aucune espèce d’importance, on peut quand même en donner une valeur approximative. Si on se concentre sur les programmes écrits en caractères ASCII (en excluant les commentaires avec des caractères accentués), sur 7-bits donc, alors il y a au plus 27t pro-grammes d’exactementt caractères. En fait beaucoup d’entre-eux ne compilent même pas, et très peu affichent un entier et s’arrêtent. Il y a des programmes det = 0,1,2, . . . jusqu’à n1 caractères, d’où ρ(n)6Pn1

t=027t= (27n1)/(271)<128n.

14. On utilise ici « l’arrêt » dans la définition deK(n). Sinon, le même programme pourrait potentielle-ment afficher plusieurs entiers s’il ne s’arrêtait pas. Par exemple, le code suivant de 32 caractères affiche n’importe quel entieri, n’est-ce pas ?for(int i=0;;) printf("%d",i++);01234567891011...

1.3. APPROCHE EXHAUSTIVE 11