Exercice 0. QCM d’activation
Pour chaque question, une seule réponse est correcte.
Question 1. Le problème de l’arrêt consiste à déterminer :
- A) si un programme s’exécute en temps polynomial
- B) si un programme finira par s’arrêter pour une entrée donnée
- C) combien de temps un programme met à s’exécuter
- D) si un programme contient des erreurs de syntaxe
Correction
Réponse B. Le problème de l’arrêt demande : « étant donné un programme P et une entrée E, est-ce que P finit par s’arrêter quand on l’exécute sur E ? ». Alan Turing a démontré en 1936 qu’il est impossible d’écrire un programme qui résout ce problème dans tous les cas.
- A est faux : déterminer un temps d’exécution polynomial relève de la complexité, pas de la terminaison ;
- C est faux : la complexité temporelle est un autre problème ;
- D est faux : les erreurs de syntaxe sont détectables par un compilateur ou un interpréteur.
Question 2. Un problème est dit « décidable » si :
- A) il admet au moins une solution
- B) il existe un algorithme qui répond toujours correctement par oui ou non en temps fini
- C) il peut être résolu uniquement par un humain
- D) il ne peut être résolu que par force brute
Correction
Réponse B. Un problème de décision est décidable s’il existe un algorithme (une machine de Turing) qui, pour toute instance du problème, s’arrête en temps fini et donne la bonne réponse (oui ou non).
- A est faux : admettre une solution ne signifie pas qu’on peut la trouver algorithmiquement ;
- C est faux : la décidabilité concerne les algorithmes, pas les humains ;
- D est faux : la méthode de résolution n’est pas contrainte à la force brute.
Question 3. Le problème de l’arrêt est :
- A) décidable et de complexité polynomiale
- B) décidable mais de complexité exponentielle
- C) indécidable
- D) décidable uniquement pour les programmes récursifs
Correction
Réponse C. Turing a prouvé par un raisonnement par l’absurde qu’aucun algorithme ne peut résoudre le problème de l’arrêt dans le cas général. C’est l’exemple fondateur de problème indécidable.
- A et B sont faux : le problème n’est pas décidable du tout ;
- D est faux : le problème est indécidable quel que soit le type de programme.
Question 4. Un problème de la classe NP est un problème :
- A) impossible à résoudre
- B) dont on peut vérifier une solution en temps polynomial
- C) qui ne peut être résolu qu’en temps exponentiel
- D) qui n’a pas de solution
Correction
Réponse B. Un problème est dans NP (nondeterministic polynomial) si, étant donnée une solution candidate, on peut vérifier en temps polynomial qu’elle est correcte. Cela ne signifie pas que trouver la solution est nécessairement long.
- A est faux : les problèmes NP sont résolubles (en temps éventuellement exponentiel) ;
- C est faux : certains problèmes NP sont aussi dans P (résolubles en temps polynomial) ;
- D est faux : les problèmes NP ont des solutions.
Question 5. La question ouverte « P = NP ? » demande si :
- A) tous les problèmes informatiques sont résolubles
- B) tout problème dont on peut vérifier la solution rapidement peut aussi être résolu rapidement
- C) les machines de Turing sont plus puissantes que les ordinateurs actuels
- D) le problème de l’arrêt peut être résolu
Correction
Réponse B. La question P = NP demande si tout problème dont la solution est vérifiable en temps polynomial (classe NP) est aussi résoluble en temps polynomial (classe P). C’est l’un des plus grands problèmes ouverts en informatique et en mathématiques.
- A est faux : certains problèmes sont indécidables, indépendamment de P vs NP ;
- C est faux : les machines de Turing sont un modèle théorique équivalent en puissance aux ordinateurs ;
- D est faux : le problème de l’arrêt est indécidable, ce qui est un résultat établi.
Exercice 1 – Programme comme donnée
- Expliquer en quelques phrases pourquoi un programme peut être considéré comme « une donnée comme une autre ».
- Donner un exemple concret où un programme prend un autre programme en paramètre.
- Qu’est-ce qu’un quine ? Exécuter dans un interpréteur Python la ligne suivante et observer le résultat :
a='a=%r;print(a%%a)';print(a%a)
Correction
Un programme est stocké sous forme de texte (son code-source), qui est une suite de caractères. Cette suite de caractères peut être lue, transmise ou analysée par un autre programme, exactement comme n’importe quelle autre donnée. Par exemple, quand on exécute
python3 test.py, le programmepython3reçoit en paramètre le fichiertest.pyqui contient le code-source d’un autre programme.L’interpréteur Python est un programme qui prend en paramètre le code-source d’un programme Python. De même, un compilateur C prend en paramètre un fichier
.cet produit un exécutable. Autre exemple : un débogueur est un programme qui analyse l’exécution d’un autre programme.Un quine est un programme qui affiche son propre code-source sans lire aucun fichier. La ligne
a='a=%r;print(a%%a)';print(a%a)affiche exactementa='a=%r;print(a%%a)';print(a%a), c’est-à-dire elle-même.
Exercice 2 – Le programme countdown
Considérons le programme :
def countdown(n):
while n != 0:
print(n)
n = n - 1
print("fini")
- Que fait
countdown(5)? S’arrête-t-il ? - Que fait
countdown(-3)? Justifier. - Que fait
countdown(2.5)? Justifier. - Modifier le programme pour qu’il s’arrête dans tous les cas (entier, flottant, négatif).
Correction
countdown(5)affiche 5, 4, 3, 2, 1, puis « fini ». Il s’arrête carnatteint 0 après cinq itérations.countdown(-3)ne s’arrête jamais (boucle infinie). La conditionn != 0est toujours vraie carnvaut successivement −3, −4, −5, … et ne sera jamais égal à 0.countdown(2.5)ne s’arrête jamais (boucle infinie). Les valeurs successives densont 2.5, 1.5, 0.5, −0.5, −1.5, … La valeur 0 n’est jamais atteinte.Version corrigée :
def countdown(n): while n > 0: # remplacer != par > print(int(n)) n = n - 1 print("fini")Avec
n > 0, la boucle s’arrête dès quendevient négatif ou nul, quel que soit le type den.
Exercice 3 – La preuve par l’absurde du problème de l’arrêt
On suppose qu’il existe une fonction halt(prog, entree) qui renvoie True si le programme prog s’arrête quand on lui donne entree, et False sinon. On définit alors :
def sym(prog):
if halt(prog, prog):
while True:
pass
else:
return 0
- Que fait
sym(sym)sihalt(sym, sym)renvoieTrue? - Que fait
sym(sym)sihalt(sym, sym)renvoieFalse? - En déduire la contradiction et conclure.
Correction
Si
halt(sym, sym)renvoieTrue, cela signifie quesym(sym)devrait s’arrêter. Or, dans ce cas,symentre dans la boucle infiniewhile Trueet ne s’arrête jamais. Contradiction.Si
halt(sym, sym)renvoieFalse, cela signifie quesym(sym)ne devrait pas s’arrêter. Or, dans ce cas,symexécutereturn 0et s’arrête. Contradiction.Dans les deux cas, la prédiction de
haltest fausse. Donc la fonctionhaltne peut pas exister : le problème de l’arrêt est indécidable.
La preuve procède par l’absurde : on suppose que halt existe, on construit sym qui contredit systématiquement la prédiction, et on arrive à une contradiction dans tous les cas.
Exercice 4 – Décidable ou indécidable ?
Pour chacun des problèmes suivants, indiquer s’il est décidable ou indécidable. Justifier brièvement.
- Déterminer si un nombre entier donné est premier.
- Déterminer si un programme Python donné affiche
"bonjour"au moins une fois. - Déterminer si une liste triée contient un élément donné.
- Déterminer si deux programmes Python calculent toujours la même chose pour les mêmes entrées.
- Déterminer si un entier donné est pair.
- Déterminer si un programme Python donné contient une boucle
while.
Correction
Décidable. Il existe des algorithmes de test de primalité qui terminent toujours (divisions successives, Miller-Rabin, AKS).
Indécidable. C’est une question sémantique (sur le comportement) d’un programme arbitraire. Par le théorème de Rice, toute question sémantique non triviale sur un programme est indécidable.
Décidable. La recherche dichotomique termine toujours et donne une réponse en \(\mathcal{O}(\log n)\).
Indécidable. C’est le problème de l’équivalence de programmes, auquel se réduit le problème de l’arrêt (théorème de Rice).
Décidable. Il suffit de tester si
n % 2 == 0. L’algorithme termine toujours.Décidable. C’est une question syntaxique (sur la forme du code, pas sur son comportement). Il suffit de chercher le mot-clé
whiledans le code-source. Le théorème de Rice ne s’applique qu’aux questions sémantiques.
Exercice 5 – P, NP, NP-complet
Classer les problèmes suivants dans la catégorie qui convient (P, NP, NP-complet). Justifier.
- Trier une liste de \(n\) nombres.
- Déterminer si un graphe admet un cycle hamiltonien (passant par chaque sommet exactement une fois).
- Rechercher un élément dans une liste triée.
- Le problème du sac à dos (version décision).
- Multiplier deux matrices \(n \times n\).
Correction
P. Le tri fusion résout ce problème en \(\mathcal{O}(n \log n)\), qui est polynomial.
NP-complet. Aucun algorithme polynomial n’est connu. En revanche, si on propose un cycle, on peut vérifier en temps polynomial qu’il est hamiltonien (il suffit de vérifier que chaque sommet apparaît exactement une fois et que les arêtes existent).
P. La recherche dichotomique résout ce problème en \(\mathcal{O}(\log n)\).
NP-complet. La version décision du sac à dos (« peut-on atteindre exactement la valeur \(V\) sans dépasser la capacité ? ») est NP-complète. Vérifier qu’un ensemble d’objets satisfait les contraintes est polynomial, mais trouver cet ensemble ne l’est pas (en l’état des connaissances).
P. La multiplication de matrices se fait en \(\mathcal{O}(n^3)\) (algorithme classique) ou mieux avec l’algorithme de Strassen en \(\mathcal{O}(n^{2.81})\). Ces complexités sont polynomiales.
Exercice 6 – Vrai ou faux
Pour chaque affirmation, indiquer si elle est vraie ou fausse et justifier.
- « Le problème de l’arrêt montre que certains programmes ne s’arrêtent jamais. »
- « Si un problème est dans NP, alors il est difficile à résoudre. »
- « Tous les problèmes de P sont aussi dans NP. »
- « NP signifie “non polynomial”. »
- « Si on prouvait que P = NP, la cryptographie RSA serait menacée. »
- « Le théorème de Rice dit que toute question sur un programme est indécidable. »
Correction
Faux. Le problème de l’arrêt ne dit pas que certains programmes ne s’arrêtent pas (cela, on le sait déjà avec les boucles infinies). Il dit qu’aucun algorithme ne peut prédire de manière générale si un programme donné va s’arrêter ou non.
Faux. Tout problème de P est aussi dans NP, et les problèmes de P ne sont pas considérés comme difficiles. NP contient des problèmes faciles (P) et des problèmes potentiellement difficiles (NP-complets).
Vrai. Si un problème peut être résolu en temps polynomial, alors sa solution peut aussi être vérifiée en temps polynomial. Donc P ⊂ NP.
Faux. NP signifie « Non-déterministe Polynomial », c’est-à-dire résolu en temps polynomial par une machine de Turing non déterministe.
Vrai. La sécurité du RSA repose sur le fait que la factorisation de grands nombres est considérée comme difficile (pas dans P). Si P = NP, la factorisation aurait un algorithme polynomial, ce qui rendrait le RSA vulnérable.
Faux. Le théorème de Rice concerne les questions sémantiques (sur le comportement) et non triviales. Les questions syntaxiques (sur la forme du code) restent décidables. Par exemple, « ce programme contient-il une boucle
for? » est décidable.
Exercice 7 – Réduction au problème de l’arrêt
On veut montrer que le problème suivant est indécidable : « étant donné un programme prog, est-ce que prog(0) renvoie la valeur 42 ? »
- Supposons qu’il existe un programme
test42(prog)qui renvoieTruesiprog(0)renvoie 42, etFalsesinon. Construire, à partir detest42, un programme capable de résoudre le problème de l’arrêt. - En déduire que le problème «
prog(0)renvoie-t-il 42 ? » est indécidable.
Indication : pour un programme p et une entrée x donnés, construire un nouveau programme q tel que q(0) renvoie 42 si et seulement si p(x) s’arrête.
Correction
Soit
pun programme etxune entrée. On construit le programmeqsuivant :def q(n): p(x) # on exécute p(x) ; si p(x) ne s'arrête pas, q non plus return 42 # atteint seulement si p(x) s'arrêteSi
p(x)s’arrête, alorsq(0)exécutep(x)puis renvoie 42. Donctest42(q)renvoieTrue.Si
p(x)ne s’arrête pas, alorsq(0)boucle indéfiniment et ne renvoie jamais 42. Donctest42(q)renvoieFalse.On a donc :
test42(q)renvoieTruesi et seulement sip(x)s’arrête. Autrement dit,test42permet de résoudre le problème de l’arrêt.Or le problème de l’arrêt est indécidable. Si
test42existait, on pourrait résoudre le problème de l’arrêt, ce qui est impossible. Donctest42ne peut pas exister : le problème «prog(0)renvoie-t-il 42 ? » est indécidable.
C’est un exemple de réduction : on a montré que résoudre le nouveau problème permettrait de résoudre un problème déjà connu comme indécidable.
Exercice 8 – Vérification vs résolution (classe NP)
Le problème du sudoku 9×9 est NP-complet.
- Expliquer ce que signifie « la vérification d’une solution est polynomiale » pour le sudoku. Quelle est la complexité de cette vérification ?
- Pourquoi ne suffit-il pas de « vérifier toutes les grilles possibles » pour résoudre un sudoku ? Estimer le nombre de grilles à tester.
- Le problème du tri d’une liste est dans P. Est-il aussi dans NP ? Justifier.
Correction
Vérifier une grille de sudoku remplie consiste à contrôler que chaque ligne, chaque colonne et chaque bloc 3×3 contient les chiffres de 1 à 9 sans répétition. Il y a 27 groupes de 9 cases à vérifier, soit un nombre fixe de vérifications : la complexité est \(\mathcal{O}(1)\) pour une grille 9×9 (ou \(\mathcal{O}(n^2)\) pour une grille \(n \times n\), ce qui reste polynomial).
Essayer toutes les grilles possibles reviendrait à tester jusqu’à \(9^{81} \approx 2 \times 10^{77}\) configurations (en réalité moins avec les contraintes, mais c’est un nombre astronomique). C’est une approche exponentielle, inenvisageable en pratique.
Oui, le tri est aussi dans NP. Puisque P ⊂ NP, tout problème résolu en temps polynomial est aussi vérifiable en temps polynomial. Concrètement, vérifier qu’une liste est triée se fait en \(\mathcal{O}(n)\) (parcourir la liste et vérifier que chaque élément est inférieur ou égal au suivant).