Théorème de Rice

Théorème fondamental de la calculabilité

En informatique théorique, plus précisément en théorie de la calculabilité, le théorème de Rice énonce que toute propriété sémantique non triviale d'un programme est indécidable[1],[2],[3]. Le théorème de Rice généralise l'indécidabilité du problème de l'arrêt. Le théorème est classique[4],[5],[6],[7],[8],[9] et fait l'objet d'exercices dans certains ouvrages de théorie de la calculabilité[10]. Il a une certaine portée philosophique vis-à-vis de la calculabilité et est dû au logicien Henry Gordon Rice.

Explication de l'énoncé modifier

 
L'animation montre une machine impossible : d'après le théorème de Rice, il n'existe pas de machine qui lit des codes sources de fonctions et qui prédit si la fonction ne retourne jamais un entier non nul.

Les propriétés sémantiques concernent le comportement d'un programme et s'opposent aux propriétés syntaxiques sur le code source du programme. Une propriété est non triviale si elle n'est ni vraie pour toute fonction calculable, ni fausse pour toute fonction calculable. La table suivante donne des exemples de propriétés non triviales syntaxiques et des propriétés non triviales sémantiques. Le théorème de Rice ne s'applique qu'aux propriétés sémantiques.

Propriétés syntaxiques (attention, le théorème de Rice ne s'applique pas) Propriétés sémantiques (et donc indécidables par le théorème de Rice)
  • « le programme ne rend jamais de valeurs nulles[3] »
  • « le programme ne termine jamais par une erreur d'exécution »
  • « le programme calcule le même résultat qu'un programme donné », autrement dit « le programme calcule une fonction calculable donnée ».
  • « le programme calcule un résultat correct par rapport à sa spécification » autrement dit « la fonction calculée par le programme est bien celle définie par la spécification ». C'est une variante du précédent.
  • « le programme contient un virus »
  • « le programme accède à un site Web »

Impact en vérification de programmes modifier

Pour vérifier qu'un programme est correct, on peut recourir au test, y compris à des batteries de tests avec couverture de code. Mais comme l'a souligné Edsger Dijkstra « Le test de programmes peut être une façon très efficace de montrer la présence de bugs, mais est désespérément inadéquat pour prouver leur absence »[11].

La formulation pragmatique du théorème de Rice est qu'aucune méthode automatique d'analyse statique de programmes ne permet de décider, à partir du code source d'un programme, si la fonction qui associe les entrées à la sortie de ce programme satisfait ou non une propriété intéressante (non triviale) donnée.

En pratique, on adopte des stratégies pour contourner les limitations du théorème de Rice[12],[13] :

  1. Vérification de programmes avec seulement un nombre fini d'états.
  2. Méthode de vérification partiellement automatisée.
  3. Méthodes à base d'approximations.
  4. Méthodes restreignant l'ensemble des programmes sur lesquels on veut démontrer la propriété.
  5. Restrictions raisonnables de l'ensemble des fonctions calculables[14].

Ces stratégies ont donné lieu à différentes approches pour vérifier des programmes : l'interprétation abstraite, la vérification de modèles (model checking[15]) et la preuve semi-automatisée de programmes par assistant de preuve. Aucune de ces méthodes n'a une portée universelle. Des recherches en cours visent à étendre les domaines d'application des vérificateurs, donc à diminuer les restrictions citées ci-dessus, mais le théorème de Rice dit que le vérificateur absolu n'existe pas ou comme disait Frederick Brooks « il n'y a pas de balle en argent »[16].

Un cas particulier introductif : la fonction réalisée par un programme modifier

Comme introduction au théorème de Rice, considérons le cas spécifique où la propriété du programme soumise à décision est le fait que le programme calcule une fonction donnée   ; on dit aussi que le programme « réalise » la fonction  . Par rapport à ce que nous avons dit dans l'introduction et le premier paragraphe, la propriété à décider sur la fonction associée au programme est l'égalité à  . Autrement dit, on veut savoir si la fonction calculée par le programme est la fonction   ou non. Nous allons considérer trois cas de généralité croissante.

La fonction est la fonction nulle part définie modifier

Si la fonction calculée par le programme est celle qui n'est pas définie, cela signifie que le programme ne se termine jamais, quelle que soit la valeur en entrée. Décider cette propriété n'est pas possible en application du théorème de l'indécidabilité de l'arrêt qui peut se formuler en disant qu'il n'y a pas d'algorithme pour décider si un programme réalise la fonction nulle part définie.

La fonction est la fonction carré modifier

Supposons que nous souhaitions décider si un programme réalise la fonction carré, autrement dit, réalise la fonction  . Il faut que nous puissions décider si le programme

programmeCarré_p (x) =
 (x);
x * x

  est un programme quelconque, calcule effectivement la fonction   pour une valeur  , sans être non défini sur  . Pour décider si le programme programmeCarré_p calcule la fonction carré, il faut décider si   se termine sur  . Il faut donc décider l'arrêt de   sur  . C'est ni plus ni moins le problème de l'arrêt, qui, comme l'on sait, est indécidable. Donc décider si un programme calcule le carré de la valeur qu'on lui donne en entrée est indécidable.

La fonction est une fonction quelconque modifier

On peut dans ce cas aussi ramener la décision de la fonction calculée par un programme pour une fonction   quelconque au problème de l'arrêt, il suffit de remplacer x * x par  (x), à savoir décider si le programme

truc_p (x) =
 (x);
 (x)

calcule la fonction  . On en conclut donc qu'étant donnée une fonction  , décider si un programme calcule la fonction   est indécidable.

Différentes présentations modifier

Dans cette section, nous exposons différentes versions du théorème de Rice dans la littérature.

Version avec des machines de Turing modifier

Dans les ouvrages de théorie de la calculabilité, le théorème de Rice est souvent énoncé avec l'appui des machines de Turing[6],[17]. Wolper, dans son livre Introduction à la Calculabilité[2], énonce que toute propriété non triviale sur les langages récursivement énumérables est indécidable. On rappelle qu'un langage est récursivement énumérable s'il est accepté par une machine de Turing. Wolper insiste bien qu'il s'agit d'une propriété sur les langages acceptés par les machines de Turing et non pas sur les machines de Turing, c'est-à-dire une propriété sémantique et non pas syntaxique.

Version avec des programmes modifier

Olivier Ridoux et Gilles Lesventes[18] proposent une propriété dite « extensionnelle » (i.e., sémantique) et non triviale sur des programmes.

Théorème de Rice pour les fonctions modifier

Le théorème de Rice peut être exprimé du point de vue des fonctions calculées par les programmes[4],[3],[19]. On suppose que l'on travaille avec un langage de programmation Turing-complet. Soit   la fonction calculée par le programme p.   est donc le résultat de l'évaluation du programme p sur l'entrée  . Si le programme p ne se termine pas sur l'entrée  ,   n'est pas défini. Comme il existe des programmes qui ne se terminent pas, la fonction   est partielle. Notons FC l'ensemble de toutes les fonctions calculables partielles de   dans  . Soit F   FC. Notons PF l'ensemble {p |   F}, c'est-à-dire l'ensemble des programmes p tels que la fonction   soit dans F. Le théorème de Rice dit que PF est récursif si et seulement si F=∅ ou F=FC.

Théorème de Rice pour les ensembles modifier

Le théorème de Rice pour les fonctions calculables peut également être exprimé[20] du point de vue des ensembles récursivement énumérables. Notons RE la classe de tous les sous-ensembles de   récursivement énumérables. Soit E   RE. Notons P l'ensemble des programmes p qui décident un ensemble A   E (i.e. y   A ssi l'exécution de p se termine sur l'entrée y). Le théorème de Rice dit que P est récursif si et seulement si E = ∅ ou E=RE.

Le théorème de Rice ci-dessus exprime l'indécidabilité de propriétés portant sur les ensembles récursivement énumérables. Il est cependant possible de caractériser parmi de telles propriétés celles qui sont semi-décidables. Une propriété Prop sur les ensembles récursivement énumérables est dite monotone si, pour tous ensembles récursivement énumérables A et B tels que A   B, on a Prop(A)   Prop(B). Par exemple, « A est un ensemble fini » n'est pas monotone, alors que « A contient l'élément x » l'est. Soit Prop une propriété sur les ensembles récursivement énumérables et EProp   RE la classe des ensembles récursivement énumérables qui satisfont Prop. Notons PA l'ensemble des programmes p qui décident un ensemble A   E (i.e. y   A ssi l'exécution de p se termine sur l'entrée y). Cette variante du théorème de Rice[19],[7],[20] dit que si PEProp est récursivement énumérable, alors Prop est monotone.

Démonstration du théorème de Rice modifier

Démonstration pour les ensembles modifier

Soit P une propriété non triviale sur les ensembles récursivement énumérables. Sans perte de généralité, supposons que P(∅) est fausse (si ce n'est pas le cas, on raisonne pareillement avec la négation de P). Montrons que le problème de l'arrêt se réduit à la décision de P. Nous définissons une réduction qui transforme toute instance (M, w) du problème de l'arrêt, où M est une machine de Turing et w est un mot, en une machine de Turing M', instance de la décision de P.

Il existe un ensemble récursivement énumérable A qui satisfait P, et une machine MA qui accepte A. Dès lors, on construit de manière effective la machine de Turing M' suivante à partir de (M, w) :

M'(u)
      Lancer M sur w
      Lancer MA sur u

La démonstration s'achève avec la correction de la réduction : M s'arrête sur w, si et seulement si P(L(M')). En effet :

  • Si M s'arrête sur w, le langage de M' est exactement le langage de MA, c'est-à-dire A et P(A).
  • Si M ne s'arrête pas sur w, le langage de M' est le langage vide et P(∅) est fausse.

Le théorème de Rice pour les fonctions peut se démontrer de façon similaire.

Démonstration pour les fonctions (par le théorème du point fixe de Kleene) modifier

Le théorème de Rice pour les fonctions peut se démontrer[5],[9] par le théorème du point fixe de Kleene. Le théorème du point fixe de Kleene dit que pour tout transformateur de programme T qui est une fonction totale, il existe un programme p tel que les programmes p et T(p) calculent la même fonction ( ).

Soit une propriété   non triviale (  et  FC). Supposons par l'absurde que P = {p |   F} est récursif.

Comme F est non triviale, il existe f   et g  . Les fonctions f et g étant calculables, il existe deux programmes p et q avec   = f et   = g. Définissons le transformateur de programmes T :

T(x) = q si x   P

T(x) = p si x   P

Comme P est récursif, T est une fonction totale calculable. Par le théorème du point fixe de Kleene, il existe un programme n tel que  . Procédons maintenant par étude de cas sur la valeur de T(n) :

  • Si T(n)=p, par définition de T, on a n   P. Comme  , T(n)   P. Or T(n)=p  P. Contradiction.
  • Si T(n)=q, alors n   P. Comme  , T(n)   P. Or T(n)=q   P. Contradiction.

Preuve par réduction du problème de l'arrêt modifier

Brouillon de preuve modifier

Avant d'établir une preuve formelle, tentons d'abord une approche par un cas pratique. Supposons que nous ayons un algorithme qui détermine de manière infaillible qu'un programme p est une implémentation correcte de la fonction de mise au carré. Celle-ci prend un entier d et retourne d2 . Il est à noter que la preuve fonctionne pour n'importe quel algorithme vérifiant une propriété non-triviale d'un programme.

L'intuition pour la preuve est de convertir notre algorithme vérifiant les programmes de mise au carré en un algorithme identifiant les fonctions qui s'arrêtent, faisant alors intervenir le problème de l'arrêt. Construisons pour ce faire un algorithme prenant comme entrées a et i et qui détermine si le programme a s'arrête pour un i donné.

Cet algorithme construit la description d'un nouveau programme t prenant un unique argument n, et  :

  1. Premièrement exécute le programme a avec comme entrée i. (Note: a et i sont tous deux décrits dans t)
  2. Secondement retourne le carré de n.

Si a(i) tourne à l'infini, alors t ne parvient jamais à l'étape (2) quelle que soit la valeur de n.

Ainsi t est une fonction calculant les carrés de nombres si et seulement si l'étape (1) se termine.

Comme notre supposition de départ était que nous pouvions fermement identifier les programmes calculant des carrés, nous pouvons déterminer si f, lequel dépend de a et i, est un tel programme, et ceci pour n'importe quels a et i. Par conséquent, nous avons obtenu un programme décidant si le programme a s'arrête pour une certaine entrée i.

Notez que notre algorithme de décision d'arrêt n'exécute jamais t, mais passe seulement sa description au programme d'identification des carrés, lequel par hypothèse se termine toujours. Dès lors, si la description de t est construite de façon qu'il se termine toujours, l'algorithme d'arrêt ne peut par conséquent pas échouer à s'arrêter.

 halts (a,i) {
   define t(n) {
     a(i)
     return n×n
   }
   return est_une_fonction_de_carre(t)
 }

Cette méthode de preuve ne se concentre pas sur des fonctions calculant des carrés. Tant que certains programmes peuvent faire ce que nous essayons de reconnaître, c.à.d. déterminer une propriété d'un programme, nous pouvons faire un appel à a pour obtenir notre t. Nous pourrions avoir une méthode vérifiant des programmes calculant des racines carrées, ou des programmes calculant la paye mensuelle, ou des programmes qui s'arrêtent avec une entrée donnée "Abraxas". Pour chaque cas, nous sommes capables de résoudre le problème de l'arrêt de manière similaire.

Preuve formelle modifier

 
Si nous avons un algorithme qui décide une propriété non-triviale, nous pouvons construire une machine de Turing qui décide du problème de l'arrêt.

Pour la preuve formelle, on suppose que les algorithmes définissent les fonctions partielles comme des chaînes de caractères et sont eux-mêmes représentés par des chaînes. La fonction partielle calculée par l'algorithme représenté par une chaîne de caractères a est notée Fa. Cette preuve procède par un raisonnement par l'absurde : nous supposerons d'abord qu'il y ait une propriété non-triviale qui est décidée par un algorithme ; nous démontrerons ensuite que par cette supposition nous pouvons montrer que le problème de l'arrêt est calculable, ce qui est impossible et par conséquent, une contradiction.

Supposons maintenant que P(a) est un algorithme décidant d'une propriété non-triviale de Fa. Supposons ensuite que P(ne-sarrete_pas) = "non", avec ne-sarrete_pas la représentation d'un algorithme qui ne s'arrête jamais. Si ce n'est pas vrai, alors cela vaut pour la négation de la propriété. Comme P décide une propriété non-triviale, cela implique qu'il existe une chaîne de caractères b représentant un algorithme et P(b) = "oui". Nous pouvons alors définir un algorithme H(a, i) comme suit :

  1. Construire une chaîne de caractères t représentant un algorithme T(j) tel que :
    1. T simule en premier le calcul de Fa(i).
    2. T simule le calcul de Fb(j) et retourne son résultat.
  2. Retourne P(t).

Nous pouvons maintenant montrer que H décide du problème de l'arrêt :

  • Si l'algorithme représenté par a s'arrête pour une donnée i, alors, Ft = Fb. Parce que P(b) = "oui" et le résultat de P(x) dépend seulement de Fx, cela implique que P(t) = "oui" et donc que H(a, i) = "oui".
  • Si l'algorithme représenté par a ne s'arrête pas pour une donnée i, alors, Ft = Fne-sarrete-pas, la fonction partielle qui n'est jamais définie. Comme P(ne-sarrete-pas) = "non" et le résultat de P(x) dépend seulement de Fx, cela implique que P(t) = "non" et donc, H(a, i) = "non".

Comme le problème de l'arrêt n'est pas calculable, il y a une contradiction et par conséquent, l'hypothèse qu'il existe un algorithme P(a) qui décide une propriété non-triviale pour la fonction représentée doit être fausse. CQFD.

Démonstration pour les ensembles (variante du théorème) modifier

De manière analogue à la démonstration du théorème de Rice pour les ensembles, on montre[19],[7] que la semi décision de la négation du problème de l'arrêt peut se réduire à la semi-décision de toute propriété non-monotone sur les ensembles récursivement énumérables.

Soit P une propriété non-monotone et semi-décidable. Il existe donc deux ensembles récursivement énumérables A et B, calculés respectivement par des machines de Turing MA et MB tels que :

  • A est inclus dans B
  • A satisfait P
  • B ne satisfait pas P.

De plus, il existe une machine de Turing MP qui, pour toute représentation d'une machine de Turing, s'arrête et accepte si l'ensemble récursivement énumérable accepté par cette machine satisfait P.

Dès lors, on peut construire une machine de Turing H prenant en entrée la représentation d'une machine de Turing M suivie d'une entrée x dont l'algorithme est le suivant :

1 Construire la représentation d'une machine de Turing T qui, sur une entrée y :
1 Exécute en parallèle
  • MA sur y
  • MB sur y
  • M sur x
2 Accepte y si
  • MA accepte y ou bien
  • MB accepte y ET M s'arrête sur x
2 Exécuter MP sur la représentation de T et renvoyer le résultat.

Par « exécuter en parallèle », on entend que la machine T exécute un pas MA sur y, puis un pas de MB sur y, puis un pas de M sur x, puis un second pas de MA sur y, et ainsi de suite. Autrement dit, on «entrelace» les pas de calcul d'une machine avec ceux de l'autre machine.

Si M s'arrête sur x, T accepte y si, et seulement si MA ou MB accepte y, et comme A est inclus dans B, cela revient à dire si et seulement si y appartient à B. Donc, T accepte exactement l'ensemble B, qui, par hypothèse, ne vérifie pas P. Par conséquent, MP n'accepte pas T. (P étant supposé semi-décidable, MP peut même ne pas s'arrêter du tout) Si M ne s'arrête pas sur x, T accepte y si et seulement si y appartient à A. T accepte donc exactement l'ensemble A qui, par hypothèse, satisfait P. Par conséquent, MP accepte T (et finit donc par s'arrêter, par définition de la semi-décidabilité). La machine H calcule donc la négation du problème de l'arrêt. Celui-ci n'étant pas semi-décidable, par contradiction, P ne peut donc pas être semi-décidable.

Notes et références modifier

Notes modifier

  1. Ce théorème est la reformulation « intuitive » du corollaire B de la publication originale de Henry Gordon Rice (1953).
  2. a et b Pierre Wolper, Introduction à la calculabilité, Dunod, , p. 150, Théorème 7.3
  3. a b et c Olivier Ridoux et Gilles Lesventes, Calculateurs, Calculs et Calculabilité, p. 53
  4. a et b (en) Rogers, Hartley, Jr., 1926-2015., Theory of recursive functions and effective computability, Cambridge (Mass.)/London, MIT Press, , 482 p. (ISBN 0-262-68052-1, OCLC 15108070, lire en ligne), p. 34
  5. a et b Mandrioli, Dino., Theoretical foundations of computer science, Wiley, (ISBN 0-471-83834-9, OCLC 15162953, lire en ligne), p.174-175
  6. a et b Hopcroft, John E., 1939- et Ullman, Jeffrey D., 1942-, Introduction to automata theory, languages, and computation, Pearson/Addison Wesley, , 535 p. (ISBN 978-0-321-46225-1 et 0-321-46225-4, OCLC 69013079, lire en ligne), p.307
  7. a b et c Machtey, Michael., An introduction to the general theory of algorithms, North-Holland, (ISBN 0-444-00226-X, OCLC 3168554, lire en ligne), p.102 et 106
  8. Pippenger, Nicholas., Theories of computability, Cambridge University Press, (ISBN 0-521-55380-6, OCLC 35593710, lire en ligne), p. 148
  9. a et b Davis, Martin, 1928- et Weyuker, Elaine J., Computability, Complexity, and Languages : Fundamentals of Theoretical Computer Science, Academic Press, Harcourt, Brace, , 609 p. (ISBN 978-0-12-206382-4, OCLC 28506245, lire en ligne), p. 102-103
  10. (en) Sipser, Introduction to the Theory of Computation, p. 210 Ex. 5.22
  11. (en) Edsger Dijkstra, « The Humble Programmer », Communications of the ACM, vol. 15, no 10,‎ , p. 859-866
  12. (en) Traub, Formal Verification of Concurrent Embedded Software, p. 16
  13. (en) « Cours sur les méthodes formelles par John Rushby », sur p. 129
  14. Par exemple les fonctions normalisantes en calcul des constructions inductif, ne sont pas toutes fonctions calculables, mais couvrent toutes les fonctions utiles en mathématiques.
  15. « Cours sur le model checking par Gerard Berry au Collège de France »
  16. (en) « No Silver Bullet », IEEE Computer Magazine,‎
  17. (en) Papadimitriou, Christos H., Computational complexity, Reading (Mass), Addison-Wesley, , 523 p. (ISBN 0-201-53082-1, OCLC 28421912, lire en ligne), p. 62
  18. Olivier Ridoux et Gilles Lesventes, Calculateurs, Calculs et Calculabilité, Dunod, coll. « Sciences Sup », , 204 p., p. 54
  19. a b et c Bridges, D. S. (Douglas S.), 1945-, Computability : a mathematical sketchbook, Springer-Verlag, (ISBN 0-387-94174-6, OCLC 28891770, lire en ligne), p. 78 et 85
  20. a et b Kozen, Dexter, 1951-, Automata and computability, , 400 p. (ISBN 978-3-642-85706-5, OCLC 883383306, lire en ligne), Lecture 34

Références modifier

  • Olivier Ridoux et Gilles Lesventes, Calculateurs, calculs, calculabilité, Dunod, coll. « Sciences sup », , 204 p. (ISBN 978-2-10-051588-2), Chapitre 4
  • (en) D. Mandrioli, C. Ghezzi, Theoretical Foundations of Computer Science, John Wiley & Sons, 1987; (ISBN 0-471-83834-9), pages 174-175
  • (en) D.S. Bridges, Computability, A Mathematical Sketchbook, Springer, (ISBN 0387941746), 1994, pages 78 et 85.
  • (en) M. Machtey, P. Young Introduction to the General Theory of Algorithms, North Holland, 1978, pages 102 et 106
  • (en) Martin Davis, Ron Sigal Elaine Weyuker, Computability, Complexity, and Languages (2nd ed), Morgan Kaufmann, (ISBN 9780122063824), 1994, p. 609, page 103
  • (en) Nicholas Pippenger, Theories of computability, Cambridge University Press, (ISBN 0-521-55380-6), 1997, page 148
  • (en) John E. Hopcroft, Rajeev Motwani, Jeffrey D. Ullman , Introduction to Automata Theory, Languages, and Computation (3rd Edition), Addison-Wesley, (ISBN 0321462254), 2006, page 307