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.