Adloun

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

Définition 20.1Problème de décision, décidabilité

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.

Exemple 20.2Des problèmes décidables

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

Exemple 20.3Un problème semi-décidable

« 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

Définition 20.4Problè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 ?

◆Théorème 20.5Indécidabilité de l'arrêt (Turing, 1936)

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 diagonale s'arrête, alors arrete diagonale diagonale vaut true, donc diagonale boucle — contradiction ;
  • si elle ne s'arrête pas, alors arrete vaut false, donc diagonale s'arrête — contradiction.

Dans les deux cas, contradiction. L'hypothèse est fausse : arrete ne peut pas exister.

iRemarque

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

ImportantOn ne peut pas tout automatiser

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)

Exercice 1 : Décidable ou non ?

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.

Exercice 2 : Un décideur

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

Exercice 3 : Le piège du « il suffit d'exécuter »

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)

Exercice 4 : Semi-décider l'arrêt

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

Exercice 5 : Syracuse, problème ouvert mais pas indécidable

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.

Exercice 6 : Comprendre une réduction

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)

Exercice 7 : La diagonale

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 D entre dans while true : elle ne s'arrête pas. Contradiction avec true.
  • Cas arrete D D = false : « appliqué à ne s'arrête pas ». Or diagonale D prend alors la branche else et s'arrête. Contradiction avec false.

arrete ne peut donc renvoyer ni true ni false de façon cohérente : elle ne peut exister.

Exercice 8 : Une propriété sémantique indécidable

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.

Exercice 9 : Le castor affairé (busy beaver)

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.

Exercice 10 : Décidable, semi-décidable, ou ni l'un ni l'autre ?

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.

Synthèse du chapitre (à retenir)
  • 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 (p s'arrête-t-il sur x ?) est indécidable (Turing) : preuve par auto-référence (diagonale appliqué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.
Thème B — Semi-décidabilité.
Thème C — Réductions.
Thème D — Limites et culture.

Continuer sur Adloun : animation, QCM, fiches, exercices