TIA: Berechenbarkeit (Lernziele aus KE4, Update 6)
Update: ich modelliere auch diesen Beitrag auf die Lernziele um. Evtl. kann es sein, dass der Beitrag nicht ganz fertig wird, so dass ein paar Antworten (noch) leer sind. Da ich ihn aber nicht speichern kann ohne ihn zu aktualisieren oder ihn offline nehmen müsste, habe ich keine andere Wahl als das zunächst so zu handhaben.
Update 6: Nachdem ich nun schon zwei Mails zum Thema -Rekursion bekommen habe, möchte ich das hier noch einmal ausführen. Für die Details zum Thema Nullstellen möchte ich mich hier auch bei Oliver bedanken. Lernziel 5 also.
Update 5: mir ist was zur Standardnummerierung von und aufgefallen, dass ich hier passend unbedingt noch erwähnen musste.
Riesen Update: alle Lernziele habe ich nun überarbeitet und einige Ungenauigkeiten korrigiert. Der Beweis der nicht-berechenbaren Funktionen ist wohl auf das 10-fache des ursprünglichen Texts angewachsen. Irgendwie konnte ich mich mit dem alten Verweis auf das Diagonalrgument von Cantor für die Überabzählbarkeit der reellen Zahlen nicht anfreunden (beim ersten Erstellen hielt ich das noch für ausreichend) und habe den Skriptbeweis nun komplett auseinander genommen. Hoffentlich hilft es euch.
Kurseinheit 4 ist wieder ein Rundumschlag. Einige Dinge, die hier drin sind, hätten sich auch in Kurseinheit 2 wiederfinden müssen (LOOP, WHILE, Churchsche These und Zusammenhang zu -rekursiven Funktionen. Taten sie aber nicht. Wäre wahrscheinlich einfach zu einfach gewesen. Ich würde daher vorschlagen, dass wir uns ausnahmsweise nicht thematisch, sondern anhand der Lernziele entlang hangeln.
Rekapitulation: Zahlen, Wörter
Nochmal als Wiederholung bevor wir loslegen.
Zahlenfunktionen: . D.h. Abbildung von ggf. mehrstelligen (unser ) Eingabewerten von natürlichen Zahlen auf einen einzigen Ausgabewert, eine einzige natürliche Zahl. Berechenbar mit Registermaschinen, nicht mit Turingmaschinen.
Konkretes Beispiel: mit ,
z.B.
Wortfunktionen: . D.h. Abbildung von ggf. mehreren (wieder unser ) Eingabewerten von beliebig langen (unser ) Worten über einem Alphabet (unser ) auf einen einzigen Ausgabewert: ein einziges, beliebig langes Wort. ist hier die Wortmenge über dem Alphabet . Berechenbar mit Turingmaschinen, nicht mit Registermaschinen.
Konkretes Beispiel: mit ,
z.B.
Wir können Zahlenfunktionen nicht auf Turingmaschinen und Wortfunktionen nicht auf Registermaschinen berechnen. Es gibt jedoch einen Weg: Erst wenn man Wörter in Zahlen codiert und Zahlen in Wörter (bijektive Abbildung zwischen zwei Mengen: Wörtern und Zahlen) kann man diese mit den entsprechend anderen Maschinen berechnen.
Ausgenutzt wird dabei, dass Registermaschinen und Turingmaschinen über Flussdiagramme definiert sind. Aber kümmern wir uns zunächst um die Standardnummerierung selbst.
Das ist die sogenannte Standardnummerierung (bijektive Abbildung zwischen den natürlichen Zahlen und einer Mengen). Definition kommt gleich. Es gibt jedoch einen wesentlichen Unterschied zu einer Nummerierung, der nicht verschwiegen werden darf.
Eine Nummerierung ist nicht bijektiv; Surjektivität reicht. Wir können in der Nummerierung dann jedem Wort mindestens eine Zahl zuordnen, aber wir haben keine eindeutige Umkehrabbildung, d.h. wenn wir dann zu einem Wort die zugehörige Zahl suchen, könnten wir diese mit etwas Pech auf mehrere Zahlen abbilden.
Achtung: während die Standardnummerierung von durch bijektiv ist, ist die Standardnummerierung der berechenbaren, einstelligen Funktionen aus dem nächsten Beitrag das nicht! Warum, sage ich dann dort. Bitte behaltet das unbedingt im Hinterkopf.
Formal definiert ist eine Nummerierung also:
Sie kann partiell sein und ist - wie gesagt - surjektiv. Damit hat zwar jedes Element aus der nummerierten Menge eine Zahl aus , aber nicht zu jeder Zahl aus gibt ein Element aus der Menge .
Und weil Marco mich in den Kommentaren zu KE5 auf die Idee gebracht hat, noch eine kleine Nebeninfo: Haben wir eine bijektive Abbildung zwischen zwei Mengen, gelten diese als gleichmächtig und die Eigenschaften der einen, gelten auch für die andere Menge. Bilden wir also die natürlichen Zahlen mittels einer bijektiven Funktion auf eine andere Menge ab, wie wir das mit der Standardnummerierung tun, so übernimmt diese Menge eine wunderbare Eigenschaft der natürlichen Zahlen : sie ist dann ebenfalls abzählbar unendlich.
Lernziel 1
Angabe und Erläuterung der Definition einer Standardnummerierung von
Nehmen wir als Beispiel ein Alphabet mit Symbolen, welches eine totale Ordnung hat (d.h. die Symbole innerhalb des Alphabets sind - wie auch immer - eindeutig sortiert), so beinhaltet alle Worte über dem Alphabet .
ist das -te Wort aus dieser sortierten Liste. Die Sortierung nennt man Ordnungsfunktion. Das spannende an dieser Nummerierung ist, dass sie bijektiv ist. Wir haben also eine eindeutige Abbildung von einem Wort in eine Zahl und eine Inverse, die uns zu einer Zahl ein eindeutiges Wort liefert. Lasst uns die Definition mal formalisieren:
ist ein Alphabet mit .
die Ordnungsfunktion mit und .mit sowie
für alle .
ist unsere Inverse der Funktion und damit . Sie gibt uns zu einer gegebenen Zahl das entsprechende, eindeutige Wort zurück und wird Standardnummerierung von genannt.
Keine Sorge, wir gehen das direkt an einem Beispiel durch.
Beispiel:
mit (Kardinalität, Mächtigkeit einer Menge). Ein Alphabet mit den Buchstaben und , d.h. nur Elementen und damit der Kardinalität .
Wir haben zwei Elemente und im Alphabet, also ist und wir haben und : innerhalb der Wortmenge werden die Elemente wie im Skript nach Länge und dann lexikographisch geordnet. Die Menge wäre dann
.
Wir haben nun jedem unserer zwei Elemente eine Ordnungszahl zugewiesen. Das ist unsere Ordnungsfunktion .
Der letzte Teil ist jetzt etwas ekelig, aber halb so wild. Erinnert mich irgendwie an SIMPLEX. Die Funktion macht nichts anderes, als zu einem bestimmten Wort die eindeutige Zahl anhand der definierten Ordnung zu bestimmen. Wir suchen z.B. die zugewiesene Zahl zu . steht an 10. Stelle in der Reihenfolge und wir erwarten die auch als Ergebnis.
(ist klar, die Kardinalität von , d.h. Anzahl der Elemente)
(das Wort besteht aus drei Elementen, wir zählen von und haben damit )
ist unsere Ordnungszahl. Da zuerst kommt, ist und da an zweiter Stelle in unserer Ordnung kommt, ist . Hätten wir noch , so wäre unserer festgelegten Ordnung nach.
Und ja, steht an 10. Stelle in unserer Ordnung.
Man mache sich einfach klar, dass ein beliebiges Alphabet definieren können, solange wir nur eine numerische Ordnung auf den Elementen des Alphabets definieren. Da wir aus den Elementen des Alphabets Worte bauen können, können wir auch aus den Ordnungszahlen, die den Elementen zugeordnet sind Kombinationen herstellen.
Die Ordnung ist ja nichts weiter als die Festlegung der Reihenfolge der verwendeten Elemente in unserem Alphabet. Damit rechnen wir statt mit den Buchstaben, nun mit ihren "Ordnungszahlen". Und da auf den verwendeten, natürlichen Zahlen für unsere Reihenfolge auch eine natürliche Ordnung herrscht (), können wir damit wunderbar rechnen.
Unser im Alphabet repräsentiert unsere "Ordnungszahl" und unsere "Ordnungszahl" , welche wir dann oben in der Gleichung für verwendet haben und damit auf den Rechenweg kommen. Die grüne 1 ist daher die Ordnungszahl unseres und die rote 2 die unseres .
Die Inverse zu ( ist ein Wort) ist und gibt uns für eine Zahl das dazugehörige Wort. Das 10. Wort wäre also .
Damit ist eine Standardnummerierung von , also aller Worte über dem Alphabet .
Antwort zum Lernziel: die Standardnummerierung der Worte über einem Alphabet ist eine bijektive Abbildung zwischen den natürlichen Zahlen und den Worten aus . Die Bijektivität ist wichtig damit wir einer Zahl eindeutig ein Wort und einem Wort eindeutig eine Zahl zuweisen können.
Diese Zuweisung funktioniert aufgrund einer sog. Ordnungsfunktion auf dem Alphabet , welches jedem Zeichen aus den Alphabet eine eindeutige Nummer (Ordnungszahl) aus den natürlichen Zahlen zuordnet. Durch die natürliche Ordnung auf den natürlichen Zahlen haben wir auch eine natürliche Ordnung auf den Elementen aus unserem Alphabet , die wir vorher nicht hatten.
Mit bekommen wir somit zu einem Wort die zugehörige Ordnungszahl und mit zu einer Zahl das zugehörige Wort aus den Worten über dem Alphabet : .
Lernziel 2
Formulierung und Erläuterung der Beziehung zwischen Zahlen- und Wortfunktionen
Zunächst noch einmal die Definition wann Wortfunktionen berechenbar sind:
Eine (ggf. partielle) Wortfunktion ist genau dann berechenbar, wenn es eine Turing-Maschine gibt, die die Funktion berechnet. Wenn also gilt.
Das gleiche Spiel für Zahlenfunktionen.
Eine (ggf. partielle) Zahlenfunktion ist genau dann berechenbar, wenn es eine Registermaschine gibt, die die Funktion berechnet. Wenn also gilt.
Kennen wir schon aus den alten Beiträgen. Registermaschinen für Zahlen- und Turingmaschinen für Wortfunktionen. Langweilig. But wait, there's more! Im Zusammenhang mit der Standardnummerierung hatten wir das noch nicht. Denn wir können Wortfunktionen durchaus mit Registermaschinen und Zahlenfunktionen mit Turingmaschinen berechnen.
Man macht sich zunächst noch einmal folgenden Zusammenhang klar: Unsere (-steligen) Wortfunktionen, welche die Turingmaschinen (Mehrbandmaschinen mit Bändern) berechnen können, können auch auf Einbandmaschinen berechnet werden (Ihr erinnert euch: Spuren, Hilfssymbole, etc.?). Wir können uns also auf die Betrachtung der Einbandmaschinen für die Berechnung der Wortfunktionen beschränken.
Und hier kommt die Standardnummerierung ins Spiel: wollen wir eine Wortfunktion auf einer Registermaschine berechnen, geht das zunächst nicht. Die Registermaschine rechnet ja mit Zahlen und nicht mit Worten. Und auch als Ausgabe bekommen wir eine Zahl und kein Wort. Aber hey! Wir können die Worte ja mit unserer Standardnummerierung eindeutig auf Zahlen und Zahlen eindeutig auf Worte abbilden. Damit gelingt es uns die Eingabeworte für unsere Turingmaschine in eine Zahl zu verwandeln, damit die Registermaschine zu füttern und die Ausgabe dieser (die ja auch eine Zahl ist) wieder in ein Wort zu verwandeln.
Die Standardnummerierung erledigt das. Was uns hier noch fehlt ist die Umwandlung der Flussdiagramm der Turing- in eine passende Registermaschine. Das geschieht wie folgt:
- Aufbereitung der Eingabe: jedes Register bekommt die eindeutige Nummer der Eingabeworte. Nur Register , unser Ausgaberegister bleibt leer. Die Worte der Arbeitsbänder werden so alle in die Register abgebildet. Ein Register bekommt also zugewiesen, z.B. .
- Simulation des Flussdiagramms der Turingmaschine (hier lasse ich die Details erstmal weg, evtl. trage ich sie nach)
Nun können wir auch mit der formalen Definition des Zusammenhangs etwas anfangen:
Sei ein Alphabet, eine Standardnummerierung von , . Es sei und . Dann gilt:
berechenbar berechenbar.
berechenbar berechenbar.
Harter Tobak. Der Satz besagt eig. nichts anderes, als dass
Die Wortfunktion genau dann berechenbar ist, wenn ihre Verschlüsselung eine berechenbare Zahlenfunktion ist
und
Die Zahlenfunktion genau dann berechenbar ist, wenn ihre Verschlüsselung eine berechenbare Wortfunktion ist.
Also genau das, was wir oben bereits beschrieben haben. Versuchen wir dass mal anhand eines Beispiels aufzudröseln:
Beispiel: , mit der Ordnungsfunktion ,
d.h. ist wieder unser . und unser . Element in der Ordnung.
Wir definieren und willkürlich:
Wir müssen uns anschauen, was und aus der Definition von oben denn nun tatsächlich tun.
Fangen wir mit an, denn es liefert uns zu der Nummer des Definitionswertes (ein Wort) die Nummer des Bildes/Funktionswerts (ja eig. auch ein Wort):
Wir machen uns zunächst einmal klar, dass ist, denn ist das erste Element und gibt uns zu einer Zahl das Wort aus. Die Inverse wäre dann , zu einem Wort bekommen wir also seine eindeutige Nummer.
Und lasst euch von nicht erschrecken. Es ist nur eine Komposition aus den oben genannten Funktionen und sieht geklammert weniger bedrohlich aus: . Aber der Reihe nach.
Unserer oben definierten Funktion nach, ist z.B. . Zu dem Definitionswert bekommen wir also das Bild/den Funktionswert . Was tun wir nun wenn wir statt auf Worten (was und ja selbstredend sind) nun auf den zugehörigen Zahlen rechnen wollen? Die Funktionalität der Ursprungsfunktion soll dabei natürlich erhalten bleiben. Und genau das geht mit unserem , was ja nur - wie gesagt - eine Komposition von Funktionen ist.
Wir tun das, was wir wollten (auf den Zahlen der Worte und rechnen statt auf den Worten selbst) und setzen , da der Zahlenwert unseres Arguments ist und dröseln auf:
Ergebnis passt? Passt!
Damit haben wir dank unserer Standardnummerierung unsere Wortfunktion in eine Zahlenfunktion überführt und können ruhigen Gewissens erneut sagen:
Die Wortfunktion ist berechenbar gdw. ihre Verschlüsselung eine berechenbare Zahlenfunktion ist.
Damit kann man nun eine Zahlenfunktion angeben, welche statt auf abzubilden nun eine auf eine abbildet. Ist diese berechenbar, so ist auch eine Wortfunktion berechenbar.
Analog geht der gleiche Spaß mit , was unsere Zahlenfunktion in eine Wortfunktion verschlüsselt. Wir setzen statt nun einfach und schauen ob wir herausbekommen.
Wow! Was man mit den natürlichen Zahlen alles anstellen kann! Wir haben unsere Zahlenfunktion nun in eine Wortfunktion verschlüsselt und schließen unser Beispiel mit folgenden Worten ab:
Die Zahlenfunktion ist berechenbar gdw. ihre Verschlüsselung eine berechenbare Wortfunktion ist.
That's it.
Antwort zum Lernziel: mittels Standardnummerierung ist es uns möglich Worte in Zahlen und Zahlen in Worte bijektiv zu verschlüsseln. Da Register- und Turingmaschinen über Flussdiagrammen definiert sind, können wir diese ineinander simulieren und durch die Standardnummerierung so mit Registermaschinen auf Worten und mit Turingmaschinen im Endeffekt auf Zahlen arbeiten.
Lernziel 3
Definition der primitiv-rekursiven Funktionen
Im Beitrag über primitiv rekursive Funktionen und LOOP Berechenbarkeit haben wir das Thema bereits behandelt. Daher nur ein kurzer Abriss der Definition:
Eine Funktion heißt primitiv-rekursiv wenn sie sich in endlich vielen Schritten aus der menge der Grundfunktionen durch wiederholtes Anwenden der Substitution und primitiver Rekursion erzeugen lässt.
Diese Menge nennen wir .
PS: sie sind alle total (wichtig!) und eine echte Teilmenge der -rekursiven Funktionen (kommen wir später noch darauf zurück).
Die im Skript genannten Grundfunktionen sind:
- Null- und einstellige Nullfunktion
- Nachfolgefunktion
- Projektion
Alle Funktionen, die wir damit und durch wiederholtes Anwender der primitiven Rekursion und Substitution erstellen können, sind ebenfalls primitiv-rekursiv aufgrund der Abgeschlossenheit. Beispiele zu diesen findet Ihr im oben verlinkten Beitrag.
Wir hatten das bereits im Beitrag zur -Berechenbarkeit ausgearbeitet, es sei dennoch der Vollständigkeit halber darauf hingewiesen:
Eine Funktion ist -berechenbar genau dann wenn sie primitiv-rekursiv ist.
Nicht vergessen. 😉
Antwort zum Lernziel: die Menge der primitiv-rekursiven Funktionen wird mittels der oben genannten Grundoperationen und wiederholtes Anwenden der Substitution () und primitiver Rekursion () gebildet. Es sind alles totale Funktionen (d.h. überall definiert) und bilden eine Teilmenge der -rekursiven Funktionen.
Lernziel 4
Beweis, dass bestimmte Funktionen primitiv-rekursiv sind
In dem oben verlinkten Beitrag könnt Ihr euch die Details dazu zu Gemüte führen. Wir zeigen dort, dass die Addition primitiv-rekursiv ist.
Antwort zum Lernziel: Für den Beweis, dass eine Funktion primitiv-rekursiv ist wird diese einfach mittels der Grundoperationen (oder der als primitiv-rekursiv bereits bewiesenen anderen Operationen) nachgebildet. Damit gilt die Funktion für ein als bewiesen. Mittels vollständiger Induktion wird es dann auch für gezeigt.
Ex-Lernziel: Rechenzeitsatz
Ebenfalls wird im Skript jedoch der Rechenzeitsatz erwähnt. Der besagt nichts anderes, als dass eine Maschine , welche eine Funktion für eine Eingabe von eine bestimmte Anzahl an Schritten rechnet. Die Anzahl der Schritte wird mit bezechnet.
Gibt es diese Anzahl von Schritten, so ist die Funktion primitiv rekursiv und die Anzahl der Schritte durch eine Funktion () beschränkt. Wir haben hier also nichts weiter als die Beschränkung der Rechenschritte einer Registermaschine beim Berechnen einer Funktion abhängig vom Eingabewert der Funktion, einer Konstanten und einer anderen primitiv rekursiven Funktion. Im Skript wird als Funktion verwendet, aber Achtung: das ist nicht die Ackermann-Funktion, denn diese ist nicht primitiv rekursiv und muss primitiv rekursiv sein!
Alle Funktionen, die sich auf einer Registermaschine nicht in (Exponentialzeit) berechnen lassen, gelten lt. Skript als "nicht in der Praxis berechenbar". Damit sind alle in der Praxis berechenbaren Funktionen primitiv rekursiv. Die Isomorphie von Graphen ist z.B. in Exponentialzeit berechenbar, aber es ist noch nicht bewiesen ob es nicht einen effizienteren Algorithmus gibt.
Lernziel 5
Definition der -rekursiven Funktionen
Auch das haben wir bereits in einem Eintrag für die -rekursiven Funktionen bereits behandelt. Wir fassen das nochmal in einem Merksatz zusammen:
Die ggf. partielle Funktionen (d.h. sie sind ggf. nicht überall definiert: Beispiel Wurzelfunktion) ist -rekursiv wenn sie mittels der Grundoperationen: Nachfolge-, null- und einstellige Funktion sowie durch wiederholtes Anwenden der Substitution, primitiver Rekursion und des -Operators abbilden lässt.
Gemerkt? Die Totalität unserer Funktion ist für die -Rekursion nun nicht mehr notwendig. Auch haben wir zusätzlich zu den Grundoperationen, der Substitution und der primitiven Rekursion nun mit dem -Operator das Nullsetzen der Funktion mit drin.
Aber Achtung: der -Operator ist im Skript nur auf totalen Funktionen definiert. Bei partiellen Funktionen können wir in Endlosschleifen geraten, aus denen wir sonst nicht mehr herauskommen. Durch eine kleine Erweiterung können wir aber auch auf partiellen Funktionen arbeiten (siehe hier). Ich schreibe dann später noch ein par Kleinigkeiten dazu sobald ich alle Kurseinheiten nochmal überarbeite.
Merke: während man die primitiv rekursiven Funktionen also in -Schleifen nachbilden kann, kann man -rekursiven Funktionen nur in -Schleifen und nicht in -Schleifen nachbilden. Das liegt daran, dass die Anzahl der Iterationen bei der primitiven Rekursion im Vorfeld bekannt ist (FOR 1 TO 5 DO X) und bei der -Rekursion (DO X WHILE i NOT 0) nicht. Dieses "Nullstellen" unserer Funktion besorgt uns der -Operator.
Update: Ein ausführliches Beispiel mittels partieller Subtraktion zum Nullsetzen habe ich im oben verlinkten Beitrag zur -Rekursion selbst gebracht. Dort wurde gezeigt, wie man die -Rekursion anwendet um eine Funktion, die nicht mittels primitiver Rekursion (LOOP) berechenbar ist, als berechenbar nachzuweisen.
Es stellt sich die Frage, warum der -Operator auf totalen Funktionen definiert ist und der -Operators auch auf partiellen Funktionen arbeiten kann.
Beispiel mit als -berechenbar nachweisen
Was müssen wir hier tun? Offensichtlich ist auf den natürlichen Zahlen partiell, denn , da das Ergebnis keine natürliche Zahl ist. Wenn wir diese Funktion nun als -rekursiv nachweisen wollen, müssen wir folgendes tun:
Wir basteln uns durch "Nullsetzen" aus unserer Wurzelfunktion eine neue Funktion , die uns in Abhängigkeit von eine ausgibt wenn korrekt berechnet wurde und ansonsten etwas anderes als eine als Ergebnis hat. Kann die Berechnung nicht korrekt abgeschlossen werden, erhöht auf das und läuft ewig weiter.
Sie darf aber kein undefiniertes Ergebnis bringen, da wir ansonsten mit dem nächsten nicht fortfahren könnten. Das ist der Grund, warum der -Operator nur auf totalen Funktionen definiert ist. Wäre die "nullgesetzte" Funktion nicht total, hätte das einen Abbruch zur Folge und unser würde uns nichts brauchbares liefern.
Die aus daraus entstehende Funktion ist aber partiell. Denn wir bekommen das Ergebnis, die kleinste Nullstelle, nur dann wenn die Berechnung in Ordnung war. Ansonsten läuft unser ja durch die Totalität von der "nullgesetzten" Funktion endlos weiter und wir kommen nie zum Stillstand.
Formal ausgedrückt wäre dies:
Damit ist partiell.
PS: betrachtet bitte als "Die aus entstehende Funktion", d.h. als komplettes Gebilde und nicht als Funktion auf auf .
Schaut euch, wie gesagt, noch einmal ein konkretes Beispiel zur partiellen Subtraktion hier an. Dort seht Ihr auch, wie man eine Funktion nullsetzen kann.
Antwort zum Lernziel: die -rekursiven Funktionen können - im Gegensatz zu primitiv-rekursiven - auch partiell sein. Sie werden ebenfalls durch die gleichen Grundoperationen und Substitution und primitive Rekursion gebildet wie die primitiv rekursiven Funktionen.
Durch den -Operator jedoch wird eine Möglichkeit geschaffen die Anzahl der Schleifendurchläufe, nicht von Anfang an festlegen zu müssen (wie das bei der primitiven Rekursion der Fall ist), indem man die Funktion "Nullsetzt" und mit dem -Operator die erste Nullstelle sucht.
Es gibt damit Funktionen, die mittels -Schleife implementierbar, aber nicht primitiv-rekursiv sind (Ackermann-Funktion z.B.). Die Klasse der implementierbaren Funktionen ist damit größer als die Klasse der primitiv-rekursiven Funktionen.
Lernziel 6
Erläuterung der Churchschen These
Etwas Vorarbeit: es gibt zunächst einen großen Unterschied zwischen maschinell berechenbar und Register-(und damit auch Turing-)berechenbar. Worin liegt der?
Nehmen wir als Beispiel die Ackermann-Funktion. Wir können sie implementieren und wissen daher, dass sie (-)berechenbar ist und mit einer Turing- oder Registermaschine berechnet werden kann.
Wollt Ihr mal berechnen? Macht das mal. Und dann könnt Ihr hier weiterlesen. Okay, das war gemein: es gibt keinen Rechner, der genügend Speicher hätte diese Zahl zu speichern. Ebenfalls würde selbst das Alter des Weltalls nicht ausreichen um einen Speicher mit dieser Zahl zu füllen (Satz geklaut aus dem Skript).
Vielleicht habt Ihr nun eine kleine Vorstellung, was den Unterschied ausmacht zwischen intuitiv berechenbar und maschinell-berechenbar.
In der theoretischen Informatik ist uns diese "maschinelle Berechenbarkeit" aber nicht wirklich wichtig; wir kümmern uns eher um die erste Eigenschaft: die intuitive Berechenbarkeit. Die Speicherkapazität und die Geschwindigkeit der Maschinen ändert sich und es gibt immer mehr Funktionen, die maschinell berechnet werden können. Aber die (intuitiv) berechenbaren Funktionen ändern sich nicht nicht. Sie können entweder berechnet werden, oder eben nicht.
Kommen wir daher zur Churchschen These selbst (aus der Wikipedia, die aber etwas von der im Skript abweicht. Warum sage ich gleich):
Die Klasse der Turing-berechenbaren Funktionen stimmt mit der Klasse der intuitiv berechenbaren Funktionen überein.
Wir erinnern uns an den Begriff der intuitiven Berechenbarkeit: es gibt einen Algorithmus für eine Funktion , der die Funktion berechnet. Auch können wir uns auf einstellige Zahlenfunktionen beschränken, da wir Wortfunktionen mittels der Standardnummerierung in Zahlen codieren können und mehrstellige Zahlenfunktionen letztendlich durch die Cantorsche Paarungsfunktion in einstellige Zahlenfunktionen überführt werden können. Wir betrachten also im Endeffekt nur noch die Einband-Turing- (Wortfunktionen) oder die Registermaschinen (Zahlenfunktionen).Aufgrund der Äquivalenz beider Berechnungsmodelle können wir uns zudem aussuchen, was wir betrachten.
Lange Rede, kurzer Sinn: um uns also nicht mit "maschinell" und "intuitiv" auseinandersetzen und den Begriff "maschinell" alle paar Jahre neu definieren zu müssen, setzen wir einfach "maschinell" mit "intuitiv" gleich. Und da wir mit Register- und Turing-Berechenbarkeit (durch die Standardnummerierung) ein Äquivalentes Berechnungsmodell haben, können wir statt dem oben genannten Satz aus der Wikipedia, problemlos auch die Churchsche These aus dem Skript herleiten:
Die Register-berechenbaren Funktionen sind genau die maschinell berechenbaren Zahlenfunktionen.
Deutlich geworden?
Die These bedeutet also nichts anderes, als dass man mit der Turing- oder Registermaschine alle intuitiv/maschinell berechenbaren Funktionen berechnen kann. Sie ist zwar nicht beweisbar, da wir den Begriff "intuitiv berechenbar" nicht exakt formulieren können, sie wird aber allgemein akzeptiert.
Gelingt es uns ein Computermodell anzugeben, dass Funktionen berechnen kann, die mit der Turingmaschine nicht berechnet werden können, so könnten wir die These widerlegen (Ihr wisst, also was zu tun ist!).
Noch ein paar Hintergrund-Details:
Es ist noch niemandem gelungen eine maschinell-berechenbare Funktion anzugeben, die nicht Turing/Register-berechenbar ist, daher liegt der Schluss nahe, dass wir (ohne Berücksichtigung der Faktoren wie Zeit und Speicher) sagen können, dass die maschinell-berechenbaren Funktionen wirklich genau die intuitiv Register/Turing-berechenbaren Funktionen sind.
Antwort zum Lernziel: Die Churchsche These besagt, dass alle intuitiv bzw. maschinell berechenbaren Funktionen genau die Turing- bzw. Register-berechenbaren Funktionen sind. Sie ist aufgrund des fehlenden Formalismus des Begriffs "intuitiv" nicht beweisbar, konnte aber auch nicht widerlegt werden.
Lernziel 7
Beweis der Existenz von nicht-berechenbaren Funktionen durch Diagonalisierung
Wir rekapitulieren auch hier (im Beitrag über Entscheidbarkeit könnt ihr euer Wissen darüber auffrischen): eine Menge ist entscheidbar (d.h. rekursiv) wenn für jede Eingabe aus der Definitionsmenge entschieden werden kann, ob sie eine Eigenschaft besitzt oder nicht. Formal ausgedrückt:
Entscheidbar/rekursiv: eine Menge heißt entscheidbar falls die charakteristische Funktion berechenbar ist.
Ich wiederhole hier aus dem oben verlinkten Beitrag die formale Definition:
Eine Menge ist entscheidbar/rekursiv wenn die charakteristische Funktion definiert durch
berechenbar ist (Achtung: sie muss berechenbar sein!)
Wir haben also eine definitive Aussage zu einer Eigenschaft eines Elements: wir können für jedes Element entscheiden ob es diese Eigenschaft besitzt oder nicht.
Was wäre so eine entscheidbare Eigenschaft? Die Entscheidung ob eine Zahl eine Primzahl ist oder nicht wäre entscheidbar.
Den Begriff der Entscheidbarkeit haben wir aber nur für Mengen definiert. Wir interessieren uns hier aber für Funktionen und wollen zeigen, dass es Funktionen gibt, die nicht berechenbar sind. Wir gehen im Prinzip genauso vor, wie Cantor das in seinem zweiten Diagonalisierungsbeweis getan hat. Im Beitrag über Entscheidbarkeit bekommt Ihr einen Einblick über diese Beweismethode am Beispiel der Mächtigkeit von reellen und natürlichen Zahlen.
Aber wollen wir den Beweis aus dem Skript mal Schritt für Schritt durchgehen und die Diagonalisierung nicht auf Mengen, sondern auf Funktionen anwenden. Was haben wir vor? Wir wollen zeigen, dass es nicht-berechenbare Funktionen gibt. Und so gehen wir dazu vor:
1. Zunächst definieren wir uns eine surjektive Funktion mit .Was sie genau macht, zeigen wir gleich.
2. ist das Alphabet der -Programme, während dann die Menge aller -Programme ist. Kann es über auch "Nicht--Programme geben? Sicher: irgendwelches Kauderwelsch, dass aus den Zeichen des Alphabets besteht.
3. Wir Standard-nummerieren auch mit , diese ist also bijektiv. Alle Worte über haben also eine eindeutige Nummer. Bereits jetzt haben wir das Gefühl, dass in der Menge weniger drin ist, als in der Menge . Aber langsam.
Was haben wir bis jetzt? Die Nummerierung aller Worte über unserem Alphabet mit . Hier ist das Spannende, dass selbstverständlich nicht alle Worte über ein -Programm sind (siehe Punkt 2). Es kann auch irgendwelches Kauderwelsch sein. Die Menge der -Programme ist damit eine Teilmenge der Worte über : .
Und wir haben eine "Nummerierung" der ggf. partiell einstelligen, berechenbaren Funktionen mittels .
Während wir -Programme mit der Eingabe für Registermaschinen (d.h. unsere Registerbelegung) füttern, füttern wir Funktionen einfach nur mit einem Eingabewert. Ist unser -Programm, so bezeichnet die von berechnete Zahlenfunktion.
Schon wieder diese Kompositionen. Am besten wir kümmern uns direkt um ein
Beispiel:
Diese Funktion addiert zu einem Eingabewert einfach nur eine . Das folgende -Programm tut dies ebenfalls:
i=5; WHILE DO
x=x+1;
i=i-1;
END;
Da die -Programme mittels Register- oder Turingmaschinen definiert werden, brauchen wir ein passendes Flussdiagramm :
Seht Ihr das Problem?
Das -Programm können wir nicht einfach mit unserem Funktions-Eingabeparameter , füttern, sondern brauchen eine Registerbelegung . Was tun? Unsere Eingabecodierung bemühen, die wir bereits kennen. Wir definieren:
(nicht vergessen, das 1. Register bleibt leer, da es unser Ausgaberegister ist).
Soweit so gut. Wir starten unser -Programm nun mit und bekommen als Ausgabe . Auch hier ist die Ausgabe des Flussdiagramms nicht der Ausgabewert, den wir bei der Funktion erwarten!
Ihr ahnt es sicherlich schon: wir brauchen eine Ausgabecodierung und definieren:
Für uns ist also nur das 1. Register spannend.
Und wenn wir uns die Definition von (damit wird die von berechnete Funktion bezeichnet) vor Augen führen, erschließt sich auch direkt unser . Lassen wir es mal mit laufen:
Done!
Nennen wir also die von berechnete, einstellige Zahlenfunktion.
Für unser Vorgaben brauchen wir noch eins: , unsere Nullfunktion. Egal, was wir da rein werfen, wir bekommen immer eine heraus: für alle .
Jetzt sind wir gerüstet um für unser Vorhaben zu definieren:
Ist ein eine Nummer eines legitimen -Programms, d.h. es gilt , so berechnet dieses -Programm natürlich auch etwas: irgendeine Funktion aus . Ihre Ausgabe ist (wie wir oben gesehen haben) ja genau . Und das ist dann unser .
Es kann aber auch Nummern geben, die nicht zu einem -Programm gehören (unser oben genanntes Kauderwelsch). Da Kauderwelsch nichts berechnen kann, haben wir auch keine Ausgabe. Wir brauchen aber für unseren Beweis in jedem Fall eine und definieren in diesem Fall einfach, dass wir mit unserer Nullfunktion eine bekommen.
Durch die Surjektivität von hat jede Funktion aus eine zugehörige Zahl und es müsste also auch für die folgende Funktion eine Zahl geben:
Was ist ? Ganz einfach: ist die von berechnete, einstellige Zahlenfunktion wenn es ein richtiges -Programm und kein Kauderwelsch ist. Damit ist einfach nur das -Programm mit der Nummer , welches als Eingabeparameter die Nummer bekommt.
Die Bedeutung erschließt sich hier am besten auch an einem
Beispiel:
Nehmen wir an, das obige -Programm hat die willkürliche Nummer . Da es ein echtes -Programm ist, gilt damit und
Und nun übergeben wir die als Parameter:
Damit ist .
Und unser wäre der obigen Definition nach .
Was würde passieren, wenn kein -Programm wäre? D.h. ?
Dann wäre der Definition nach für jedes . Und ? wäre:
.
Wie wir an dem Beispiel erkennen, ist sichergestellt, dass in jedem Fall einen anderen Funktionswert annimmt als wenn beide Funktionen mit gefüttert werden.
Dämmert es euch bereits? Was ist denn nochmal? Das ist unsere "Nummerierung" aller einstelligen, berechenbaren Funktionen aus ! In liegen sie alle drin. Und wo ist ? gehört zweifelsohne auch in die Menge aller einstelligen, berechenbaren Funktionen aus . Dann liegt es doch sicherlich auch irgendwo , oder?
Nein! ist von jeder Funktion aus durch seine Definition, dass es immer einen anderen Wert bei annimmt als verschieden, obwohl es definitiv zu gehört. Widerspruch!
Allgemein beweist man, dass Funktionen nicht berechenbar sind durch Widerspruchsbeweise. Im Skript wird dazu genau das gleiche Verfahren angewandt wie im zweiten Diagonalisierungsbeweis von Cantor: man geht von Vollständigkeit aus, zeigt, dass man noch etwas hinzufügen kann, was sich auf jeden Fall von allen anderen Einträgen unterscheidet (bei Diagonalisierungsbeweisen wird das Diagonalelement eines Eintrags für den neuen Eintrag abgeändert und verändert, so dass beide Einträge mindestens an der abgeänderten Stelle unterschiedlich sind) und stößt so auf einen Widerspruch.
Damit haben wir eine Funktion definiert, die offensichtlich nicht berechnet werden kann. Es folgt: .
Antwort zum Lernziel: die Angabe einer nicht berechenbaren Funktion gelingt durch Widerspruchsbeweis mittels Diagonalisierung, ähnlich dem Verfahren, das Georg Cantor bereits für sein zweites Diagonalargument angewendet hat um die Überabzählbarkeit der reellen Zahlen zu beweisen.
Dazu wird angenommen, man habe alle berechenbaren Funktionen aufgelistet und zeigt, dass es eine weitere Funktion gibt, die sich definitiv von allen anderen Funktionen unterscheidet. Woraus folgt, dass diese nicht berechenbar sein kann. Zumindest nicht wenn wir Berechenbarkeit mit dem üblichen Begriff für Berechenbarkeit, der Register- und/oder Turing-Berechenbarkeit gleichsetzen.
Das war viel Stoff. Sicherlich sind irgendwo noch Ungenauigkeiten drin oder es haben sich evtl. auch Fehler eingeschlichen. Über Hinweise in den Kommentaren würde ich mich freuen.
November 27th, 2012 00:50
Hallo !
guter blog ! Ich bin das Beispiel für die Standardnummerierung durchgegangen. Bei der Funktion sigma(abb)steht hinten noch eine 0, was laut Formel i0 entsprechen müsste, oder ? i0 kann aber laut Definition nur Werte zwischen 1...n annehmen. Bin jetzt etwas verunsichert. Gibt es dafür eine Erklärung ?
November 27th, 2012 09:32
Du hast recht, da war tatsächlich noch Fehler drin. i0=2,i1=2,i2=1. Damit wäre sigma(abb) = 1*2^2+2*2+2 = 10. Ist abgeändert.
November 28th, 2012 18:10
Vielen Dank für den tollen Blog. Im Gegensatz zum Skript ist hier alles verständlich. Hoffe es geht weiter...
Eine echte Hilfe in diesem Kurs zumal es in Berlin kein Mentoriat gibt.