Donnerstag, 22. November 2007Die Diagonalsprache
Obwohl ich im Moment echt durch den Wind bin, fühle ich irgendwie die Verpflichtung, hier auch mal wieder etwas substantielles zu schreiben, auch wenn es wahrscheinlich weniger umfangreich wird als sonst. Es geht mal wieder um das Halteproblem, heute machen wir einen weiteren (und letzten) Zwischenschritt, um danach endlich das Halteproblem anzugehen. Zunächst brauchen wir dafür die so genannte kanonische Ordnung. Das ist eine spezielle Sortierung von Bitstrings (also eine Ordnung auf {0,1}*). Dabei steht ein Wort w vor einem anderen Wort w', wenn: Anders gesagt wird zuerst nach Länge des Wortes, dann erst nach lexikographisch Ordnung sortiert. Kürzeste Worte kommen also zuerst, inklusive dem leeren Wort: Jetzt überlegen wir uns eine Matrix, wobei die Zeilen mit Turingmaschinen Die Matrix ist natürlich unendlich, denn sowohl die Anzahl der Wörter als auch die Menge der Gödelnummern hört nie auf. Jetzt kommt an eine Schnittstelle von Turingmaschine und Wort jeweils eine 0 oder eine 1, je nachdem ob die Turingmaschine das Wort akzeptiert oder nicht.
In diesem Fall würde die Turingmaschine So weit so gut, aber was soll all der Blödsinn? Stellen wir uns vor, wir hätten eine Sprache, die immer falsch rechnet. Diese wäre mal ganz sicher nicht rekursiv, wir bräuchten uns nicht einmal Gedanken machen, wann sie unendlich läuft oder nicht definiert ist. So eine Sprache ist die so genannte Diagonalsprache: Informell gesagt ist das die Sprache, die alle Wörter enthält, die die zugehörige Turingmaschine nicht akzeptiert. Die zugehörige Turingmaschine ist natürlich die, die in der korrespondierenden Zeile steht. Und damit ist D die Sprache, die alle Nullen auf der Diagonale dieser Matrix enthält. Das führt zu einem ziemlich üblen Widerspruch. Die Annahme ist, dass die Sprache rekursiv ist. Das heißt, dass es eine TM gibt, die auf allen Eingaben hält und genau D akzeptiert. Nennen wir diese TM einfach Das bedeutet, dass das zu 2)
Wie man sieht führen beide Fälle zum Widerspruch, keine Turingmaschine kann damit D akzeptieren und rechnet dabei immer richtig. Die Sprache ist damit definitiv nicht rekursiv. Das kann man benutzen um die nichtrekursivität des Halteproblems zu beweisen, das wird aber erst im nächsten Beitrag passieren.
Die Diagonalsprache Geschrieben von Turing
in Informatik um
20:14
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: diagonalsprache, entscheidbarkeitstheorie, informatik, tm, turing-maschine
Mittwoch, 24. Oktober 2007Wolframs 2,3 TM ist universell!Ich glaubs ja kaum. Stephen Wolfram hat 2004 eine Turingmaschine entworfen und 25000$ für einen Beweis ausgelobt, der die Universalität entscheidet. Heute, am gleichen Tag an dem ich zufällig meinen Beitrag über Universelle Turingmaschinen geschrieben habe kommt das rein: Wolfram's 2,3 Turing Machine Is Universal! (Beweis) Damit ist es die kleinste bekannte universelle Turingmaschine. Hier gibts technische Details.
Wolframs 2,3 TM ist universell! Geschrieben von Turing
in Informatik um
18:25
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: entscheidbarkeitstheorie, informatik, tm, turing-maschine, universelle turingmaschinen, utm
Mittwoch, 24. Oktober 2007Universelle TuringmaschinenVielleicht erinnert sich noch jemand, dass ich in grauer Vorzeit mal eine Serie über Automatentheorie gestartet habe, mit dem Ziel, irgendwann zur Entscheidbarkeitstheorie zu gelangen. Der Grund, warum ich das nie weitergeführt habe ist, dass ich Automatentheorie nicht besonders spannend finde. Also überspringe ich den langweiligen Teil, komme direkt wieder zu Turingmaschinen und schreibe vielleicht später einen Beitrag über Automatentheorie mit einem eher zusammenfassenderen Charakter. Entscheidbarkeitstheorie also. Die meisten Probleme sind ja irgendwie durch eine konkrete Fragestellung motiviert. Hier ist diese Frage, welche Funktionen entschieden werden können und welche nicht. Ich werde noch darauf kommen was das im Detail bedeutet. Erstmal führen wir eine neue Art Turingmaschine ein, die wir später brauchen. Eine Turingmaschine, nennen wir sie M, ist ja folgendermaßen definiert: Dabei ist Q die Menge der Zustände und q0 identifiziert den Startzustand. So eine gewöhnliche Turingmaschine hat einen gewaltigen Nachteil. Sie ist mit der formalen Definition bereits vollständig programmiert. Und zwar endgültig. Viel schöner und vertrauter wäre es doch, wenn eine Turingmaschine nur die "Hardware" zur Verfügung stellen würde und wir das Programm auf das Band schreiben könnten, genau wie wir das bei normalen Computern tun. Da schreiben wir das Programm auf die Festplatte (genauer gesagt in den Bootsektor) und von da aus guckt unser Computer nur, welches Programm an der richtigen Stelle der Festplatte zur Ausführung bereit liegt. Man stelle sich vor, wir würden für jeden auszuführenden Algorithmus einen neuen Prozessor kaufen und dem nur die Instanzen füttern. Ein Sortierprozessor zum Beispiel, dem wir nur Ganzzahlen zum Sortieren geben könnten, oder ein "Fülle-den-Cache-mit-Daten-Prozessor". Im echten Leben mutet das absurd an, aber so machen es klassische Turingmaschinen und für die Theorie kann man das auch tun. Aber es geht eben auch anders, und das nennt man eine "universelle Turingmaschine", kurz UTM, noch kürzer U. Diese kann ein beliebiges Programm (bzw. eine andere, normale Turingmaschine M) ausführen. Die Eingabe besteht jetzt nicht mehr aus einem Wort w, sondern aus (<M>w). Dabei ist w nach wie vor das zu bearbeitende Wort, neu ist <M>, die so genannte Gödelnummer der zu simulierenden Turingmaschine M. Man kann jede normale TM in eine lange Zahl codieren, die dann wiederum eindeutig ist. Zu jeder Gödelnummer gehört genau eine Turingmaschine. Diese Nummer wiederum gibt man dann als Eingabe an die UTM, die dann die zur Gödelnummer zugehörige TM simuliert. Diese Codierung funktioniert so:
Keine Erklärung nötig soweit? Doch? Na gut. Zuerst transferieren wir das Bandalphabet (hier oBdA {0,1,B}) in Und das ist ja schließlich unser Ziel gewesen. Nun, die universelle TM hat allerdings auch nur ein {0,1} Alphabet, deshalb notiert man einen einzelnen Zustandsübergang so: Jetzt dienen die Einsen als "Trenner" für eine Anzahl von Nullen, die mit dem ursprünglichen Zustandsübergang korrespondiert. Ein alter Übergang Wo wir uns jetzt diese ganze Arbeit gemacht haben, können wir damit endlich wieder auf die Gödelnummer zurück kommen. Die sieht jetzt nämlich so aus: 111 code(1) 11 code(2) 11 ... 11 code(n-1) 11 code(n) 111 Drei Einsen markieren also Start und Ende der Gödelnummer, zwei Einsen trennen zwei Codierungen für die Übergänge. Das Ziel ist erreicht, die Turingmaschine wird in einer langen, langen Nummer notiert, die offensichtlich auch wieder in die entsprechende Maschine zurück rechnen lässt. Wenn wir jetzt eine solche Gödelnummer, zusammen mit dem zu entscheidenden Wort an die UTM übergeben, kann diese Schritt für Schritt die Gödelnummer lesen, den neuen Zustand (und damit die neue Position in der Gödelnummer) berechnen und am Ende entscheiden, ob das Wort akzeptiert wird oder nicht. Wie das genau funktioniert wollt ihr nicht wissen, die Gödelnummerkonstruktion war ja schon etwas unheimlich. Nur so viel: Man kann Turingmaschinen auch mit mehreren Speicherbändern definieren. Davon nehmen wir uns in diesem Fall drei, schreiben die zu simulierende Gödelnummer auf das erste, das Wort auf das zweite und auf das dritte kommt der aktuelle Zustand der zu simulierenden TM. Dann wird die Programmierung der UTM zwar weniger hässlich, aber nicht viel. Bleibt die Frage nach der Rechenzeit. Wenn man sich die Rechenoperationen der UTM allerdings genau anschaut, wird schnell klar, dass die aufwändigste Operation die Suche nach der neuen Position in der Gödelnummer ist. Die UTM ist damit nur konstant langsamer als die ursprüngliche TM, hier droht also keine exponentielle Gefahr, außer die ursprüngliche TM war eh schon exponentiell langsam. So weit, so gut. Wir haben gesehen, dass man eine TM auch als lange Nummer schreiben kann. Außerdem gibt es offensichtliche eine universelle Turingmaschine, die mit dieser Nummer und dem zu entscheidenden Wort diese TM simulieren kann. Benutzen kann man das für... ääh... eigentlich kann man das nicht benutzen. Man braucht es lediglich später für einen wichtigen Beweis. Ist theoretische Informatik nicht schön? Wer hier aber dringend eine "Auflösung" braucht, der kann sich ja damit behelfen, dass die UTM offenbar eine praxisnähere Version von Turingmaschinen darstellt, denn man kann sie (auf aufwändige Art und weise) programmieren und muss sich nicht für jeden Algorithmus eine neue Turingmaschine kaufen. Gott sei dank. Update: Übrigens..
Universelle Turingmaschinen Geschrieben von Turing
in Informatik um
07:49
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: entscheidbarkeitstheorie, halteproblem, informatik, tm, turing-maschine, universelle turingmaschinen, utm
Dienstag, 29. Mai 2007NP VollständigkeitEigentlich hatte ich das P vs. NP Problem bereits abgeschlossen, aber es gibt da so eine Sache, die gehört zum Thema einfach dazu. Außerdem ist es eine großartige Sache um damit auf Cocktailpartys Wissen raushängen zu lassen. Also, wir hatten ja festgestellt, dass Probleme aus NP in polynomieller Zeit auf nichtdeterministischen Turingmaschinen entschieden werden können. Die P vs. NP Frage ist jetzt, ob die Problemklassen P und NP gleich sind oder nicht. Essentiell heißt das, dass wir nicht wissen, ob es für heutzutage praktisch nicht effizient lösbare Probleme wirklich keinen effizienten Algorithmus gibt, oder ob wir ihn nur einfach noch nicht gefunden haben. Nun ist es ziemlich schwierig, untere Schranken zu finden. Ich nehme da immer gerne das Beispiel mit der Orangenkiste. Man stelle sich vor, man will möglichst effizient Orangen in eine Kiste packen. Dabei kommt es natürlich zu Luft zwischen den einzelnen Kugeln. Was ist die optimale Packstrategie? Einfach zufällig reinwerfen, die Orangen wie Blöcke übereinander stapeln oder die Orangen leicht versetzt anordnen, so dass sie gegenseitig die Hohlräume füllen? Intuitiv würden wir natürlich die letztere Möglichkeit wählen, aber können wir denn sicher sein, dass nicht in 2000 Jahren irgendein schlauer Mensch daher kommt und eine revolutionäre Idee hat? Hierzu braucht man untere Schranken, man will mathematisch beweisen, dass es kein besseres Verfahren geben kann. Das ist natürlich eine ganze Ecke schwieriger, denn man muss ja auch alle Fälle ausschließen können, die man noch nicht kennt. Das ist auch im Grunde das Problem bei P vs. NP. Beide Komplexitätsklassen beinhalten eine Menge Probleme, aber wir können nicht erwarten, wirklich alle Probleme bereits identifiziert zu haben. Wie können wir also z.B. P=NP behaupten, wenn wir vielleicht morgen ein Problem entdecken, das in NP aber nicht in P ist? Anders herum: Wir können auch nicht einfach P!=NP sagen wenn wir ein Problem haben, das in NP, aber nicht in P ist. Es könnte ja einen Algorithmus geben, den wir nur noch nicht entdeckt haben. Der Ausweg sind so genannte Reduktionen. Wenn man Problem A auf Problem B reduziert, bedeutet das, dass man die Eingabe für Problem A so umbasteln kann, dass man sie in einen Algorithmus für Problem B füttern kann, der das Problem löst und dabei die Antwort für A liefert. Ein Beispiel hilft wie immer: Problem A ist "Ist die Zahl x gerade?". Problem B ist "Ist x mod 2=1?". Nun, für uns mit unserer menschlichen Intuition sehen die Probleme gleich aus, denn eine gerade Zahl modulo 2 ist eben immer null. Aber unsere Intuition macht nichts anderes als eine Reduktion. Wenn wir Problem A lösen wollen, rechnen wir eigentlich x mod 2 und entscheiden Aufgrund dieser Rechnung (des Problems B!) das Problem A. Und damit (und hier kommt der Knackpunkt), ist das Problem A in der gleichen Zeit entscheidbar wie B. Wenn B einen O(n) Algorithmus hat, dann ist auch A in dieser Zeit entscheidbar. Nicht für alle Probleme allerdings ist das so offensichtlich wie hier, es gibt teilweise die abenteuerlichsten Reduktionen. Wer hätte z.B. gedacht dass Tetris komplexitätstechnisch so schwer ist, wie die optimale Anordnung von Sicherheitskameras zu finden? Zurück zu den unteren Schranken. Sicher wäre es doch äußerst praktisch, wenn man sagen könnte, dass ein Problem das schwerste aus NP ist. Dann könnte wir nämlich sagen, dass wir nur noch einen P-Algorithmus für dieses schwerste Problem finden müssten. Wenn sich dieses allerschwerste Problem nämlich effizient lösen ließe, müssten einfachere Probleme aus NP ja wohl auch effizient lösbar sein. Und interessanterweise hat Stephen A. Cook bewiesen, dass es ein Problem gibt, das das schwerste in NP ist. Das ist natürlich überraschend, denn auch hier muss man ja über potentiell noch nicht entdeckte Probleme argumentieren, trotzdem schafft dieser großartige Beweis genau das. Wie immer reiße ich die Beweisidee nur kurz an, denn die Details dürften nur sehr wenige interessieren. Wer näheres Wissen will schreibt mir eine Mail oder kauft sich ein Buch über theoretische Informatik ;) Das schwerste Problem aus NP heisst "SAT" und hat nichts mit deutschen Fernsehsendern zu tun. Das Kürzel steht viel mehr für "satisfiability". Stellen wir uns eine Klausel aus boolschen Variablen vor. "x1" wäre so eine Klausel mit nur einer Variablen. x1 AND x2 wäre eine andere, auch (x1 AND x3) OR (x5 AND x1 AND NOT(x3)) ist so eine. Die Frage die das SAT-Problem stellt ist: Ist diese Klausel erfüllbar? D.h. gibt es eine Belegung von Variablen, wo die ganze Klausel "true" wird? x1 AND NOT(x1) zum Beispiel ist trivialerweise nicht erfüllbar. Es gibt nur eine Variable, und wenn diese 1 wäre, wäre der NOT(..) Teil nicht mehr erfüllbar und umgekehrt. Dieses Problem ist aus NP, wir kennen keine bessere Idee als "Belegungen ausprobieren". Im schlechtesten Fall müssen wir deshalb alle möglichen Belegungen ausprobieren und das sind exponentiell viele. Deshalb ist es auf TMs nicht effizient lösbar. Warum ist SAT jetzt das schwerste Problem im NP? Ganz einfach, Turingmaschinen lassen sich auf trickreiche Weise in Boolschen Ausdrücken codieren. Dabei stellt man durch allerlei Kniffe sicher, dass eine sehr lange Klausel entsteht, die genau und ausschließlich dann erfüllbar ist, wenn die Turingmaschine terminiert und ein Ergebnis liefert. Dann löst man diese Klausel auf und sieht: Wenn die Klausel erfüllbar ist, dann liefert die codierte TM "true", sonst "false". Und diese Idee ist geradezu genial, denn wer würde schon darauf kommen, ein so umfangreiches Modell wie eine TM in eine lange boolsche Formel umzusetzen um das Ergebnis der SAT Berechnung als Ergebnis der TM zu nehmen? Aber warum ist damit SAT das schwerste Problem aus NP? Nun, man stelle sich ein schwereres Problem als SAT vor, so ein richtig scheiße schweres Problem. Der Michael Moore unter den Problemen. Nun könnte man doch einfach die entsprechende TM in eine Klausel umbasteln (und der Satz von Cook stellt sicher dass das in poynomieller Zeit passiert). Wenn man diese Klausel hat, kann man sie in den SAT Problemlöser füttern, der dann das Ergebnis berechnet. D.h. also, dass jedes noch so schweres NP-Problem nicht schwerer zu lösen sein kann als SAT. Und das ist genial, denn wir haben damit das schwerste Problem aus NP identifiziert. Und die Implikationen sind enorm, denn jetzt können wir die oben angesprochene Reduktion anwenden und wiederum SAT-Eingaben in Eingaben von anderen Problemen umbasteln. Z.B. gibt es ein Problem, das DHC heisst. Wenn wir ein DHC-Probleminstanz so bauen können, dass ein DHC-Algorithmus genau dann "wahr" entscheidet, wenn die Klausel vom SAT "wahr" entscheiden würde, könnten wir auch DHC als "schwerstes" Problem identifizieren. Nun, schwerer als SAT kann es aber auch nicht sein, also müssen beide Probleme gleich schwer sein. Solche Probleme heißen NP-Vollständig. Sie gehören einer Unterklasse von NP an, die die schwersten Probleme aus NP umfasst. Tausende Probleme sind NP Vollständig und wenn man auch nur für ein einiziges von diesen einen P-Algorithmus finden würde, hätte man automatisch P=NP bewiesen. Denn wenn ein schwerstes Problem aus NP effizient lösbar wäre, wären es auch alle einfacheren. Der Fakt allerdings, dass für kein einziges dieser tausenden Probleme ein guter Algorithmus existiert, lässt wenig Hoffnung übrig, dass es einen solchen gibt
NP Vollständigkeit Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
20:27
Kommentare (4) Trackbacks (0) Tags für diesen Artikel: algorithmus, determinismus, informatik, komplexitã¤t, komplexitã¤tsklasse, laufzeit, millenium-probleme, nichtdeterminismus, np, p, p vs. np, tm, turing-maschine
Donnerstag, 3. Mai 2007Nichtdeterminismus und NPHeute ist es soweit, die Serie über P vs. NP kommt zum Abschluss. Dieser letzte Eintrag könnte noch einmal etwas verzwickt werden, aber wer bis hierhin durchgehalten hat, wird den letzten Schritt auch noch schaffen ;) Wir hatten ja Turingmaschinen besprochen und dabei implizit festgestellt, dass diese deterministisch arbeiten. Das heißt, für eine bestimmte Eingabe werden immer die gleichen Arbeitsschritte erledigt, das Verhalten ist damit perfekt vorhersagbar. Dieses Prinzip ist übrigens universell anwendbar. In der Tat ist die Frage nach Determinismus in der Natur noch weitestgehend unbeantwortet. Die ganzen Atome und Elektronen die um uns herum schwirren - sind die alle nur vom vorherigen Zustand abhängig? Wenn mich ein Atom trifft, tut es das dann nur weil es vorher mit einem anderen zusammen gestoßen ist? Wenn ja, war dieses Zusammenstoßen nicht aus einem vorherigen Zustand berechenbar? Ultimativ, ist seit Beginn des Universums nur ein Zustand nach dem nächsten passiert, und müsste damit streng formal aus einem derzeitigen Zustand der Ursprungszustand berechenbar sein? Ich weiß es nicht, aber diese Modellvorstellung nennt man eben "Determinismus". Was ist aber mit den ebenfalls besprochenen randomisierten Turingmaschinen? Mal abgesehen davon, dass es in einem deterministischen Natur eh keinen echten Zufall gäbe. Nun ja, randomisierte Turingmaschinen sind irgendwie nicht deterministisch, denn die Folge von Rechenschritten hängt ja nicht nur von der Eingabe ab, sondern auch von all den Zufallsbits. Aber bevor wir Randomisierung und Nichtdeterminismus vergleichen, müssten wir vielleicht erst kurz besprechen was letzteres in der Informatik bedeutet. Eins vorweg: Nichtdeterministische Turingmaschinen ("NTM") sind in der Praxis unrealistisch. Nie wird jemand eine NTM wirklich bauen können. Warum sie trotzdem relevant ist, wird erst später deutlich, also akzeptiert diesen Fakt erst mal. Stellen wir uns also folgendes vor: Wir suchen eine TM die "wahr" ausgibt, falls entweder "0011" oder "0110" als Eingabe kommt. Ein deterministischer Algorithmus säge so aus:
Hier sieht man alle möglichen Eingaben. Die beiden grün markierten Wege symbolisieren die beiden zu akzeptierenden Eingaben. Wie man außerdem erkennt gibt es insgesamt 16 Wege. Das sind Normalerweise sehen Probleme allerdings nicht so aus wie das obige. Normalerweise fragt man sowas wie "gibt es überhaupt irgendeinen Weg etwas zu tun?". Gibt eine eine TSP-Rundreise mit Kosten X? Gibt es Situationen in denen der Prozessor nicht korrekt arbeitet? Und so versteht man auch den Unterschied zwischen TM und NTM besser. Eine TM würde zu diesem Zweck alle Wege ausprobieren und "wahr" ausgeben, falls z.B. eine fehlerhafte Prozessorkonfiguration gefunden wurde. Das dauert nur leider im allgemeinen exponentiell lang, im Zweifelsfall müssen alle Wege ausprobiert werden. Eine NTM hingegen kann wie gesagt "raten". Wenn es auch nur einen Weg gibt wo die Eingabe akzeptiert wird, so wählt die NTM automatisch diesen Weg. Sollte es mehr als einen möglichen Weg geben, wählt die NTM irgendeinen davon. Also Beispiel: Wenn eine TSP-Rundreise mit Kosten 20 gesucht wird, "rät" die NTM immer den richtigen Rechnungsschritt, damit man am Ende bei "Kosten 20" raus kommt. Sollte es schlicht nicht möglich sein Kosten 20 zu erreichen, wird das auch erkannt und die NTM gibt "falsch" aus. Die TM hingegen würde im schlechtesten Fall alle möglichen (exponentiell viele) Wege ausprobieren und dafür eine Ewigkeit brauchen. Schauen wir uns das obige Bild nochmal genauer an: Wir könnten ja auch einfach sagen, dass die Wege mit den Nullen und Einsen jeweils Zufallsbits darstellen und damit im Grunde auch eine randomisierte TM für dieses Bild passen könnte. In der Tat ist es dank probability amplification (siehe letzter Beitrag) genau so: Eine NTM und eine RTM mit Fehlerwahrscheinlichkeit <1 sind komplexitätstechnisch gleich. Und damit können wir endlich (tadaa!) die Komplexitätsklasse NP definieren: In dieser Klasse sind alle Probleme, die von einer NTM in polynomieller Zeit entschieden werden können. Klar ist natürlich, dass P eine Untermenge von NP ist. Alles was von einer TM entschieden werden kann, kann trivialerweise auch von einem NTM entschieden werden. Aber ist das umgekehrt auch der Fall? Kann eine TM irgendwie besser werden als "alle Wege ausprobieren"? Genau das ist die große Frage, die 1 Mio$ wert ist. Dafür reicht es natürlich nicht, für irgendein Problem aus NP einen Algorithmus aus P zu finden, denn es kann ja schwerere Probleme in NP geben, die keinen Algorithmus in P haben. Damit wäre dann P!=NP (!= bedeutet übrigens ungleich"). Zum Glück ist es den Theoretikern gelungen, schwerste Probleme aus NP zu finden. Es kann keine schwereren Probleme als diese geben. D.h. wenn es für eines dieser schwersten Probleme einen Algorithmus aus P gibt, dann ist P=NP. Das nennt man Satz von Cook und könnte durchaus noch Stoff für einen weiteren Beitrag sein. Aber um die eigentliche P vs. NP Frage zu verstehen ist das nicht notwendig, eigentlich ist diese Serie also hier abgeschlossen. Trotzdem will ich noch einmal über die Konsequenzen dieser großen Frage referieren. Zum Beispiel ist die Faktorisierung von Primzahlen ein Problem aus NP, das (vermutlich) keinen Algorithmus in P hat. Nun basieren viele wichtige Verschlüsselungsverfahren darauf, dass es keine solchen Algorithmen gibt. Wer sofort alle Faktoren einer Primzahl errechnen könnte, bräuchte nicht mehr hunderte Jahre um so einen Schlüssel zu knacken. Aber auch viele wichtige Algorithmen aus der Bioinformatik sind aus NP und brauchen deshalb sehr lange. Wäre P != NP, bräuchten wir keine Hoffnung auf schnellere Lösung der Probleme machen. Generell würde P != NP bedeuten, dass es für viele wichtige Probleme keine schnellere Lösungsmethode als "alles ausprobieren" gibt. Und jetzt die schlechte Nachricht: Wahrscheinlich ist P ungleich NP. Es sind tausende schwerste Probleme aus NP bekannt, aber wir kennen keinen einzigen Algorithmus aus P dafür. Generationen von Informatikern haben danach gesucht, aber alle sind gescheitert. Natürlich ist das kein Beweis, aber gesunder Menschenverstand sagt einem, dass es vermutlich einen guten Grund dafür gibt..
Nichtdeterminismus und NP Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
17:01
Kommentare (2) Trackbacks (0) Tags für diesen Artikel: algorithmus, determinismus, fehlerwahrscheinlichkeit, komplexität, komplexitätsklasse, millenium-probleme, nichtdeterminismus, np, p vs. np, rp, tm, turing-maschine
Donnerstag, 12. April 2007Einseitige Fehler, RP und co-RPIm letzten Beitrag hatten wir ja ZPP besprochen und dabei festgestellt, dass ZPP-Algorithmen keine Fehler machen, dafür aber "?" ausgeben können. Deshalb kann man ZPP-Algorithmen einfach öfter aufrufen und hoffen, dass irgendwann irgendein Ergebnis außer "?" kommt. Dann können wir nämlich sicher sein, dass das Ergebnis richtig ist. Gut, aber es gibt auch andere Fehlerarten. Wenn ein Algorithmus auf einer randomisierten TM in polynomieller Zeit ausgeführt werden kann und der Algorithmus einen einseitigen Fehler machen kann, ordnen wir ihn der Komplexitätsklasse RP bzw. co-RP zu. Bevor ich erkläre was ein einseitiger Fehler ist, muss ich noch kurz über Entscheidungsprobleme sprechen. Man kann ja Algorithmen schreiben, die verschiedene Fragen stellen. Zum Beispiel könnte man ein großes Integer Array als Eingabe nehmen und fragen "Was sind die größten drei Elemente daraus?". Das wäre ein Optimierungsproblem, denn man gibt drei "optimale" Elemente als Ergebnis aus. Eine andere Frage wäre "Was ist die Summe der größten drei Elemente?". Das wiederum ist ein Evaluationsproblem, hier wird eine Zahl ausgegeben, nicht die Elemente selber. Und dann gibt es noch die Fragestellung "Gibt es drei Elemente, deren Summe genau 42 ist?" Hier hätten wir ein Entscheidungsproblem, es wird nur 0 oder 1 ausgegeben. Aber wie schwer sind die Problemvarianten aus komplexitätstheoretischer Sicht? Die Antwort ist "meistens sind sie gleich schwer". Leider eben nur meistens, aber immerhin. Oft kann man in etwa folgeden Argumentationsgang verwenden: Man löst das Evaluationsproblem, bekommt damit eine Zahl heraus, z.B. 50 und kann damit auch das Entscheidungsproblem lösen. Alle Beziehungen jetzt durch zu exerzieren wäre anstrengend und langweilig, also glaubt mir einfach: Normalereweise sind alle Varianten gleich schwer. Und das bedeutet eigentlich auch nur, dass alle polynomiell schwer sind. Im weiteren Verlauf beschränke ich mich deshalb auf Entscheidungsprobleme, denn die jetzt kommenden Komplexitätsklassen machen nur so Sinn. Und damit ultimativ auch die P vs. NP-Frage. Zurück zum einseitigen Fehler. Sagen wir, wir hätten einen Algorithmus der für alle ungeraden Zahlen "1" ausgibt und für alle geraden Zahlen "0". Der Algorithmus könnte zwei Fehler machen, er könnte fälschlicherwiese bei ungeraden Zahlen "0" ausgeben oder bei geraden Zahlen eine "1". Der eine Fehler ist gut und der andere ist schlecht, was an einem anderen Beispiel gut deutlich wird. Wir haben einen Algorithmus, der Bierflaschen auf Verunreinigungen überprüft. Schlecht wäre, wenn der Algorithmus "Flasche sauber" (1) ausgibt, wenn in Wirklichkeit eine 0 gefragt wäre. Gut wäre, wenn der Algorithmus "Flasche dreckig" (0) ausgibt, obwohl die Flasche vielleicht doch sauber ist. Ich persönlich habe lieber einen kleinen Produktionsverschleiß als alte Heroinspritzen in der Flasche. Also, die erste Art Fehler (die gute Art) ordnet man der Komplexitätsklasse RP zu, die zweite Art nennt man co-RP. Und natürlich kann man auch hier eine Wahrscheinlichkeit angeben, dass ein Fehler auftritt, streng genommen heißen die Klassen also wieder RP(f(n)) bzw co-RP(f(n)). Der probability amplification Trick funktioniert jetzt etwas anders. Wenn der Algorithmus aus RP ist, kann man mit Sicherheit sagen dass eine "1" richtig ist. Wenn wir also jemals eine 1 bekommen, akzeptieren wir die Eingabe als richtig. Wenn es nur Nullen gibt (bei einer Fehlerwahrscheinlichkeit von z.B. 1/2) ist die Wahrscheinlichkeit, dass es immer ein Fehler war genau (1/2)n. Auch hier greift das Prinzip wie bei ZPP: wenn die Fehlerwahrscheinlichkeit <= 1/2 ist, dann kann man die Gesamtfehlerwahrscheinlichkeit durch mehrfaches ausführen exponentiell klein machen. Wir kürzen also auch hier wieder ab: RP(1/2)=RP. Außerdem ist RP(1)=RP*. Im Übrigen ist ZPP eine Teilmenge von RP und von co-RP, denn man könnte einfach einen ZPP-Algorithmus nehmen und jedesmal wenn ein ? ausgegeben wird, einfach irgendwas ausgeben. Damit hätte man einen einseitigen Fehler gemacht und hätte nach Definition einen (co-)RP-Algorithmus. Und damit ist eigentlich erstmal alles gesagt. Wir haben zwei neue Arten Fehler kennengelernt und gesehen, dass auch hier 1/2 als Grenze für die Fehlerwahrscheinlichkeit funktioniert. Im Gegensatz zu ZPP* wird allerdings RP* sehr wichtig, denn überraschenderweise ist RP*=NP. Deshalb formuliere ich RP* zum Schluss nochmal aus: RP* ist die Klasse der Algorithmen, die auf einer randomisierten TM in polynomieller Zeit ausgeführt werden können und dessen Fehlerwahrscheinlichkeit nicht beschränkt ist. Da stellt sich natürlich die Frage, wie wir entscheiden sollen ob wir einen RP(1/4) oder einen RP(3/4) Algorithmus vor uns haben. Wenn wir diesen oft ausführen würden, würde sich entweder der Fehler verstärken oder egalisieren. Nun, diese praktische irrelevanz zieht sich leider auch durch NP durch, aber dazu im nächsten Beitrag mehr.
Einseitige Fehler, RP und co-RP Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
10:59
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: algorithmus, cp-RP, fehlerwahrscheinlichkeit, komplexität, komplexitätsklasse, millenium-probleme, p vs. np, randomisierung, RP, tm, turing-maschine, zpp
Sonntag, 8. April 2007Randomisierung und ZPPIm Gegensatz zu den bisher betrachteten deterministischen Algorithmen gibt es die so genannten randomisierten Algorithmen. Dazu wird ein Zufallsgenerator benutzt und der weiter Verlauf des Algorithmus von diesem abhängig gemacht. In der Realität gibt es natürlich Zufallsgeneratoren beliebiger Qualität, aber in der Theorie beschränken wir uns mal wieder auf das kleinste Vorstellbare: Unser Zufallgsgenerator produziert perfekt zufällige Bits. In jedem Rechenschritt genau eins.
Aber vielleicht ist dem ein oder anderen noch nicht einsichtig, warum wir eigentlich randomisierte Algorithmen brauchen, schließlich produzieren sie Fehlerquellen und nehmen uns doch eine große Portion der Sicherheit, dass der Algorithmus das macht was er soll. Am Besten hilft auch hier ein Beispiel. Wenn beim Quicksort-Algorithmus immer deterministisch das letzte Element als Pivot-Element nimmt und die Eingabe vorsortiert ist, ist die Laufzeit O(n2). Und das wo doch gerade Quicksort normalerweise O(n*log(n)) macht. Da der Speziallfall der sortierten Liste nicht gerade selten vorkommt, ist das Verhalten natürlich sehr ungünstig. Und einfach das erste Element als Pivot zu nehmen verschiebt das Problem auch nur. Die Lösung ist, einfach ein zufälliges Element zu wählen. Auch da kann es natürlich ganz blöd laufen und O(n2) brauchen, aber die Wahrscheinlichkeit ist doch sehr gering, denn dazu müsste immer zufällig genau das Element gewählt werden, das im unsortierten Teil am größten ist. Hier trägt randomisierung also dazu bei, dass es in den meisten Fällen eine gute durschnittliche Laufzeit gibt. Ein anderes prominentes Beispiel ist der Primzahltest von Solovay-Strassen. Hier wird am Anfang eine zufällige Zahl gewählt und die zu prüfende Zahl damit "bearbeitet". Die genauen Schritte wären hier jetzt zu schwierig, aber auch hier ist es praktisch unmöglich, eine "fest einprogrammierte" Zahl zu finden die man benutzen kann, denn es würde Primzahlen geben, bei denen der Algorithmus immer "dies ist keine Primzahl" sagen würde. Der Algorithmus würde ohne Randomisierung also nichtmal korrekt funktionieren. Wir sollten uns also darüber einig sein, dass Algorithmen mit einem Zufallselement sinnvoll sind. Wir erweitern unsere Turingmaschine also dahingehend, dass die Zustandsübergangsfunktion nicht nur davon abhängt in welchem Zustand wir sind und welches Zeichen wir lesen, es wird jetzt auch noch in jedem Rechenschritt ein Zufallsbit generiert. Damit verdoppelt sich zwar die Zahl der Übergänge, aber dass Turingmaschinen in der Praxis eh untauglich sind wissen wir ja auch. Jetzt habe ich ja im letzten Beitrag mit den Komplexitätsklassen sozusagen die letzte Abstraktionsstufe erreicht und da passt es natürlich nicht, dass wir wieder in die Tiefen der Turingmaschine gehen. Deshalb gibt es natürlich auch randomisierte Komplexitätsklassen und eine davon besprechen wir jetzt noch kurz, nur um zu sehen wie man Beziehungen zwischen den Klassen herstellt. Wir definieren: Die Komplexitätsklasse ZPP(f(n)) umfasst alle Algorithmen, die auf einer randomisierten TM ausgeführt werden können und wo die Fehlerwahrscheinlichkeit durch f(n) beschränkt ist. Algorithmen in ZPP können entweder das richtige Ergebnis oder "?" ausgeben. Das klingt jetzt vielleicht etwas hölzern, eigentlich geht es nur darum, dass ZPP-Algorithmen vielleicht nicht zu einem Ergebnis kommen und dann "keine Ahnung" ausgeben. Wenn es aber ein Ergebnis gibt, ist es sicher richtig. Die Wahrscheinlichkeit dass ein ? ausgegeben wird, ist dabei durch f(n) angegeben und damit gibt es im Prinzip unendlich viele ZPP-Klassen. Es gibt ZPP(1/4), ZPP(1), ZPP(1/2) usw. Dabei ist ZPP(1/4) natürlich eine Untermenge von ZPP(1/2), denn wir hatten ja gesagt, dass die Fehlerwahrscheinlichkeit durch f(n) beschränkt ist, es geht also darum, dass f(n) ausdrückt was der schlechteste mögliche Fall ist. Denken wir kurz darüber nach, was ist denn ZPP(0)? Ein randomisierter Algorithmus, der nie einen Fehler macht, also immer das richtige Ergebnis liefert. Klingt nach der Definition von P. Damit ist P=ZPP(0) und damit eine Untermenge von ZPP(f(n)). Was ist ZPP(1)? Komplett sinnlos, denn diese Algorithmen geben immer "?" aus. Wenn man jetzt noch weiter nachdenken wollte, könnte man darauf kommen, dass man einen ZPP(1/4)-Algorithmus ja auch einfach zweimal laufen lassen kann, dann wäre die Wahrscheinlichkeit für ein ? nur noch 1/16. Was würde uns denn daran hindern, den Algorithmus einfach so oft auszuführen bis wir kein ? mehr bekommen? Doch nur die exponentielle Grenze, denn irgendwann müssen wir den Algorithmus im Wesentlichen exponentiell oft laufen lassen um ein Ergebnis erwarten zu können. Das ist der Fall wenn f(n) > 1/2, also können wir mit dieser Technik sagen, dass eigentlich alls Algorithmen mit ZPP(1/2) gleich sind. ZPP(1/4), ZPP(1/3) und ZPP(1/2) unterscheiden sich nur dadurch, dass man hier und da eventuell mehrere Durchläufe braucht. Da aber die Laufzeit je Durchlauf polynomiell ist, bleibt die Laufzeit insgesamt auch polynomiell. Nur wenn wir eine exponentielle Anzahl von Durchläufen brauchen, kommen wir insgesamt auf exponentielle Laufzeit (das ist dann bei f(n)>1/2 der Fall). Mit diesem Wissen kürzen wir ZPP(1/2)=ZPP ab und erkennen P als kleine Unterklasse von ZPP. ZPP mit Fehlerwahrscheinlichkeit >1/2 nennt man ZPP*, aber diese Klasse ist relativ uninteressant. Im nächsten Eintrag wird es dann um andere Komplexitätsklassen gehen, die tatsächlich Fehler machen können (im Sinne von: Das Ergebnis kann falsch sein). Und wenn wir diese Klassen kennen und die Verbindung zu Nichtdeterminismus hergestellt haben, können wir die P vs. NP-Frage endlich verstehen.
Noch ein letzter Satz, mit dem man auf Partys wunderbar angeben kann: Diese Technik des "mehrfachen Ausführens" nennt man probability amplification. Wenn man das in einen Satz mit "Komplexitätstheorie", "polynomielle Laufzeit" und "randomisierte Turingmaschine" bringt, kann man sicher sein, dass man von allen anderen Partygästen bis auf weiteres gemieden wird.
Randomisierung und ZPP Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
12:56
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: algorithmus, determinismus, informatik, komplexität, komplexitätsklasse, laufzeit, millenium-probleme, p, p vs. np, randomisierung, tm, turing-maschine, zpp
Sonntag, 1. April 2007KomplexitätsklassenIch bin wieder zu Hause und begrüße erstmal alle heise-Leser. Heute geht es um Komplexitätsklassen, im speziellen um P. Die Komplexitätstheorie ist ein großer Teil der theoretischen Informatik und das Ziel ist, Probleme so zu gruppieren und in Klassen einzuteilen, so dass man die Klassen untereinander vergleichen kann. Wir hatten ja schon über Turingmaschinen gesprochen, außerdem müssten wir inzwischen den Unterschied zwischen einem Problem und einem Algorithmus kennen. Die Definition einer Komplexitätsklasse ist natürlich relativ willkürlich und ich könnte auch einfach sagen "Ich packe alle Probleme, die einen Algorithmus haben, wo die Turingmaschine eine gerade Anzahl an Schritten macht in eine Klasse und nenne sie QWERTZ." Das würde nur nicht viel Sinn machen, weil das keine wirklich relevante Eigenschaft ist. Deshalb würde QWERTZ schlicht nicht benutzt und schnell in der Versenkung verschwinden. Es gibt aber auch relevante Subklassen von P, zum Beispiel L. In L sind alle Probleme, die von einer TM geöst werden können, die einen endlichen Speicher hat (Wir erinnern uns: Eine TM hat formal unendlichen Speicher). Mit dem Begriff der Komplexitätsklassen haben wir erstmal zu Ende abstrahiert. Wir sind angefangen mit Betrachtungen von Algorithmen, der O-Notation, haben festgestellt dass man Zwecks besserer Vergleichbarkeit zu Turingmaschinen abstrahiert. Dann haben wir irgendwann nur noch zwischen polynomiellen und exponentiellen Laufzeiten unterschieden und jetzt teilen wir die Probleme auch noch in Klassen ein und argumentieren nur noch über diese Klassen und nicht mehr über einzelne Probleme. Schön, im nächsten Schritt schauen wir uns randomisierte Algorithmen an und definieren dafür einige Komplexitätsklassen. Damit nähern wir uns dann der Frage was NP ist und schließlich wird dann das P vs. NP Problem klar.
Komplexitätsklassen Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
20:03
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: algorithmus, determinismus, komplexitã¤t, komplexitã¤tsklasse, millenium-probleme, p, p vs. np, tm, turing-maschine
Donnerstag, 22. März 2007Polynomiell vs. exponentiellIch hatte ja schon über die O-Notation gesprochen und schon angedeutet, dass wir nur im wesentlichen polynomielle und exponentielle Laufzeiten auseinander halten wollen. Die Grafik im betreffenden Post war ja schon ganz anschaulich, aber ich will es doch noch ein bisschen plastischer machen um auch die praktisch veranlagten zu überzeugen. Ich habe ein paar Tests laufen lassen und habe einen kleinen, sinnlosen Algorithmus in Python geschrieben. Dieser füllt ein Array und macht nichts weiter außer ein paar überflüssigen Additionen. Für ein Array der Größe 100 braucht dieser Aber ich schweife ab. Mein Algorithmus braucht also eine Sekunde für n=100. Das bedeutet für 1003 "Schritte" braucht mein Computer eine Sekunde. Erhöhen wir mal auf n=1000, da wären wir bei runden 17 Minuten für 10003 Schritte. Das ist schon nicht mehr ganz wenig. Für n=10000 allerdings wären wir bereits bei guten 31000 Jahren. Das ist bereits utopisch für den realen Einsatz, aber wie siehts denn im Vergleich mit Für n=10 haben wir noch überschaubare 17 Sekunden, aber da hört es auch schon auf. Wir erinnern uns: beim Man zieht also die Grenze da, wo das n im Exponent steht. Das führt natürlich auch zu Ungenauigkeiten, so wäre
Polynomiell vs. exponentiell Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
20:48
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: algorithmus, determinismus, millenium-probleme, o-notation, p vs. np, turing-maschine
Freitag, 16. März 2007TuringmaschinenIm letzten Beitrag hatte ich ja erklärt, dass man Algorithmen äußerst weit abstrahiert um sie vergleichen zu können. Das lag daran, dass man bestimmte Faktoren einfach nicht einbeziehen darf, weil sonst nicht mehr Algorithmen verglichen werden würden, sondern CPU-Power oder Betriebssysteme. Wir haben das gemacht, um später überhaupt eine Argumentationsbasis zu haben. Wenn wir sowas sagen wie "Das Problem A lösen wir mit Algorithmus B in O(log(n))", dann geht das nur weil wir uns überhaupt auf die O-Notation und deren Vergleichbarkeit geeinigt haben. Jetzt liegt es natürlich nahe ein möglichst allgemeingültiges Computermodell zu entwickeln, um eben diese Vergleichbarkeit zu erreichen. Das was man üblicherweise benutzt ist die sogenannte Turingmaschine (kurz: TM). Diese wurde 1936 von Alan Turing entwickelt, was insofern bemerkenswert ist, als dass es da noch keine echten Rechner gab. Ich nehme mal die "Auflösung" vorweg: Turingmaschinen bilden genau unsere aktuellen Rechner ab, d.h. man kann Algorithmen mit akzeptablem Aufwand von einem Athlon64 zu einer Turingmaschine übertagen. Was ein akzeptabler Aufwand ist, darüber handelt der nächste Beitrag. Und dass sich keiner wirklich die Mühe macht, TM-Programme zu schreiben, soviel sei auch schon gesagt. Das ist auch nicht nötig. Wichtig ist, dass man damit eine gemeinsame Argumentationsbasis hat. Dann schauen wir uns Turingmaschinen also mal konkret an.
Aber wie berechnet die TM die Ausgabe? Dafür gibt es die Menge der Zustände Vielleicht macht ein Beispiel das etwas klarer. Sagen wir, auf dem Band steht "010011" und wir wollen alle nullen löschen. Wir sind ja im Zustand Das war jetzt kein Entscheidungsproblem, wenn man ein solches hat, wird normalerweise gefordert, dass man die Eingabe komplett löscht und eine 0 oder 1 (wahr oder falsch) an die erste Position schreibt. Im obigen Beispiel kamen wir mit einem Zustand aus, normalerweise hat man mehrere. Man kann sich z.B. leicht vorstellen, dass man zählen will, ob auf dem Band genau so viele einsen wie nullen stehen. Dann würde man z.B. eine null lesen, in Zustand Formal ist eine TM ein Tupel:
Turingmaschinen Geschrieben von Turing
in Millenium-Probleme, P vs. NP um
12:43
Kommentare (0) Trackbacks (0) Tags für diesen Artikel: determinismus, informatik, millenium-probleme, p vs. np, tm, turing-maschine
|
KategorienFeedsGetaggte Artikelööh.. informatik?
algorithmus china determinismus entscheidbarkeitstheorie fehlerwahrscheinlichkeit fernsehen filme formale sprachen games geek-zeug informatik komplexitã¤t komplexitã¤tsklasse laufzeit linux medien millenium-probleme monty hall nichtdeterminismus nicht eingã¤ngig nintendo ds np o-notation p poker p vs. np randomisierung rffc RP sco sonstiges sonstiges mathematisches spieltheorie statik technische mechanik tm turing turing-maschine universelle turingmaschinen utm videospiele wachstum wahrscheinlichkeit xkcd zpp SonstigesBlogrollSuche |
Powered by s9y - Design by Lordcoffee