8.6 Unentscheidbarkeit
Im vorherigen Teilkapitel haben wir die universelle Turingmaschine konstruiert, die
eine andere Turingmaschine, deren Codierung und Inputwort sie als Input gegeben hat, simulieren
kann.
Technisch gesprochen: akzeptiert die Sprache
Allerdings: wenn auf nicht terminiert, dann terminiert auf auch
nicht. akzeptiert die Sprache also, entscheidet sie aber nicht. Wäre es
nicht schön, eine Turingmaschine zu haben, die diese Sprache entscheidet? Dann könnten wir jede
Turingmaschine simulieren und gleichzeitig Endlosschleifen und eventuell ganz allgemein
"Programmierfehler" vorhersagen und abfangen. Wir werden zeigen, dass dies leider nicht
möglich ist. In der Literatur ist dies als die Unentscheidbarkeit des Halteproblems
(englisch undecidability of the Halting problem bekannt).
Als vorbereitenden Schritt schauen wir uns kurz die Codierungsfunktion nochmal genauer an. Wir
bezeichnen
mit die Menge aller Turingmaschinen mit Inputalphabet . Wir hatten
die Codierungsfunktion definiert, für das
Codierungsalphabet . In diesem Teilkapitel wird es nötig sein, die
Turingmaschine
über dem Alphabet selbst zu codieren. Dies ist nicht besonders schwierig, solange
mindestens zwei Zeichen hat. Wenn z.B. die Zeichen und enthält,
dann können wir alle Zeichen in
wiederum als Strings in codieren. Wir müssen hier
nur vorsichtig sein, dass der Code präfixfrei ist. Wenn wir zum Beispiel naiv
als und als und als codieren, dann wissen wir nicht mehr, was
mit dem Codewort gemeint ist. Am einfachsten geht das mit einem Blockcode, in dem
alle Codewörter die gleiche Länge haben, also
. Mit
ist das kein Problem. Unsere "neue" Codierungsfunktion
ist nun also . Wir definieren nun
die Haltesprache :
Wir können die universelle Turingmaschine leicht abwandeln, dass sie akzeptiert;
wir müssen nur einen Decodierungsschritt vorausschicken, der die neue Codierung
in unsere "alte" in übersetzt. Beachten Sie, dass das Zeichen , das wir
auch blockcodiert haben, uns hilft, die Grenze zwischen und zu erkennen.
Wir zeigen nun, dass unentscheidbar ist, dass es also keine Möglichkeit gibt,
das Nichtterminieren einer Maschine auf Eingabe vorauszusehen und abzufangen.
Theorem 8.6.1
(Unentscheidbarkeit des Halteproblems).
Die Sprache ist unentscheidbar.
Ich gebe erst einmal einen kurzen und knappen Widerspruchsbeweis. Falls das ihnen zu schnell
ging,
lesen Sie den zweiten Beweis, in dem ich mir mehr Zeit nehme.
Kurzer Beweis per Wiederspruch. Nehmen wir an, es gäbe eine Maschine ,
die entscheidet. Dann wäre auch die Sprache
entscheidbar. Warum? Wir können einfach schauen, ob das Eingabewort die Form
hat
und in diesem Fall das Wort der Maschine übergeben.
Die Sprache ist, salopp ausgedrückt, die Menge aller Turingmaschinen, die ihre
eigene
Codierung als Inputwort akzeptieren. Ebenso wäre auch
entscheidbar; wir müssen ja nur entscheiden und dann das Ergebnis negieren.
ist sozusagen die Menge aller Turingmaschinen, die nicht ihre eigene Codierung als
Inputwort akzeptieren. Da nach Annahme entscheidbar ist, gibt es eine Maschine
, die entscheidet.
Wir fragen uns jetzt: gehört selbst zu ?
Also , ein Widerspruch.
Unsere
Annahme, dass entscheidbar sei, ist also falsch.
Ausführlicher Beweis. Ich finde Beweise durch Widerspruch immer
etwas unintuitiv, weil man die ganze Zeit im Konjunktiv argumentieren muss.
Daher hier ein Beweis ohne Widerspruch. Wir zeigen, dass unentscheidbar ist,
indem wir für eine beliebige Turingmaschine zeigen, dass sie nicht entscheidet,
indem wir nämlich ein Eingabewort konstruieren, auf dem scheitert, also
entweder
- aber , oder
- aber , oder
- , d.h. terminiert auf Eingabewort nicht.
Wir setzen nun und , wobei eine neue
Turingmaschine ist, die wir auf Basis von
konstruieren werden.
Also noch einmal. Für eine beliebige, uns gegebene
Turingmaschine , werden wir eine neue Turingmaschine
bauen und sie codieren als , so dass
entweder
- aber , oder
- aber , oder
- .
Wenn uns dies gelingt, so haben wir gezeigt, dass nicht
die Sprache entscheidet: im Fall 3 terminiert
ja nicht einmal; in Fall 1 und 2 liefert zwar
eine Antwort, aber die falsche.
Der Code für ist sehr einfach:
def D(x):
if H(xx) == accept then
reject
else
accept
Zur Erinnerung: . Wir unterscheiden drei Fälle.
- . Dann geht der Aufruf von
also in den else-Teil
in den Zeilen 4-5 und
, somit
Wir befinden uns
in Fall 1: aber .
Die Maschine hat eine falsche Antwort
für geliefert.
-
. Dann geht
der Aufruf von in Zeile 3,
und , somit .
Wir befinden uns in Fall 2:
und . Die Maschine
hat abermals eine falsche Antwort geliefert.
-
terminiert nicht. Dann befinden
wir uns in Fall 3: kann
nicht entscheiden,
denn Mindestbedingung hierfür wäre ja,
auf jedem Eingabewort zu terminieren.
In jedem Fall sehen wir, dass auf dem Eingabewort
einen Fehler macht und somit nicht
entscheidet. Da das für
jede Turingmaschine
geht, schließen wir: keine Turingmaschine kann
die Sprache entscheiden; sie ist unentscheidbar.
Ein Student hat am 26. Juni 2024 angemerkt, dass die Sprache
ja eine extrem konstruierte, nicht wirklich relevante Sprache sei (da hatte er Recht). Insofern
sei es auch nicht relevant, dass unentscheidbar ist. Das ist allerdings auch nicht,
was uns interessiert: unser Ziel war, zu zeigen, dass unentscheidbar ist, und
die Unentscheidbarkeit von war ein Schritt auf diesem Weg. Dass
unentscheidbar ist,
ist in der Tat relevant, denn daraus folgt (nicht direkt, aber mit ein paar technischen Tricks),
dass im Prinzip
jede nichttriviale Frage über das Verhalten eines Programmcodes unentscheidbar ist.
Also sind
auch Fragen wie "Kann das Programm abstürzen?" oder "Kann ein unautorisierter Nutzer Zugang zu
XYZ erhalten?" unentscheidbar.
Das Wort Unentscheidbarkeit verwenden wir hier in seiner
technischen Bedeutung,
die wir definiert haben: es gibt keine Turingmaschine, die das Problem entscheidet, also
auf jeder Eingabeinstanz terminiert und die richtige Antwort liefert. Es gibt also in der Tat
Raum für Algorithmen, die Software untersuchen und diese gegebenenfalls verifizieren oder Fehler
/ Sicherheitslücken finden. Dies ist im Prinzip das sehr real existierende Forschungsfeld der
Programmverifikation. Die Unentscheidbarkeit des Halteproblems impliziert nicht, dass man
auf dem Feld der Programmverifikation keine Fortschritte erzielen kann; sie impliziert nur,
dass es keinen ultimaten Programmverifikator bzw. Bugfinder gibt.