Calculabilité, décidabilité
===========================
... ou l'étude des possibilités et limites des algorithmes
<br><br>
*Ce document a été créé en collaboration avec Bing Copilot (relié à GPT4) pour transposer le cours correspondant (accessible [ici](recherche-textuelle)) en un diaporama.*
*Pour voir la conversation avec Copilot : [cliquer ici](https://copilot.microsoft.com/sl/cRLnEzsqfVk)*
---
# Introduction
---
## Le problème de décision de Hilbert
- Question posée par David Hilbert en 1928 : « *Existe-t-il un algorithme capable de déterminer, pour tout énoncé mathématiques bien formulé, si ce dernier est vrai ou faux ?* »
<img class="r-stretch centre image-responsive" alt="Alonzo Church" src="data/David_Hilbert.jpg">
- C'est l'origine de la **théorie de la calculabilité**.
----
## Le problème de décision de Hilbert
- Réponse négative apportée indépendamment par Alonzo Church et Alan Turing en 1936.
- Excellente vidéo retraçant cette histoire :
<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/Zci9m08HQws" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
<small>Crédits : Voyages au pays des maths, ARTE</small>
---
## Programme en tant que donnée
- Idée clé de la théorie de la calculabilité : **un programme est une donnée comme une autre**
- Concrètement : un programme peut être lu, écrit et exécuté par d'autres programmes.
- Exemples :
- Commande `python` : est un programme (ici c'est l'**interpréteur** Python) qui exécute d'autres programmes
```bash
python prog.py
```
- **Compilateur** : un programme qui convertit un autre programme en langage machine.
----
## Programme en tant que donnée
- Autres exemples :
- pour **télécharger un programme** (logiciel) on utilise des programmes (navigateur, gestionnaire de téléchargement)
- **système d'exploitation** : programme qui gère tous les autres
- **antivirus** : programme scanne d'autres programmes
- **virus informatique** : programme qui prend en entrée un programme et en produit d'autres (infectés)
----
### Même en Python...
- Une fonction peut prendre d'autres fonctions en paramètres.
- Exemple : la fonction `sorted` avec le paramètre `key` qui est une fonction.
```python
>>> animaux = ['vache', 'anaconda', 'chat', 'chien',
'ver', 'poule', 'souris']
>>> sorted(animaux, key=len) # fonction len passée en paramètre
['ver', 'chat', 'vache', 'chien', 'poule', 'souris', 'anaconda']
```
- `doctest.testmod()` : fonction qui prend en entrées des fonctions, les exécute et vérifie leur comportement
---
# Calculabilité
---
## Quelques définitions
- Un *algorithme* est une méthode de calcul qui peut être vue comme une *fonction mathématique* (paramètres en entrée et calcule un résultat)
- La **théorie de la calculabilité** étudie les fonctions qui peuvent être calculées par un algorithme.
- Une fonction est dite **calculable** si elle peut être calculée par un algorithme en un nombre fini d'étapes.
----
## Quelques définitions
- Il existe des fonctions calculables (ex : le pgcd de deux nombres) mais d'autres ne le sont pas (nous en verrons)
- La théorie de la calculabilité permet de **comprendre les limites des problèmes que peuvent résoudre les ordinateurs**.
- Théorie (à la frontière entre mathématiques et informatique) développée dans les années 1930 par **Alan Turing** et **Alonzo Church** qui essayaient de répondre au problème de décision de Hilbert
---
## La vision de Church
<img class="r-stretch centre image-responsive" alt="Alonzo Church" src="data/Alonzo_Church.jpg">
- **Alonzo Church** (américain) a proposé une définition (mathématique) des fonctions calculables.
- Il a introduit le **$\lambda$-calcul**, un langage pour décrire les fonctions calculables : c'est l'ancêtre des langages de programmation
- Dans ce langage : une fonction est **calculable** si elle peut s'exprimer comme une $\lambda$-expression.
----
## La vision de Church
- Le $\lambda$-calcul considère qu'**une fonction est une donnée comme une autre**, qui peut être passée en paramètre à une fonction et aussi le résultat d'une fonction.
- Les $\lambda$-expressions ont une structure définie *récursivement* : la théorie de Church est à la base des langages de *programmation fonctionnelle*.
----
## La vision de Church (exemples)
- Exemples de $\lambda$-expressions (ni à connaître, ni même à comprendre) :
- L'entier 0 est $\lambda f.\lambda x. x$
- L'entier 1 est $\lambda f.\lambda x.f(x)$
- La fonction $f:x \longmapsto x+1$ est calculable car elle peut s'exprimer ainsi : $\lambda x.\lambda f.\lambda z.x(f)(f(z))$
- En Python :
```python
zero = lambda f: lambda x: x
un = lambda f: lambda x: f(x)
ajouter_un = lambda x: lambda f: lambda z: x(f)(f(z))
```
```python
# Utilisation de la fonction pour ajouter 1 au nombre un
deux = ajouter_un(un)
```
----
## La vision de Church (exemples)
- Comment vérifier que `deux` correspond bien à l'entier 2 ? ... pas évident car `deux` est alors une fonction et non un nombre entier
- `deux` est une fonction qui applique une autre fonction `f` à un argument `x` (en écrivant `deux(f)(x)`)
- Elle doit normalement appliquer *deux* fois (c'est ce qu'on veut vérifier !) la fonction `f` en partant de l'argument `x`
- Vérification avec `f` qui est la fonction `triple` :
```python
>>> triple = lambda x: x * 3
>>> deux(triple)(1) # calcule bien 1 * 3 * 3
9
>>> deux(triple)(2) # calcule bien 2 * 3 * 3
18
>>> deux(triple)(5) # calcule bien 5 * 3 * 3
45
```
---
## La vision de Turing
<img class="r-strecth centre image-responsive" alt="Portrait d'Alan Turing" src="data/Alan_Turing.jpg">
- **Alan Turing** (britannique) propose une définition mécanique approche mécanique du calcul et donc des fonction calculables
- Il a définit les **machines de Turing** (concept *abstrait* malgré son nom) pour décrire les fonctions calculables
- Pour Turing : une fonction est **calculable** si elle peut être calculée par une machine de Turing.
----
## La vision de Turing
- Qu'est-ce qu'une **machine de Turing** ?
- une tête de lecture/écriture
- un ruban infini
- un ensemble de règles pour indiquer ce que doit faire la machine dans chaque situation
<img class="r-stretch centre image-responsive" alt="Vue d'artiste d'une machine de Turing" src="data/machine_turing.png">
----
## La vision de Turing (exemple)
- Exemple : la fonction $f:x\mapsto x+1$ est calculable car elle peut être calculée par la machine de Turing suivante
<iframe class="centre" loading="lazy" src="https://animations.interstices.info/machine-turing/index.html" width="745" height="350" frameborder="0" scrolling="no"></iframe>
<p class="legende"><small>Animation HTML5/JS réalisée par Hugo Lehmann, <a href="https://centralelilleprojets.fr/" target="_blank">Centrale Lille Projets</a>, librement adaptée d’une <a title="Machine de Turing" href="https://interstices.info/machine-de-turing/" target="_blank" rel="noopener">applet Java</a> écrite par Hamdi Ben Abdallah.</small></p>
----
## La vision de Turing
- Chaque machine est monotâche ?
- Non ! Turing a montré qu'il existe des **machines de Turing universelles** : elles peuvent simuler l'exécution de n'importe quelle autre machine de Turing $M$ sur une entrée $e$.
- On retrouve ici qu'**un programme** (une machine) **est une donnée comme une autre** : peut être donné en entrée à un autre programme (une autre machine).
- Machine de Turing universelle : ancêtre des ordinateurs programmables.
---
## Universalité de la calculabilité
- Les théories développées par Church et Turing sont équivalentes !
- **Thèse de Church-Turing** : fonctions $\lambda$-calculables = fonctions calculables par machines de Turing.
- Traduction : *tout problème qui peut être résolu, peut l’être par une machine de Turing ou par une fonction de Church*
- Affirmation jamais encore contredite
- Traduction contemporaine : tout ce que le plus puissant des ordinateurs peut faire, une (simple) machine de Turing peut le faire aussi.
----
## Universalité de la calculabilité
- Tous les langages de programmation ordinaires sont construits pour permettre de calculer exactement les mêmes choses qu'une machine de Turing (ou que les fonctions de Church) : on dit qu'ils sont *Turing-complets*.
- Conséquence : **la calculabilité ne dépend pas du langage de programmation**
- Si un problème peut être résolu dans un certain langage de programmation, il peut l'être dans tous les autres
- Si un problème ne peut pas être calculé par une machine de Turing ou une fonction de Church, il ne peut être résolu par aucun programme (donc par aucun ordinateur)
---
# Décidabilité
---
## Définitions
- **Problème de décision** : problème dont la réponse est oui ou non
- Exemples : 3 est-il premier ? ce programme contient un virus ? ce programme renvoie la valeur 42 ? le problème de décision de Hilbert ! ...
- Un problème de décision est :
- **décidable** si la solution est calculable (= il existe un algorithme qui calcule la solution)
- **indécidable** sinon (= aucun algorithme ne peut donner la solution)
- Turing et Church ont chacun explicité un problème de décision **indécidable**
---
## Le problème de l'arrêt (Turing)
- Question : « *Existe-t-il un algorithme (ou un programme) universel capable de déterminer, à partir d'un programme et d'une entrée, si ce programme s'arrête avec cette entrée ou non ?* »
- Réponse de Turing : **Non** ! Il a démontré qu'il n'existait pas de machine de Turing qui résout le problème de l'arrêt.
- Donc : **le problème de l'arrêt est indécidable**.
----
### Une démonstration avec Python
- On *raisonne par l'absurde* : on suppose le contraire de ce qu'on veut montrer et cela va nous amener à une contradiction
- Supposons qu'il existe une fonction `arret` qui résout le problème de l'arrêt.
```python
def arret(prog, x):
"""Fonction qui renvoie Vrai si prog(x) termine,
False sinon."""
... # inutile d'écrire quoi que ce soit
```
- Définissons une fonction `paradoxe` qui utilise `arret`.
```python
def paradoxe(prog):
if arret(prog, prog): # si prog(prog) termine
while True:
pass
else:
return False
```
----
### Une démonstration avec Python
```python []
def paradoxe(prog):
if arret(prog, prog): # si prog(prog) termine
while True:
pass
else:
return False
```
**Quel est le résultat de l'appel `paradoxe(paradoxe)` ?**
- 1er cas : `paradoxe(paradoxe)` rentre dans une boucle infinie si `arret(paradoxe, paradoxe)` est vrai donc si `paradoxe(paradoxe)` termine : *contradiction !*
- 2ème cas : `paradoxe(paradoxe)` termine (en renvoyant `False`) si `arret(paradoxe, paradoxe)` est faux donc si `paradoxe(paradoxe)` ne termine pas : *contradiction !*
----
### Une démonstration avec Python
- Dans les deux cas, nous obtenons une contradiction.
- Cela signifie que notre supposition de départ est fausse : une fonction `arret` ne peut pas exister !
- Le problème de l'arrêt est indécidable !
> Remarquez à nouveau que la démonstration proposée utilise un programme comme une donnée qui peut être passée à un autre programme.
---
## Le problème de l'égalité de deux fonctions (Church)
- Question : « *Existe-t-il un algorithme (ou un programme) universel capable de déterminer si deux programmes font exactement la même chose sur les mêmes entrées.* »
- Réponse de Church : Non, **le problème de l'égalité de fonctions est indécidable**.
- La démonstration, qui s'appuie sur le $\lambda$-calcul, est hors de portée
---
## Et le problème de Hilbert ?
- Turing et Church ont montré respectivement que, comme les problèmes de l'arrêt et de l'égalité de fonctions sont indécidables alors le **problème de décision de Hilbert est aussi indécidable**.
- Il ne peut pas exister d'algorithme universel capable de décider si un énoncé mathématique est vrai ou faux.
- (Turing a raisonné par l'absurde : il a montré que si l'*Entscheidungsproblem* était calculable par une machine de Turing, alors le problème de l'arrêt le serait également. Mais comme ce n'est pas le cas, il y a une contradiction. Donc l'*Entscheidungsproblem* est indécidable.)
---
## Indécidabilité : compléments
- Indécidabilité concerne des fonctions qui doivent répondre pour *toutes* les entrées possibles.
- Un problème général indécidable ne signifie pas qu'on ne peut pas y répondre dans des cas particuliers
- Exemples :
- on peut prouver que certain énoncés mathématiques sont vrais
- on peut prouver que la fonction suivante s'arrête sur toute entrée entière `n` positive (en utilisant un *variant de boucle*):
```python
def marrete_je(n):
while n >= 0:
print("Bonjour")
n = n - 1
```
----
## Indécidabilité : compléments
- **Gordon Rice** généralise le problème de l'arrêt
- Théorème de Rice (1951) : *toute propriété non triviale sur le comportement d'un programme est indécidable*.
- Exemples : il n'existe pas d'algorithme général qui répond à coup sûr aux questions suivantes :
- « le programme ne renvoie jamais la valeur 42 »
- « le programme ne termine jamais par une erreur d'exécution »
- « le programme calcule un résultat correct par rapport à sa spécification »
- « le programme contient un virus »
----
## Indécidabilité : compléments
- Conséquences :
- on ne peut pas savoir ce que fait un programme sans le faire tourner
- la preuve automatique de programmes est difficile
- il n'existe pas d'antivirus totalement efficace : ces derniers analysent le code source pour détecter une signature malveillante mais ne se posent pas la question : « ce que fait ce code est il dangereux ? » (ce serait inutile d'après le théorème de Rice)
---
# Bilan
---
## Bilan
- Théorie de la calculabilité :
- Quelles fonctions peuvent être calculées par un algorithme ?
- Ces fonctions sont dites **calculables**
- Permet de savoir :
- quels problèmes peuvent ou ne pas être résolus
- quelles sont les limites des ordinateurs
- Church et Turing ont développé de manière différente leur théorie de la calculabilité pour définir la notion de fonction calculable :
- approche *mathématique* pour Church : langage appelé $\lambda$-calcul
- approche *informatique* pour Turing : machine de Turing
----
## Bilan
- Les deux théories sont équivalentes (c'est la *thèse de Church-Turing*) : fonctions de Church = fonctions calculables par machines de Turing
- Elles ont une portée universelle : tout problème qui peut être résolu peut l’être par une machine de Turing, ou par une fonction de Church
- Tous les langages de programmation ordinaires (peu importe le paradigme) sont construits pour permettre de calculer exactement les mêmes choses qu'une machine de Turing (ou que les fonctions de Church)
----
## Bilan
- Conséquence : **la calculabilité ne dépend pas du langage de programmation**
- tout problème qui peut être résolu par un programme dans un langage de programmation peut l’être dans tous les autres (et aussi par une machine de Turing)
- tout ce que le plus puissant des ordinateurs peut faire, une (simple) machine de Turing peut le faire aussi.
- un problème qui ne peut pas être résolu par une machine de Turing ne peut l'être par aucun ordinateur
----
## Bilan
- **Problème de décision** : problème dont la réponse est oui ou non
- Un tel problème est **décidable** si la solution est calculable par un algorithme pour chaque entrée, **indécidable** sinon
- Le **problème de l'arrêt** (démontré par Turing) est un exemple de problème indécidable : il ne peut exister d'algorithme général qui prendrait en entrée un programme $P$ (et une entrée $e$ de ce programme) et qui puisse déterminer si ce programme $P$ va s'arrêter (sur l'entrée $e$)
- La **décidabilité** est également **indépendante du langage de programmation utilisé**.
---
### Références
- Document ressource de l'équipe éducative du DIU EIL de l'Université de Nantes, diffusé sous licence CC BY : [Les barrières de l'informatique](data/diu2019_bloc5_séance5.pdf) (Bloc 5, Séance 5)
- Livre *Spécialité Numérique et sciences informatiques : 24 leçons avec exercices corrigés - Terminale*, éditions Ellipses, T. Balabonski, S. Conchon, J.-C. Filliâtre, K. Nguyen. Site du livre : [http://www.nsi-terminale.fr/]
- Livre *Prépabac, NSI, Terminale*, éditions Hatier, G. Connan, V. Petrov, G. Rozsavolgyi, L. Signac.
- Articles Wikipédia : [Théorie de la calculabilité](https://fr.wikipedia.org/wiki/Th%C3%A9orie_de_la_calculabilit%C3%A9), [Théorème de Rice](https://fr.wikipedia.org/wiki/Th%C3%A9or%C3%A8me_de_Rice)
- Article Interstices : [Comment fonctionne une machine de Turing ?](https://interstices.info/comment-fonctionne-une-machine-de-turing/)
---
Germain BECKER, Lycée Mounier, ANGERS
Ressource éducative libre distribuée sous [Licence Creative Commons Attribution - Partage dans les Mêmes Conditions 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/)
