Calculabilité et décidabilité
Cours complet · OCaml (option informatique), chapitre 20 · prépas MPSI et MP, option informatique
Travailler ce chapitre sur Adloun Exercices corrigés de ce chapitre
<i class="fa-solid fa-compass mr-2" style="color:#9A563B"></i>20.1 Introduction et motivation
Tout au long de ce livre, on a écrit des programmes et prouvé qu'ils s'arrêtent (variant, chapitre 4) et calculent juste (invariant). Une question vertigineuse se pose alors : pourrait-on écrire un programme qui décide automatiquement, pour n'importe quel programme, s'il s'arrête ? Plus généralement, tout problème bien posé est-il résoluble par un algorithme ?
La réponse, l'un des plus beaux résultats de l'informatique, est non : il existe des problèmes parfaitement définis qu'aucun programme ne pourra jamais résoudre. Le plus célèbre est le problème de l'arrêt. Ce chapitre final, théorique, en donne la démonstration (par auto-référence, à la Turing) et ses conséquences — notamment pourquoi la terminaison se prouve « à la main », au cas par cas, faute de pouvoir l'automatiser en général.
20.2 Décidable, semi-décidable
Un problème de décision associe à chaque entrée une réponse oui ou non. Il est décidable s'il existe un algorithme qui, sur toute entrée, s'arrête et donne la bonne réponse. Il est semi-décidable s'il existe un algorithme qui s'arrête en répondant oui sur les instances positives, mais peut ne pas s'arrêter sur les négatives.
« Cette liste est-elle triée ? » est décidable : la fonction du chapitre 9 s'arrête toujours.
let rec est_trie l =
match l with
| [] | [_] -> true
| x :: (y :: _ as reste) -> x <= y && est_trie reste
De même « n est-il premier ? », « cet automate accepte-t-il ce mot ? » (chapitre 18), « ce graphe est-il connexe ? » (chapitre 15) : tous décidables, car résolus par des algorithmes qui terminent sur toute entrée.
« Existe-t-il un entier n tel que f n = 0 ? » se résout en essayant n = 0, 1, 2, … :
let cherche_zero f =
let n = ref 0 in
while f !n <> 0 do n := !n + 1 done;
!n
Si un tel n existe, on le trouve (réponse oui). S'il n'en existe aucun, la boucle ne s'arrête jamais. On a un semi-décideur : il confirme les oui, mais ne peut conclure les non.
20.3 Le problème de l'arrêt
Le problème de l'arrêt demande : étant donné un programme p et une entrée x, l'exécution de p sur x s'arrête-t-elle (par opposition à boucler indéfiniment) ?
On pourrait croire qu'il suffit d'« exécuter p sur x et de regarder » : mais si p ne s'arrête pas, on attend… indéfiniment, sans jamais pouvoir répondre non. Cela ne fournit qu'un semi-décideur. La question est : existe-t-il un vrai décideur, qui répond toujours ?
Le problème de l'arrêt est indécidable : aucun algorithme ne peut, pour tout couple (p, x), déterminer en temps fini si p s'arrête sur x.
Démonstration (Démonstration (par l'absurde, auto-référence))
Supposons qu'un tel décideur existe : une fonction arrete p x qui s'arrête toujours et renvoie true ssi le programme p appliqué à l'entrée x s'arrête. Construisons alors :
let diagonale p =
if arrete p p then (while true do () done) (* boucle pour toujours *)
else () (* s'arrête *)
diagonale prend un programme p ; elle boucle si p s'arrête sur lui-même, et s'arrête sinon. Appliquons diagonale à elle-même :
- si
diagonale diagonales'arrête, alorsarrete diagonale diagonalevauttrue, doncdiagonaleboucle — contradiction ; - si elle ne s'arrête pas, alors
arretevautfalse, doncdiagonales'arrête — contradiction.
Dans les deux cas, contradiction. L'hypothèse est fausse : arrete ne peut pas exister.
L'argument est de l'auto-référence (un programme raisonnant sur lui-même), cousin du paradoxe « cette phrase est fausse » et de la diagonale de Cantor. Il est idéalisé : on suppose qu'un programme peut recevoir un (autre) programme en donnée et l'exécuter — ce qui est légitime, un programme n'étant qu'un texte, donc une donnée.
20.4 Conséquences
De l'indécidabilité de l'arrêt découle qu'aucun outil ne peut, pour tout programme : décider s'il s'arrête, s'il est correct, s'il produit telle sortie, s'il a tel bug. Le théorème de Rice généralise : toute propriété non triviale du comportement (de la fonction calculée) d'un programme est indécidable. C'est pourquoi la terminaison se prouve au cas par cas (un variant par boucle, chapitre 4) : il n'existe pas, et il ne peut exister, de « vérificateur universel de terminaison ».
Méthode : Réduction : propager l'indécidabilité
Pour montrer qu'un nouveau problème est indécidable, on le réduit depuis un problème déjà connu indécidable (comme l'arrêt) : on montre que si l'on savait décider , alors on saurait décider . Comme est indécidable, l'est aussi. C'est l'analogue, pour l'indécidabilité, des réductions de complexité.
<i class="fa-solid fa-dumbbell mr-2" style="color:#2E7559"></i>20.5 Exercices résolus
Niveau (application directe du cours)
Pour chacun, dire s'il est décidable : (a) « n est pair » ; (b) « le tableau t contient un 0 » ; (c) « le programme p s'arrête sur 0 ».
Démonstration
(a) Décidable : n mod 2 = 0, qui s'arrête toujours. (b) Décidable : un parcours du tableau (fini) s'arrête toujours. (c) Indécidable : c'est un cas particulier du problème de l'arrêt — décider l'arrêt sur l'entrée 0 pour tout p permettrait… de décider l'arrêt.
Écrire un décideur pour « tous les éléments de la liste l sont positifs » et justifier qu'il s'arrête toujours.
Démonstration
let rec tous_positifs l =
match l with
| [] -> true
| x :: reste -> x > 0 && tous_positifs reste
La récursion porte sur une liste strictement plus courte à chaque appel : elle atteint [] en un nombre fini d'étapes (variant : la longueur). La fonction s'arrête sur toute entrée et donne la bonne réponse : le problème est décidable.
Pourquoi exécuter p sur x et « regarder si ça s'arrête » ne donne-t-il pas un décideur de l'arrêt ?
Démonstration
Si p s'arrête, on le constate au bout d'un temps fini (réponse oui). Mais si p boucle, l'observation ne se termine jamais : on ne pourra jamais répondre non avec certitude — peut-être s'arrêtera-t-il à l'étape suivante ? On obtient un semi-décideur (correct sur les oui), pas un décideur. C'est précisément cette asymétrie qui rend l'arrêt non décidable.
Niveau (raisonnement intermédiaire)
Écrire (en idéalisant l'exécution d'un programme) un semi-décideur de l'arrêt, et expliquer sa limite.
Démonstration
(* execute_n_etapes p x k : exécute p sur x pendant au plus k étapes,
renvoie true si p s'est arrêté dans ce délai (fonction idéalisée). *)
let semi_arrete p x =
let k = ref 0 in
while not (execute_n_etapes p x !k) do k := !k + 1 done;
true
On simule p de plus en plus longtemps. Si p s'arrête (en k0 étapes), on le détecte dès k = k0 et l'on renvoie true. Mais si p boucle, la recherche sur k ne s'arrête jamais : aucune réponse non. Semi-décideur, pas décideur.
La fonction syracuse (chapitre 4) s'arrête-t-elle pour tout n ? En quoi diffère cette question de l'indécidabilité de l'arrêt ?
Démonstration
Pour Syracuse, on ignore si la boucle s'arrête pour tout n (conjecture ouverte), faute d'un variant connu — mais c'est une question sur un programme précis. L'indécidabilité de l'arrêt est plus forte : elle affirme qu'aucun algorithme ne peut répondre pour tous les programmes. On peut très bien prouver la terminaison de tel programme donné (par un variant) ; ce qu'on ne peut pas, c'est un procédé général valable pour tous.
On veut montrer que « le programme p s'arrête sur toutes les entrées » est indécidable. Esquisser la réduction depuis l'arrêt.
Démonstration
Supposons un décideur arrete_partout. Pour décider si un programme q s'arrête sur une entrée y, construisons le programme r qui, sur n'importe quelle entrée, exécute q sur y (en ignorant son argument). Alors r s'arrête sur toutes les entrées si et seulement si q s'arrête sur y. Si arrete_partout r existait, on déciderait l'arrêt de q sur y — impossible. Donc « s'arrêter partout » est indécidable.
Niveau (approfondissement)
Reconstituer en détail la contradiction de diagonale appliquée à elle-même.
Démonstration
let diagonale p =
if arrete p p then (while true do () done) else ()
Notons le programme diagonale. Que fait diagonale D ? Par définition, elle teste arrete D D.
- Cas
arrete D D = true: cela signifie « appliqué à s'arrête ». Or, dans ce cas,diagonale Dentre danswhile true: elle ne s'arrête pas. Contradiction avectrue. - Cas
arrete D D = false: « appliqué à ne s'arrête pas ». Ordiagonale Dprend alors la brancheelseet s'arrête. Contradiction avecfalse.
arrete ne peut donc renvoyer ni true ni false de façon cohérente : elle ne peut exister.
Montrer que « le programme p (sur l'entrée 0) finit par afficher 42 » est indécidable.
Démonstration
Réduction depuis l'arrêt. Pour décider si q s'arrête sur y, construisons p qui : exécute q sur y, puis (s'il revient) affiche 42. Alors p affiche 42 si et seulement si q s'arrête sur y. Un décideur de « affiche 42 » donnerait donc un décideur de l'arrêt : impossible. C'est une illustration du théorème de Rice — toute propriété non triviale du comportement est indécidable.
On admet que la fonction castor n = « le plus grand nombre d'étapes qu'un programme de taille n qui s'arrête peut effectuer » n'est calculable par aucun algorithme. Relier ce fait à l'indécidabilité de l'arrêt.
Démonstration
Si l'on savait calculer castor n, on déciderait l'arrêt : pour savoir si un programme p de taille n s'arrête, il suffirait de le simuler castor n étapes ; s'il ne s'est pas arrêté dans ce délai maximal, c'est qu'il ne s'arrêtera jamais. Or l'arrêt est indécidable ; donc castor n'est pas calculable. Cette fonction croît plus vite que toute fonction calculable : un exemple concret de l'au-delà du calculable.
Classer : (a) « p s'arrête sur x » ; (b) « p ne s'arrête pas sur x » ; (c) « la formule logique f est satisfiable » (chapitre 17).
Démonstration
(a) Semi-décidable non décidable : on simule, on confirme les oui (arrêt), jamais les non. (b) Non semi-décidable : c'est le complémentaire de (a) ; si (a) et (b) étaient toutes deux semi-décidables, l'arrêt serait décidable (lancer les deux semi-décideurs en parallèle) — impossible. (c) Décidable : il n'y a que valuations à essayer (chapitre 17), l'énumération s'arrête toujours (même si elle est exponentielle). Décidabilité et efficacité sont deux questions distinctes : un problème peut être décidable mais coûteux.
- Un problème de décision est décidable s'il existe un algorithme qui s'arrête toujours et répond juste ; semi-décidable si l'algorithme confirme les oui mais peut boucler sur les non.
- Le problème de l'arrêt (
ps'arrête-t-il surx?) est indécidable (Turing) : preuve par auto-référence (diagonaleappliquée à elle-même mène à une contradiction). Il est semi-décidable. - Théorème de Rice : toute propriété non triviale du comportement d'un programme est indécidable. D'où : pas de vérificateur universel de terminaison, de correction, de bug — la preuve se fait au cas par cas (variant, invariant).
- Réduction : pour montrer indécidable, réduire l'arrêt à (« décider permettrait de décider l'arrêt »).
- Décidable efficace : SAT (chapitre 17) est décidable mais (probablement) exponentiel. Calculabilité et complexité sont deux limites distinctes.
20.6 Exercices d'entraînement
Légende : application directe, raisonnement intermédiaire, approfondissement ; signale un classique incontournable. La numérotation prolonge celle des dix exercices résolus.
Thème A — Décidable ou non.
- [11.] Classer : «
nest un carré parfait », «pcontient une bouclewhile» (syntaxe), «pexécute une boucle infinie » (sémantique). - [12.] « Le graphe
gpossède un cycle » est-il décidable ? Donner le décideur (chapitre 15). - [13.] Pourquoi « ce nombre est premier » est-il décidable malgré l'infinité des diviseurs potentiels ?
Thème B — Semi-décidabilité.
- [14.] Donner un semi-décideur de « il existe
ntel quepaffichenfois ». - [15.] Montrer : si un problème et son complémentaire sont semi-décidables, alors il est décidable.
Thème C — Réductions.
- [16.] Montrer l'indécidabilité de «
petqcalculent la même fonction ». - [17.] Montrer l'indécidabilité de «
ps'arrête sur au moins une entrée ». - [18.] Expliquer pourquoi un compilateur ne peut pas signaler exactement les codes morts (jamais exécutés).
Thème D — Limites et culture.
- [19.] En quoi l'indécidabilité de l'arrêt justifie-t-elle la démarche « spécifier, prouver à la main » du cours ?
- [20.] Esquisser le lien entre l'argument diagonal de l'arrêt et celui de Cantor (les réels ne sont pas dénombrables).
- [21.] Le théorème de Rice rend-il toute analyse de programme vaine ? (Penser aux approximations sûres : analyses qui se trompent « du bon côté ».)
- [22.] Discuter : « décidable mais intraitable » contre « indécidable » — donner un exemple de chaque.