TIA: utm-Theorem (Lernziele KE5 2/3, Update 2)
Update 2: Fehler korrigiert. Danke Max.
Update 2: Merksatz zum Lernziel hinzugefügt.
Update: aus zwei Beiträgen habe ich mittlerweile drei gemacht. Die Ladezeiten vom smn-Theorem waren ja nicht zu ertragen.
Nun Teil 2 der Kurseinheit 5. Nachdem wir in Teil 1 die Standardnummerierung und die Standardkomplexität
und das
-Theorem behandelt haben, folgen in diesem und dem nächsten Teil die zwei weiteren Theoreme.
Der letzte Beitrag war mit acht Seiten schon relativ lang, hoffentlich wird dieser was kürzer.
Zu früh gefreut, das Beispiel im nächsten Beitrag zum smn-Theorem hat mich ebenfalls 8 Seiten gekostet, daher die Beitragstrennung und der letzte Beitrag der Serie zu KE5 von TIA ist:
Starten wir zunächst mit einigen Anforderungen an vernünftige Programmiersprachen:
Es gibt zwei Anforderungen an vernünftige Programmiersprachen, die im Skript zu Anfang behandelt wurden. Das sind
- (U) Es soll einen Computer geben, der zu jedem Programm
und jedem möglichen Eingabewert
das Resultat
berechnet und nicht hält wenn
nicht existiert.
- (S) Zu je zwei Programmen
und
möchte man ein Programm für die Komposition konstruieren können, d.h. es soll eine berechenbare Funktion
geben, so dass
.
Auch wenn die Programmiersprache RPG wahrscheinlich beide Voraussetzungen erfüllt, vernünftig wird sie dadurch trotzdem nicht. Aber bevor IBM-Fans mir die Fensterscheiben einwerfen machen wir lieber weiter im Text 😉
Lernziel 4
Anwendung und Erläuterung des utm-Theorems
Für die Formalisierung des utm-Theorems brauchen wir zunächst eine hilfreiche Funktion, die wir im letzten Beitrag bereits definiert und als berechenbar bewiesen hatten:
mit
Ich werde das jetzt nicht groß ausführen, steht ja alles im ersten Teil der Lernziele zu KE5, sondern sage euch nur schnell noch einmal, was sie macht: Wir bekommen eine das Ergebnis der Maschine mit der Nummer
bei der Eingabe von
wenn die Standardkomplexität
existiert und kleiner/gleich
ist (die Berechnung von
bei der Eingabe von
ist noch vor
Schritten abgeschlossen). Ansonsten gibt es nur eine Null zurück. Fair.
Wie hilft diese Funktion uns nun beim utm-Theorem?
Das utm-Theorem ist definiert als
mit
für alle
.
ist dann berechenbar und wird die universelle Funktion von
genannt
Aber wahrscheinlich fügen sich bei euch noch nicht alle Puzzle-Teile zu einem Bild zusammen. Vielleicht holen wir daher zunächst etwas weiter aus: eine universelle Turing-Maschine ist eine Maschine, die beliebige andere Maschinen simulieren kann.
Wie wir im vorherigen Beispiel gesehen haben, können wir einer Turing-Maschine eine andere Maschine und das Eingabewort als Parameter mitgeben und so diese Maschine simulieren. Am Ende kopiert unsere universelle Maschine die Ausgabe auf Band und wir sind fertig (nur, dass wir im vorherigen Beitrag noch eine
zum Ergebnis addiert haben). Die Maschine agiert also als eine Art Interpreter und ist nicht auf die Berechnung einer einzigen Funktion beschränkt.
Was haben wir dazu nun gemacht? Die Turing-Maschinen sprechen nur unär, d.h. Zeichen aus unserem Bandprogramm mit
, mit unseren Klammern, Kommas und Doppelpunkten können wir eigentlich gar nicht interpretieren.
Doch, das können wir! Und zwar mittels der Nummerierung . Im obigen Beispiel stehen diese zwar im Klartext auf dem Band, aber nur der Übersichtlichkeit halber. Wenn Ihr euch statt einer öffnenden Klammer
nun ihren Nummerierungswert der Ordnungsfunktion
(
)auf dem Band denkt, dann ist das Jacke wie Hose. Im ersten Teil haben wir gezeigt, dass das durch die Ordnungsfunktion wunderbar funktioniert.
Nachdem wir nun diese Maschine in Zahlen überführt haben, haben wir eine sog. Gödelisierung durchgeführt. Die Codierung, die am Ende für die Maschine herauskommt ist die sogenannte Gödelnummer. Das formale utm-Theorem ist die formale und etwas abstrakte Version dieser universellen Turing Maschine, denn sie erfüllt die am Anfang gestellte Forderung (siehe oben).
Wir können nämlich mit diesem Computer (unsere universelle Turing-Maschine) zu jedem Programm
(welches wir vorher entsprechend codiert haben), das mit einem Eingabewert
gefüttert werden würde, durch die Simulation/Interpretation von ihm, sein Ergebnis berechnen, also genau unser gesuchtes
.
Das utm-Theorem bedeutet also nichts anderes, als dass eine Funktion (sie nimmt also die Nr. der zu simulierenden Maschine und die Eingabe für sie als Parameter auf) berechenbar ist wenn sie als Ausgabe
(also genau das Ergebnis der simulierten Maschine
) hat. Genau das bedeutet die obige formale Definition des utm-Theorems.
für alle
.
Jetzt müssen wir also nur noch eine Maschine angeben, die berechnet. Unsere Funktion
von oben leistet uns hier große Dienste: während wir bei
im Parameter
genau angeben mussten, wie lange die simulierende Maschine rechnen darf, wollen wir bei
eig. nur das Ergebnis haben und nicht angeben, wie lange unsere Maschine zu rechnen hat. Das
ist uns also egal. Und das geht ganz einfach.
Beispiel: wir simulieren das Programm , welches unser Programm
mit der Gödelnummer
simuliert, in einer Schleife und zählen unser
ab
einfach hoch. Eingabe bleibt
.
- Führe
aus und speichere es in
- Wenn
(wir haben die
-Marke im Programm mit unserem
noch nicht erreicht und bekommen daher eine
als Ausgabe), erhöhe
um eins und führe dann
aus, usw.
- Wenn
eine Ausgabe ungleich
hat, dann subtrahiere eine
vom Ergebnis (in
haben wir es ja immer um Eins erhöht) und beende dich.
Dam Ende steht in das Ergebnis (
) und wir haben unser kleinstes
auch. Es wird im Skript im Register
zwischengespeichert. Damit ist auch
berechenbar.
Im Skript wird eine weitere universelle Funktion für die Standardkomplexität, nämlich definiert:
mit
für alle
.
Sie macht nicht viel anders als . Wir bekommen hier jedoch nicht das Ergebnis
als Ausgabe, sondern das kleinste
(die Anzahl der Rechenschritte, Schrittzahlfunktion, wir erinnern uns?) bei der Eingabe von
, also genau
. Das Ergebnis schreiben wir ins
, dem Ergebnisregister der berechnenden Maschine und sind fertig.
Zusammenhang zu
Nachdem ich gemerkt habe, dass ich einige Details von und
durcheinander brachte und freundlich von Harald und Carsten aus der NG darauf hingewiesen wurde, habe ich mich entschlossen das hier auch nieder zu schreiben. Obwohl ich der Meinung bin, dass die meisten von euch die Unterschiede zwischen den beiden Mengen gut bewusst sind und sie keine Auffrischung brauchen, bin ich mir sicher, dass ich das in spätestens einigen Monaten vor der Prüfungsvorbereitung wieder verdrängt habe. Also tue ich etwas für mein "Zukunfts-ich" (How i met your mother lässt grüßen) und schreibe in aller Deutlichkeit nochmal:
: partielle (nicht überall definierte), berechenbare Funktionen. Nummerierung
von
erfüllt das utm-Theorem, d.h. es gibt eine universelle Turingmaschine, die die Funktion interpretiert und die entsprechende Ausgabe berechnet.
: totale (überall definierte), berechenbare Funktionen. Keine Nummerierung von
erfüllt das utm-Theorem (es gibt also keine universelle Funktion
zum interpretieren des Programms).
Die letzte Feststellung ist wichtig: warum erfüllt keine Nummerierung von das utm-Theorem? Denn es wäre doch - wie im Skript angemerkt - praktisch wenn man sich nur auf überall definierte Funktionen beschränken könnte. Was nützt einem ein Programm, dass bei einer Eingabe ggf. nicht hält? Leider geht das nicht. Die Beweisidee ist wie folgt:
Zunächst: was ist eine Nummerierung? Einfach nur die Nummer einer Funktion. Während wir also , die einstelligen, berechenbaren, ggf. partiellen Funktionen mit
nummeriert haben und diese Funktion (bzw. die Maschinen, die die Funktionen berechnen) durch eine universelle Turingmaschine mit
simulieren, können, bekommen wir bei
ein Problem.
Warum? Während nicht für jedex
definiert sein muss, d.h. es auch eine Ausgabe
geben kann, haben wir bei dem gleichen Spiel mit
, der Nummerierung von
immer eine Ausgabe. Ist ja auch klar, die Funktionen aus
sind total und damit eben für jedes
definiert.
In was für ein Problem laufen wir hier?
Wir nehmen eine Nummerierung von
. Lt. utm-Theorem gibt es dazu eine universelle Funktion
, d.h. eine universelle Turing-Maschine, welche als Eingabe die Gödelnummer/den Index der Maschine und ein
bekommt und diese so simuliert (siehe das 2. Beispiel für
von oben), dass auf Band
anschließend die Ausgabe
steht.
Nun basteln wir uns eine Funktion . Diese ist auch total und berechenbar, da
ja selbst total und berechenbar war. D.h. die universelle Funktion
simuliert uns die Maschine
mit der Eingabe
und addiert eine
dazu. Sie ist damit definitiv von
verschieden und somit eine neue Maschine.
Da es eine komplett neue Maschine ist, hat sie natürlich auch eine neue Gödelnummer/einen neuen Index . Da wir aber alle totalen Funktionen bereits durchnummeriert haben, ist
, was aber nicht funktioniert. Denn
existiert ja bereits in unserer Auflistung und kann ja gar nicht eine neue Maschine sein.
Das ist wieder ein Beweis durch Diagonalisierung: wir sind von der Vollständigkeit unserer Auflistung ausgegangen und haben offensichtlich trotzdem noch eine neue Maschine erstellen können, was uns zu einem Widerspruch führt. Damit erfüllt keine Nummerierung nur der totalen, berechenbaren Funktionen das utm-Theorem.
Und was ist mit ? Damit klappt es:
Wir gehen zunächst genauso vor, wie bei : holen uns eine Nummerierung mit
und eine universelle Funktion
.
Nun erstellen wir die neue Funktion: . Da
nicht total sein muss (für ein
kann
sein), könnte
ebenfalls nicht total sein und die Aussage
hätte durchaus Bestand:
.
Ist tatsächlich etwas abstrakt, aber hoffentlich trotzdem nachvollziehbar.
(Hier geht ein großer Dank an Barbara, Harald, Oliver und Herbert aus der NG für ein paar - wenn auch hinkende - Vergleiche 😉 Wenn jemand in "einfacheren Worten" eine Erklärung hat, warum eine Nummerierung für das utm- Theorem erfüllen kann, aber keine Nummerierung für
das zu leisten vermag, der möge mir bitte eine Nachricht schicken. Ich würde das dann gerne hier aufnehmen)
Antwort zum Lernziel: bei dem utm-Theorem geht es im Grunde um die Frage ob es einen Computer gibt, der jeden anderen Computer simulieren kann. In der theoretischen Informatik wäre es zwar unproblematisch für jede Aufgabe eine eigene Maschine anzugeben, ist aus praktischer sicherlich kein gangbarer Weg.
Diese Fragestellung hat große Bedeutung bei den Programmiersprachen, denn nur durch die Bejahung dieser Frage können Programmiersprachen durch Computer interpretiert und so Anwendungen auf ihnen ausgeführt werden.
Daher betrachten wir den Computer als universelles Gerät, dass Programme (andere Computer sozusagen, die nur eine Funktion berechnen) und Daten entgegen nimmt und die Funktion des Programms auf den entgegen genommenen Daten simuliert.
Frage ist hierbei: gibt es denn so eine Funktion, die auf einer Turingmaschine ausgeführt, eine andere Funktion simulieren kann? Und genau diese Funktion wird universelle Funktion genannt, die als Eingabe eine Gödelnummer
des zu simulierenden Programms
und die Eingabedaten
entgegen nimmt und auf diesen die Befehle des Programms Schritt für Schritt durchführt um am Ende die gleiche Ausgabe zu haben wie das Programm selbst:
.
In unserem Beweis im letzten Betrag hat es unsere Funktion für uns erledigt (wobei sie noch die maximale Anzahl der zu rechnenden Schritte verwendet hatte).
Merksatz:
Das formale utm-Theorem ist die formale und etwas abstrakte Version dieser universellen Turing Maschine. Es besagt, dass eine universelle Funktion existiert, die jede andere berechenbare Funktion berechnen kann.
Im nächsten Beitrag geht es dann um das smn-Theorem und Rekursionssätze.
Sie können zum Ende springen und ein Kommentar hinterlassen. Pingen ist im Augenblick nicht erlaubt.
Dezember 25th, 2013 13:56
Hallo,
"Auch wenn die Programmiersprache RPG wahrscheinlich beide Voraussetzungen erfüllt, vernünftig wird sie dadurch trotzdem nicht. Aber bevor IBM-Fans mir die Fensterscheiben einwerfen machen wir lieber weiter im Text"
Mensch, da kennt tatsächlich noch jemand RPG, Respekt!
Mit freundlichen Grüßen
Juli 7th, 2014 00:25
Hallo Anton,
vielen Dank, dass du dein Blog weiter pflegst.
Ein paar Kleinigkeiten zum Lernziel 4 + Beispiel:
(1^2:1,,1)(:1,1,1^2)(:B,,) (2x) ist das Programm aus Aufgabe 7.1.2,
gemeint ist wahrscheinlich w1 = (: R, 1)(1 : B, 11, ) aus Aufgabe 7.1.7.
"zählen unser t ab _1_" und "Führe h(n1,3,1) aus und ..."
Im Skript beginnt die Registermaschine mit R3=0, also t=0 (Beweis zu Satz 7.2.2).
Und weiter unten: h(2,3,2) statt h(n1,3,2) bzw. h(n1,3,1)
Viele Grüße
Steve
Juli 9th, 2014 15:16
Hallo Steve,
ich habe jetzt nur drüber gelinst. Aber es scheint okay zu sein. Ich habe ja extra etwas andere Benamungen genommen, als im Skript, damit es verständlicher ist. Aber ich schaue in einer ruhigen Minute nochmal genauer hin.
In jedem Fall, danke für den Kommentar.