Machine déterministe et machine non déterministe
Une machine déterministe est le modèle formel d'une machine telle que nous les connaissons (nos ordinateurs sont des machines déterministes). Les deux modèles les plus utilisés en informatique théorique sont :
Les machines déterministes font toujours un seul calcul à la fois. Ce calcul est constitué d'étapes élémentaires; à chacune de ces étapes, pour un état donné de la mémoire de la machine, l'action élémentaire effectuée sera toujours la même. Pour la suite, on pourra imaginer sans perte de généralité qu'une machine de Turing déterministe correspond à l'ordinateur favori du lecteur, programmé dans un langage impératif quelconque.
Une machine de Turing non-déterministe est une variante purement théorique des machines de Turing: on ne peut pas construire de telle machine. À chaque étape de son calcul, cette machine peut effectuer un choix non-déterministe: elle a le choix entre plusieurs actions, et elle en effectue une. Si l'un des choix l'amène à accepter l'entrée, on considère qu'elle a fait ce choix-là. En quelque sorte, elle devine toujours juste. Une autre manière de voir leur fonctionnement est de considérer qu'à chaque choix non-déterministe, elles se dédoublent, les clones poursuivent le calcul en parallèle suivant les branches du choix. Si l'un des clones accepte l'entrée, on dit que la machine accepte l'entrée.
Il semblerait donc naturel de penser que les machines de Turing non-déterministes sont beaucoup plus puissantes que les machines de Turing déterministes, autrement dit qu'elles peuvent résoudre en un temps raisonnable des problèmes que les machines ordinaires ne savent pas résoudre à moins de prendre des années.
L'Ordinateur à ADN est un cas particulier de machines non-déterministes, puisqu'il est capable de traiter un calcul en temps constant quelle que soit la taille des données. Notons toutefois que la difficulté est ici transposée en termes de réalisabilité de la machine, qui nécessite des quantités exponentielles d'ADN en fonction de la taille des données.
Complexité en temps et en espace
On désigne par n la taille de la donnée. On peut prendre quelques exemples :
- La donnée d'un graphe à s sommets et n arêtes est de taille ∁s2 : il y a ∁s2 arêtes possibles dans un tel graphe, et pour chacune, on doit utiliser un bit pour dire si elle est effectivement présente dans le graphe. On peut par exemple choisir une représentation matricielle (il y aura ∁s2 cellules dans la matrice à stocker et chacune vaudra 0 ou 1).
- la taille d'un vecteur d'éléments à trier.
Pour les machines déterministes, on définit la classe TIME(t(n)) des problèmes qui peuvent être résolus en temps t(n). C'est-à-dire pour lesquels il existe au moins un algorithme sur machine déterministe résolvant le problème en temps t(n) (le temps étant le nombre de transitions sur machine de Turing ou le nombre d’opérations sur machine RAM).
- TIME(t(n)) = { L | L peut être décidé en temps t(n) par une machine déterministe }
Pour les machines non déterministes, on définit la classe NTIME(t(n)) des problèmes qui peuvent être résolus en temps t(n).
- NTIME(t(n)) = { L | L peut être décidé en temps t(n) par une machine non-déterministe }
La complexité en espace évalue l'espace mémoire utilisé en fonction de la taille des données ; elle est définie de manière analogue :
- SPACE(s(n)) = { L | L peut être décidé par une machine déterministe en utilisant au plus s(n) cellules de mémoire}
- NSPACE(s(n)) = { L | L peut être décidé par une machine non-déterministe en utilisant au plus s(n) cellules de mémoire}
Le problème du codage
Le codage influence la complexité des problèmes. Il est bon de se rappeler que les données sur lesquelles travaillent les algorithmes sont nécessairement stockées en mémoire (on parle ici de la mémoire de l'ordinateur, mais aussi de la bande de la machine de Turing par exemple).
Si le codage d'une donnée est exponentiel par rapport à la taille de la donnée initiale, l'ensemble des complexités des algorithmes sera sans doute caché par la complexité du codage : il faut par exemple s'interdire de coder le résultat dans l'entrée...
On ne s'intéressera ici qu'aux codages raisonnables.
Problème de décision
Chaque problème informatique peut se réduire à un problème de décision, c’est-à-dire un problème formulé comme une question dont la réponse est Oui ou Non, plutôt que par exemple la taille du plus court chemin est 42. Un problème qui n'est pas formulé de cette manière peut être très simplement transformé en un problème de décision équivalent. Le problème du voyageur de commerce, qui cherche, dans un graphe, à trouver la taille du cycle le plus court passant une fois par chaque sommet, peut s'énoncer en un problème de décision ainsi : Existe-t-il un cycle passant une et une seule fois par chaque sommet tel que la somme des coûts des arcs utilisés soit inférieure à B, avec B∈N . Ce problème est équivalent au problème du voyageur de commerce au sens où si l'on sait résoudre efficacement l'un, on sait aussi résoudre efficacement l'autre.