M¨ achtigkeit von WHILE-Programmen
und rekursive Funktionen
Prof. Dr. Berthold V¨ocking Lehrstuhl Informatik 1 Algorithmen und Komplexit¨at
RWTH Aachen
16. November 2010
Turingmaschine (TM)
M = (Q,Σ,Γ,B,q0,¯q, δ)
. . . 0 c 0 0 B a 0 0 c 1 B . . .
Unendliches Band
Endliche Kontrolleinheit (Zust¨ande Q, Programmδ)
Registermaschine (RAM)
Programm
Befehlsz¨ahler b
Akkumulator
c(0) c(1) c(2) c(3) . . . Speicher
(unbeschr¨ankt) Befehlssatz:
LOAD, STORE, ADD, SUB, MULT, DIV,
INDLOAD, INDSTORE, INDADD, INDSUB, INDMULT, INDDIV, CLOAD, CADD, CSUB, CMULT, CDIV,
GOTO,
IF c(0) ? x THEN GOTO (wobei ? aus{=, <,≤}), END
Eingeschr¨ ankte Registermaschine
Programm
Befehlsz¨ahler b
Akkumulator
c(0) c(1) c(2) c(3) . . . c(k) Speicher
(# Register konstant) Befehlssatz:
LOAD, STORE,
ADD, SUB, DIV,
INDLOAD, INDSTORE, INDADD, INDSUB, INDDIV,
CLOAD, CADD, CSUB,
CDIV,
GOTO,
IF c(0)6= 0 THEN GOTO, END
Turing-m¨ achtige Programmiersprachen
Definition
Eine Programmiersprache wird alsTuring-m¨achtigbezeichnet, wenn jede Funktion, die durch eine TM berechnet werden kann, auch durch ein Programm in dieser Programmiersprache berechnet werden kann.
Die Programmiersprache WHILE – Syntax
Elemente eines WHILE-Programms Variablen x0 x1 x2 . . . Konstanten −1 0 1 Symbole ; := + 6=
Schl¨usselw¨orter WHILE DO END
Die Programmiersprache WHILE – Syntax
Induktive Definition – Induktionsanfang
Zuweisung
F¨ur jedesc ∈ {−1,0,1} ist die Zuweisung xi := xj +c ein WHILE-Programm.
Die Programmiersprache WHILE – Syntax
Induktive Definition – Induktionsschritte:
Hintereinanderausf¨uhrung
FallsP1 und P2 WHILE-Programme sind, dann ist auch P1;P2
ein WHILE-Programm.
WHILE-Konstrukt
FallsP ein WHILE-Programm ist, dann ist auch WHILE xi 6= 0 DOP END ein WHILE-Programm.
Die Programmiersprache WHILE – Semantik
Ein While-Programm P berechnet eine k-stellige Funktionen der Formf :Nk →N.
Die Eingabe ist in den Variablenx1, . . . ,xk enthalten.
Alle anderen Variablen werden mit 0 initialisiert.
Das Resultat eines WHILE-Programms ist die Zahl, die sich am Ende der Rechnung in der Variablex0 ergibt.
Programme der Formxi :=xj +c sind Zuweisungen des Wertes xj+c an die Variablexi (wobei 0−1 = 0).
In einem WHILE-Programm P1;P2 wird zun¨achstP1 und dann P2 ausgef¨uhrt.
Das Programm WHILExi 6= 0 DOP END hat die Bedeutung, dass P solange ausgef¨uhrt wird, bis xi den Wert 0 erreicht.
Beispiel eines WHILE-Programms
Was berechnet dieses WHILE-Programm?
WHILE x26= 0 DO x1 :=x1+ 1;
x2 :=x2−1 END;
x0 :=x1
Die Programmiersprache WHILE – M¨ achtigkeit
Satz
Die Programmiersprache WHILE ist Turing-m¨achtig.
Beweis:In einer ¨Ubungsaufgabe haben wir gezeigt, dass eine TM durch eine RAM mit konstant vielen Registern und
eingeschr¨anktem Befehlssatz
LOAD, CLOAD, STORE, CADD, CSUB, GOTO, IF c(0)6= 0 GOTO, END simuliert werden kann.
Wir m¨ussen also nur noch zeigen, dass jede Funktion, die durch eine eingeschr¨ankte RAM berechnet werden kann, auch durch ein WHILE-Programm berechnet werden kann.
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
Sei Π ein beliebiges RAM-Programm mit eingeschr¨anktem
Befehlssatz, das aus`Zeilen besteht und k Register f¨ur nat¨urliche Zahlen benutzt.
Wir speichern den Inhalt von Registerc(i), f¨ur 0≤i ≤k, in der Variablexi des WHILE-Programms.
In der Variablexk+1 speichern wir zudem den Befehlsz¨ahlerb der RAM ab.
Die Variablexk+2 verwenden wir, um eine Variable zu haben, die immer den initial gesetzen Wert 0 enth¨alt.
Die einzelnen RAM-Befehle werden nun in Form von konstant vielen Zuweisungen der Formxi :=xj+c mitc ∈ {0,1}
implementiert.
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
RAM vs. WHILE
LOAD, STORE
CLOAD, CADD, CSUB, GOTO
IF c(0)6= 0 GOTO END
xi := xj+c f¨ur c ∈ {−1,0,1}
P1;P2
WHILE xi 6= 0 DOP END Der RAM-Befehl LOAD i wird beispielsweise ersetzt durch
x0 :=xi + 0; xk+1 :=xk+1+ 1
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
RAM vs. WHILE
LOAD, STOREX CLOAD, CADD, CSUB, GOTO
IF c(0)6= 0 GOTO END
xi := xj+c f¨ur c ∈ {−1,0,1}
P1;P2
WHILE xi 6= 0 DOP END Der RAM-Befehl CLOAD i wird analog ersetzt durch
x0 :=xk+2+ 0; x0:=x0+ 1; . . .; x0:=x0+ 1;
| {z }
imal
xk+1:=xk+1+ 1
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
RAM vs. WHILE
LOAD, STOREX CLOAD, CADD, CSUB, GOTO X
IF c(0)6= 0 GOTO END
xi := xj+c f¨ur c ∈ {−1,0,1}
P1;P2
WHILE xi 6= 0 DOP END Den RAM-Befehl IFc(0)6= 0 GOTO j ersetzen wir durch das WHILE-Programm:
xk+1 :=xk+1+ 1; (b :=b+ 1)
xk+3 :=x0+ 0; (help:=c(0))
WHILE xk+36= 0 DO (whilehelp6= 0)
xk+1:=xk+2+ 0; xk+1:=xk+1+ 1;· · ·+ 1;
| {z }
j mal
(b :=j)
xk+3:=xk+2+ 0 (help:= 0)
END (end of while)
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
RAM vs. WHILE
LOAD, STOREX CLOAD, CADD, CSUB, GOTO X
IF c(0)6= 0 GOTO X END
xi := xj+c f¨ur c ∈ {−1,0,1}
P1;P2
WHILE xi 6= 0 DOP END Den RAM-Befehl END ersetzen wir durch das WHILE-Programm
xk+1 = 0
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
Jede Zeile des RAM-Programms wird nun wie oben beschrieben in ein WHILE-Programm transformiert. Das WHILE-Programm f¨ur Zeilei bezeichnen wir mit Pi.
Wir bettenPi in ein WHILE-Programm Pi0 mit der folgenden Semantik ein:
Falls xk+1 =i dann f¨uhrePi aus.
Wie kann manPi0 implementieren?
Ubung¨
Implementiere jeweils ein WHILE-Programm f¨ur die folgenden Fall- unterscheidungen.
1 Falls x` = 0 ist, f¨uhreP aus, ansonstenQ.
2 Falls xk+1 =i dann f¨uhrePi aus.
Beweis Turing-M¨ achtigkeit von WHILE-Programmen
Nun f¨ugen wir die WHILE-Programme P10, . . . ,P`0 zu einem WHILE-ProgrammP zusammen:
xk+1 := 1;
WHILE xk+16= 0 DO P10;. . .;P`0 END
P berechnet dieselbe Funktion wie Π.
Ausblick: Die Programmiersprache LOOP
Syntax
Anderung im Vergleich zu WHILE-Programmen:¨
Wir ersetzen das WHILE-Konstrukt durch ein LOOP-Konstrukt der folgenden Form:
LOOP xi DO P END , wobei die Variablexi nicht in P vorkommen darf.
Semantik
Das ProgrammP wirdxi mal hintereinander ausgef¨uhrt.
Frage
Sind LOOP-Programme Turing-m¨achtig?
Ausblick: Die Programmiersprache LOOP – M¨ achigkeit
Problem
Welche Funktionen k¨onnen durch LOOP-Programme berechnet wer- den?
Exkurs: Rekursionstheorie
Die folgenden Inhalte ¨uber primitiv rekursive und µ-rekursive Funktionen sindnicht klausurrelevant.
Wie definiert man eine Funktion?
Hilbert [1916, ¨Uber das Unendliche]:
”Die elementaren Hilfsmittel zur Bildung von Funktionen sind offenbar die Einsetzung (d.h. Ersetzung eines Argumentes durch eine neue Variable oder Funktion) und die Rekur- sion (nach dem Schema der Ableitung des Funktionswertes f¨ur n + 1 aus demjenigen f¨ur n).
Man k¨onnte meinen, daß zu diesen beiden Prozessen der Einsetzung und Rekursion noch andere elementare Definitionsmethoden hinzugenommen werden m¨ußten [...]
Es zeigt sich jedoch, daß alle solche Definitionen sich als Spezialf¨alle der Anwendung von Einsetzungen und Rekursionen darstellen lassen.“
Die Klasse der primitiv rekursiven Funktionen f : N
∗→ N
Basisfunktionen
Nullfunktionen: o(x1, . . . ,xk) = 0 Projektionen: p|i(x1, . . . ,xi, . . . ,xk) =xi Nachfolgerfunktion: s(n) =n+ 1 f¨ur n∈N Induktive Definition primitiv rekursiver Funktionen Primitiv rekursiv sind:
1 Basisfunktionen
2 Kompositionen primitiv rekursiver Funktionen
f(x1, . . . ,xk) =h(g1(x1, . . . ,xk), . . . ,gn(x1, . . . ,xk))
3 Primitive Rekursionen primitiv rekursiver Funktionen f(0,x1, . . . ,xk) =g(x1, . . . ,xk)
f(n+ 1,x1, . . . ,xk) =h(f(n,x1, . . . ,xk),n,x1, . . . ,xk)
Die Klasse der primitiv rekursiven Funktionen f : N
∗→ N
Beispiel: Additionadd :N2→N
add(0,x) =x
add(n+ 1,x) =s(p|1(add(n,x),n,x)) bzw. s(add(n,x)) Induktive Definition primitiv rekursiver Funktionen
Primitiv rekursiv sind:
1 Basisfunktionen (Null, Projektionen, Nachfolgerfunktion)
2 Kompositionen primitiv rekursiver Funktionen
f(x1, . . . ,xk) =h(g1(x1, . . . ,xk), . . . ,gn(x1, . . . ,xk))
3 Primitive Rekursionen primitiv rekursiver Funktionen f(0,x1, . . . ,xk) =g(x1, . . . ,xk)
f(n+ 1,x1, . . . ,xk) =h(f(n,x1, . . . ,xk),n,x1, . . . ,xk)
Beispiele primitiv rekursiver Funktionen
Multiplikationmult :N2 →N
mult(0,x) = 0
mult(n+ 1,x) =add(mult(n,x),x) Subtraktionsub:N2→N
sub(x,0) =x
sub(x,y+ 1) =u(sub(x,y)) wobeiu durchu(0) = 0 und u(n+ 1) =n definiert ist.
Analog: Division, Exponentiation, Fakult¨at, Binomialkoeffizient, Cantorsche Paarungsfunktion,. . .
Sind alle Funktionen primitiv rekursiv?
M¨ achtigkeit primitiv rekursiver Funktionen
Vermutung von Hilbert (1926):Die Klasse der primitiv rekursiven Funktionen stimmt mit der Klasse der rekursiven (berechenbaren) Funktionen ¨uberein.
Ackermann (1929): Diese Vermutung stimmt nicht!
Folgende Funktion ist nicht primitiv rekursiv (Beweis am Freitag).
Definition
Die AckermannfunktionA:N2 →Nist folgendermaßen definert:
A(0,n) = n+ 1 f¨urn≥0
A(m+ 1,0) = A(m,1) f¨urm≥0
A(m+ 1,n+ 1) = A(m,A(m+ 1,n)) f¨urm,n≥0
Primitiv rekursive Funktionen und LOOP-Berechenbarkeit
Satz
Die Klasse der primitiv rekursiven Funktionen stimmt genau mit der Klasse der LOOP-berechenbaren Funktionen ¨uberein.
Beweis: primitiv rekursiv ⊆ LOOP-berechenbar
Alle primitiv rekursiven Funktionen k¨onnen als LOOP-Programm implementiert werden, denn
Basisfunktionen sind offensichtlich LOOP-berechenbar Kompositionen primitiv rekursiver Funktionen werden durch Hintereinanderausf¨uhrung der entsprechenden
LOOP-Programme implementiert
Und fallsf durch primitive Rekursion definiert ist, d.h. in der Form
f(0,x1, . . . ,xk) =g(x1, . . . ,xk)
f(n+ 1,x1, . . . ,xk) =h(f(n,x1, . . . ,xk),n,x1, . . . ,xk) gegeben ist, verwenden wir das folgende LOOP-Programm:
y :=g(x1, . . . ,xk);
LOOP n DO y :=h(y,n−1,x1, . . . ,xk) END
Beweis: LOOP-berechenbar ⊆ primitiv rekursiv
F¨ur die Umkehrrichtung benutzen wir eine bijektive Abbildung encode :Nk →N(z.B. die Cantorsche Tupelfunktion), um
Modifikationen aufk Variablen als einstellige Funktion darzustellen.
Man kann sich leicht veranschaulichen, dass die in der ¨Ubung vorgestellte Cantorsche Paarfunktionπ :N2 →Nmit
π(x,y) =
x+y+ 1 2
+y
und ihre Erweiterungπ(k):Nk →Nauf k-Tupel nat¨urlicher Zahlen durch
π(k)(x1, . . . ,xk) =π(π(k−1)(x1, . . . ,xk−1),xk) primitiv rekursiv ist.
Ebenso kann man die Umkehrfunktionendi mit
di(encode(x1, . . . ,xi, . . . ,xk)) =xi zum Dekodieren der einzelnen Elemente primitiv rekursiv definieren.
Beweis: LOOP-berechenbar ⊆ primitiv rekursiv
Ein LOOP-Programm P der Form xi :=xj ±c kann nun als primitiv rekursive Funktion
gP(z) =encode(d0(z), . . . ,di−1(z),di(z)±c,di+1(z), . . . ,dk(z)) geschrieben werden.
F¨ur die Hintereinanderausf¨uhrung zweier ProgrammeQ;R verwenden wir die Komposition gR(gQ(z)).
Und LOOP xi DOQ END wird durch gLOOP(z) =h(di(z),z)
mit h(0,z) =z und h(n+ 1,z) =gQ(h(n,z)) abgebildet.
Primitiv rekursive Funktionen und LOOP-Berechenbarkeit
Wir haben gezeigt:
Satz
Die Klasse der primitiv rekursiven Funktionen stimmt genau mit der Klasse der LOOP-berechenbaren Funktionen ¨uberein.
Aber: Nicht alle Funktionen sind primitiv rekursiv.
Wie sieht die Klasse der WHILE-/Turing-berechenbaren Funktionen aus?
µ-rekursive Funktionen
Induktive Definition µ-rekursiver Funktionen µ-rekursiv sind:
1 Basisfunktionen (Nullfunktion, Projektionen, Nachfolgerfunktion)
2 Kompositionen µ-rekursiver Funktionen
3 Primitive Rekursionen µ-rekursiver Funktionen
4 µ-Rekursionenµ-rekursiver Funktionen
f(x1, . . . ,xk) =µg := min{n|g(n,x1, . . . ,xk) = 0 und f¨ur alle m<n ist g(m,x1, . . . ,xk) definiert}, wobei min{∅}:=⊥
Turing-berechenbare Funktionen
Satz
Die Klasse derµ-rekursiven Funktionen stimmt genau mit der Klasse der WHILE-/TURING-berechenbaren Funktionen ¨uberein.
Ein ProgrammP der Form WHILExi 6= 0 DOQ END wird als gP(z) =h(µ(dih)(z),z)
dargestellt, wobeih(n,z) wie im vorigen Beweis den Zustand der Programmvariablenz =encode(x0, . . . ,xk) nachn Ausf¨uhrungen vonQ wiedergibt.
Umgekehrt implementieren wirg =µf durch x0 := 0;
y:=f(0,x1, . . . ,xn);
WHILEy 6= 0 DO x0 :=x0+ 1;
y :=f(x0,x1, . . . ,xn);
END
Zusammenfassung
TM ≡RAM≡ WHILE ≡µ-rekursiv )
LOOP ≡primitiv rekursiv + − × ab xk nk
. . .
Ackermannfkt.