Skript zur Vorlesung Komplexit¨at von Algorithmen
Skript zur Vorlesung Komplexit¨at von Algorithmen
Skript zur Vorlesung Komplexit¨at von Algorithmen
Erfolgreiche ePaper selbst erstellen
Machen Sie aus Ihren PDF Publikationen ein blätterbares Flipbook mit unserer einzigartigen Google optimierten e-Paper Software.
<strong>Skript</strong> <strong>zur</strong> <strong>Vorlesung</strong><br />
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Jan Dörntlein<br />
19. Juli 2012<br />
Dieses <strong>Skript</strong> wurde auf Basis der Tafelanschriften (und zwar ohne jegliche<br />
Ergänzungen) der <strong>Vorlesung</strong> Komplexität <strong>von</strong> <strong>Algorithmen</strong> <strong>von</strong> Prof. Schröder an<br />
der FAU Erlangen erstellt. Es erhebt keinerlei Anspruch auf Vollständigkeit oder<br />
Korrektheit und dient nur dem Übungszweck.<br />
Literatur: Computability and Complexity, From a Programming Perspective, Neil<br />
D. Jones<br />
Inhaltsverzeichnis<br />
1 Komplexität 2<br />
1.1 Berechnungsmodell WHILE . . . . . . . . . . . . . . . . . . . . . . . . . . . 2<br />
1.2 GOTO - ähnliche Modelle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10<br />
1.3 Die Turingmaschine . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12<br />
1.4 Successor Random Access Machine . . . . . . . . . . . . . . . . . . . . . . . 13<br />
1.5 Komplexitätsklassen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14<br />
2 Ein Hierarchiesatz 20<br />
2.1 Berechnungsmodell I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.2 Selbstinterpretation <strong>von</strong> I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20<br />
2.3 Zeitbeschränkte Selbstinterpretation . . . . . . . . . . . . . . . . . . . . . . . 22<br />
2.4 Die lineare Hierarchie für I . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22<br />
1
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
3 Speicherplatz als Ressource 23<br />
3.1 In logspace berechenbare Funktionen . . . . . . . . . . . . . . . . . . . . . . 26<br />
3.2 Platzhierarchien . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28<br />
4 Nichtdeterminismus 28<br />
5 Die Backbone - Hierarchie 30<br />
6 Vollständigkeit 36<br />
6.1 PTIME - Vollständigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38<br />
6.2 NPTIME - Vollständigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46<br />
6.3 PSPACE - vollständigkeit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47<br />
6.4 Quantifizierte Boolesche Formeln . . . . . . . . . . . . . . . . . . . . . . . . 48<br />
7 Parallel computation models 53<br />
2
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
1 Komplexität<br />
Einteilung der Komplexitätsklassen:<br />
L<br />
NL<br />
P<br />
NP — coNP<br />
PH<br />
PSPACE<br />
EXPTIME<br />
NEXPTIME — CONEXPTIME<br />
logarithmisch<br />
nicht deterministisch<br />
polynomzeit<br />
polynomielle Hierarchie<br />
polynomieller Speicher<br />
Beispiele für Probleme und deren Einteilung in diese Klassen:<br />
Problem Komplexität Algos. / Tools<br />
SAT NP SAT-Solver<br />
OWL-DL NEXPTIME Fact++, Racer<br />
PRIMES P Zufallsalgorithmen (Rubin)<br />
Lineare Optimierung P Simplex (EXPTIME)<br />
FOL (Logik erster Stufe) unentscheidbar / r.e. SPASS, Vampire<br />
HOL (Logik hoeherer Ordnung) nicht r.e. / nicht co-r.e. Isabelle: Blast, Leo2<br />
Algorithmus als Berechnungsmodell, wie z.B. TM, sRAM, CM, WHILE, GOTO.<br />
Alle diese Modelle können sich gegenseitig in Polynomzeit simulieren.<br />
1.1 Berechnungsmodell WHILE<br />
Daten : D ist eine Menge <strong>von</strong> binäre Bäumen, d,e ∈ D. d,e := a | (d.e) (d und e sind hier der<br />
linke und rechte Teilbaum). A sind alle atomaren, endlichen Werte. Es gilt: a ∈ A, nil ∈ A<br />
(nil steht hier für das leere Element, der Platzhalter).<br />
• Bsp.: ((a.(b.c)).(a.c)<br />
• oder: (a.(b.(c.(d.(a.nil))))) := (abcda). ”Liste als Baum”.<br />
Allgemein gilt: (d 1 ,d 2 ,...,d n ) := (d 1 .(d 2 .(d 3 .(...(d n .nil)...))), nil stellt hierbei die leere<br />
Liste dar.<br />
3
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Def.: Die Listendarstellung d <strong>von</strong> d ∈ D (d als Datenelement) ist definiert durch:<br />
Mit nil:<br />
(d 1 .(d 2 .(d 3 .(...(d n .nil)...)) = (d 1 ,...d n )<br />
Ohne nil:<br />
Bsp.:<br />
(d 1 .(d 2 .(d 3 .(...(d n .a)...)) = (d 1 ,...d n ,a)<br />
((a.(b.c).((b.b).c)) = ((a.(b.c))(b.b)c) = ((abc)(bb)c)<br />
Einschub, Kodierung <strong>von</strong> Atomen nur durch nils:<br />
a i = (f alse i)<br />
(d.e) = (true,de)<br />
Natürliche Zahlen:<br />
Booleans:<br />
0 = ()<br />
n + 1 = (nil.n)<br />
n = (nil...nil)<br />
}{{}<br />
n−mal<br />
true = 1 = (nil)<br />
f alse = 0 = () = nil<br />
Formal: D ist die kleinste Menge X mit<br />
(i) A ⊆ X<br />
(ii) d,e ∈ X ⇒ (d.e) ∈ X<br />
Größe: |d| ist definiert durch:<br />
(iii) |a| = 1<br />
(iii) |(d.e)| = |d| + |e|<br />
Rekursion: Die Menge X, der d ∈ D für die |d| eindeutig erfüllt ist, erfüllt (i) und (ii),<br />
also ist D ⊆ X (also gilt X = D):<br />
Programme : bestehen aus einer Menge <strong>von</strong> Variablen, Vars (wie X,Y ,Z) und d,e,f ∈ D.<br />
4
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Ausdrücke:<br />
E,F ::== X|d| cons EF| hd E| tl E| =?EF<br />
}{{} }{{} }{{} }{{}<br />
P unkt<br />
head<br />
tail<br />
V ergleich<br />
Anweisungen:<br />
C,D ::== X := E<br />
}{{}<br />
Zuweisung<br />
| C;D<br />
}{{}<br />
SequentielleKomposition<br />
|while E do C (E wird auf nil geprüft)<br />
Programme: Sei X eine Eingabevariable und Y eine Ausgabevariable.<br />
p ::== read X; C; write Y<br />
Mehrere Ein- / Ausgaben bekommt man über Baumstrukturen, beispielsweise Eingabe<br />
<strong>von</strong> d,e als (d.e).<br />
read X; Y := hd X; Z = tl X; C; write Y<br />
Scoping: per {} oder Einrücken<br />
Beispielprogramm:<br />
reverse =<br />
read X;<br />
Y := nil;<br />
while X do<br />
Y := cons (hd X) Y;<br />
X := tl X;<br />
write Y;<br />
Makros: Z,W seien hier ’frische’ Variablen, also Variablen, die bisher noch nicht aufgetaucht<br />
sind.<br />
if E then C =<br />
Z := E;<br />
while Z do { Z := false; C; }<br />
if E then C else D =<br />
W := true;<br />
5
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
if E then { W := false; C }<br />
if W then D;<br />
list E1...En =<br />
cons E1 (cons E2 ... (cons En nil) ... )<br />
cons* E1...En =<br />
cons E1 (cons E2 .. (cons En-1 En) ... )<br />
Bsp.:<br />
list a b (d a) = (a b (d a) )<br />
cons* a b (d a) = (a b d a)<br />
Inline-Prozeduren: Für<br />
p = read X; C; write Y:<br />
Z := pW (Z,W ∈ V ars) in Programm q.<br />
Es wird ¯C aus C durch Umbennenen konstruiert:<br />
X → X ′ , Y → Z, X ′ sei frisch.<br />
Es müssen auch andere Var in C umbennant werden, damit sie frisch in q sind. Dann gilt<br />
Z := pW → X ′ = W ; ¯C.<br />
Übung: Ähnlich für Verwendung <strong>von</strong> p in komplexen Ausdrücken.<br />
Bsp. für eine Inline-Prozedur:<br />
append =<br />
read X;<br />
A := hd X; Y := tl X;<br />
B := reverse A;<br />
while B do<br />
Y := cons (hd B) Y;<br />
B := tl B;<br />
write Y;<br />
Im Vergleich hierzu jetzt die umbenannte Prozedur reverse; nur der Körper wird umbenannt:<br />
Y → B, X → X ′ .<br />
6
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
B := nil;<br />
while X’ do<br />
B := cons (hd X’) B;<br />
X’ := tl X’;<br />
Vorsicht: C geht bei einer Umbenennung <strong>von</strong> Y nach Z da<strong>von</strong> aus, dass Y mit nil initialisiert<br />
wurde. Besser ist es, wenn alle Variablen auf jeden fall frisch sind.<br />
Zahloperationen:<br />
succ = cons nil<br />
prec = tl<br />
add =<br />
read XY; X:= hd XY; Y:= tl XY;<br />
while X do<br />
Y := succ Y<br />
X := prec X<br />
write Y<br />
Formale Semantik: Vars(p) ist die Menge der in p vorkommenden Variablen. Ein Speicher<br />
für p ist eine Abbildung σ : V ars(p) → D. Store p ist die Menge der Speicher für p.<br />
Notation: [X 1 → d 1 ,...,X n → d n ] = Funktion σ mit σ(X 1 ) = d 1 ,...,σ(X n ) = d n<br />
⎧<br />
⎪⎨ d v = X<br />
σ[X → d](v) = ⎪⎩ σ(v) sonst<br />
Für Vars p = X,Z 1 ,...,Z n , mit X als Eingabevariable:<br />
Anfangsspeicher (Initialspeicher) σ p 0 (d) = [X → d,Z 1 → nil,...,Z n → nil]<br />
Ausdrücke: Eσ ∈ D :<br />
• Xσ = σ(X)<br />
• dσ = d<br />
• consEFσ = (Eσ.Fσ)<br />
⎧<br />
⎪⎨ dE = (d.e)<br />
• hdEσ = ⎪⎩ nil<br />
• tlEσ analog<br />
7
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
⎧<br />
⎪⎨ true Eσ = Fσ<br />
• =?EFσ = ⎪⎩ f alse sonst<br />
Anweisungen: Anweisung C wird ausgeführt auf Speicher σ und terminiert bei σ ′ .<br />
C ⊢ σ → σ ′<br />
Bsp.:<br />
X := d ⊢ [X → e,Y → f ] → [X → d,Y → f ]<br />
Diese Relation ⊢ → wird induktiv definiert (d.h. als kleinste unter folgenden Regeln<br />
abgeschlossene Relation). Bei folgenden Regeln gilt: oberhalb des Strichs steht die<br />
Prämisse, unterhalb die Konklusion.<br />
• Regel (:=)<br />
X := E ⊢ σ → σ[X → Eσ]<br />
• Regel (;)<br />
• Regel (w ⊥)<br />
• Regel (w⊺)<br />
C ⊢ σ → σ ′ D ⊢ σ ′ → σ ′′<br />
C;D ⊢ σ → σ ′′<br />
Eσ = nil<br />
while E do C ⊢ σ → σ<br />
Eσ nil C ⊢ σ → σ ′ while E do C ⊢ σ ′ → σ ′′<br />
while E do C ⊢ σ → σ ′′<br />
D.h. C ⊢ σ → σ ′ gilt genau dann, wenn dies mit den Regeln in endlich vielen Schritten<br />
herleitbar ist.<br />
Herleitung kann als Datenstruktur (Baum) aufgefasst werden → Induktion über Herleitung.<br />
Zeige: wenn P (h) für alle Herleitungen h gilt, die einfacher als h 1 sind, so gilt P (h 1 ), dann<br />
gilt P für alle Herleitungen.<br />
Lemma: Determinismus <strong>von</strong> WHILE.<br />
C ⊢ σ → σ 1 und C ⊢ σ → σ 2 ⇒ σ 1 = σ 2<br />
8
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beweis: Induktion über die Herleitung <strong>von</strong> C ⊢ σ → σ 1 . Anwendung <strong>von</strong> (w ⊥) und (w⊺).<br />
Y σ ′ =nil<br />
whileY do...⊢σ ′ →σ ′<br />
Y σ nil Y :=nil⊢σ→σ ′<br />
while Y do Y := nil ⊢ [Y → d] → [Y → nil] mit d nil<br />
(:=) ist klar, (w ⊥) ist klar. (;) ist einfacher als (w⊺).<br />
(w⊺):<br />
Eσ nilD ⊢ σ → σ 3 while E do D ⊢ σ 3 → σ 1<br />
while E do D ⊢ σ → σ 1<br />
Notwendigerweise haben wir folgende Regelanwendungen:<br />
Eσ nilD ⊢ σ → σ 4 while E do D ⊢ σ 4 → σ 2<br />
while E do D ⊢ σ → σ 2<br />
Nach Induktionsvorraussetzung für D ⊢ σ → σ 3 : σ 3 = σ 4 ,<br />
damit nach Induktionsvorraussetzung für while E do D ⊢ σ 2 → σ 1 : σ 1 = σ 2 .<br />
Beispiel zum Zeigen <strong>von</strong> Zustandsübergängen:<br />
(nil.nil) nil Y := Y ⊢ σ → σ w(nil.nil)do...⊢σ→σ ′<br />
while(nil.nil)doY := Y ⊢ σ → σ ′ ?<br />
⇒ offensichtlich unendliche Herleitung (unter den Strichen steht dasselbe). <br />
Programme: p : D → D ⊥ = D ∪ {⊥} wobei ⊥= undefiniert<br />
⎧<br />
⎪⎨ e falls C ⊢ σ0 P (d) → σ,σ(Y ) = e<br />
read X; C; write Y (d) = ⎪⎩ ⊥ sonst<br />
⇒ Wohldefniert nach obigem Lemma (Determinismus).<br />
Bemerkungen: =? ist programmierbar, wenn man in der Lage ist, Atome zu vergleichen (also<br />
mithilfe atomarer Gleichheit =? A ) und ohne atomare Gleichheit programmierbar, wenn<br />
A = {nil} (dann gibt es nichts zu vergleichen).<br />
Pattern: Term mit Variablen über die Sprache der Bäume: pat ::= X|a| (pat 1 .pat 2 )<br />
Verwendung z.B. beim case: case E of pat 1 ⇒ C 1 |...|pat n ⇒ C n<br />
9
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beispiel:<br />
swap:<br />
read X;<br />
case X of nil => Z := nil;<br />
write Z;<br />
bzw.<br />
swap:<br />
read X;<br />
case X of (W.Y) => Z := (Y.W);<br />
write Z;<br />
Informell: Matchen <strong>von</strong> d ∈ D (mit d = Eσ) auf pat i bindet die Var in pat i auf die<br />
entsprechenden Teilbäume <strong>von</strong> d.<br />
case ist ein Makro für geschachtelte ifs; der Zugriff auf Var geschieht per hd oder tl.<br />
rewrite rules: rewrite [X 1 ,...,X n ] by rule 1 ,...,rule k mit<br />
rule ::= [pat 1 ,...,pat n ] ⇒ [E 1 ,...,E n ]| [pat 1 ,...,pat n ] ⇒ C<br />
entspricht case auf n-Tupeln, [E 1 ,...,E n ] → [X 1 ,...,X n ] := [E 1 ,...,E n ]<br />
Matching:<br />
Beispiel:<br />
Substitution = Abb. τ : V ars(E) → D<br />
patτ ∈ D<br />
d matcht pat ⇔ ∃τ,patτ = d<br />
pat = ((X.nil).Y )<br />
d = (((a.b).nil).(a.(c.d))) matcht pat per Y → (a.(c.d)) und X → (a.b)<br />
d = (a.b) matcht nicht<br />
Beispiel: =? für A = nil<br />
(Vollständige Version des Programms findet sich im Buch).<br />
10
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
=?:<br />
read X;<br />
D := hd X;<br />
E := tl X;<br />
GO := true;<br />
Y := false;<br />
while GO do<br />
rewrite [D,E] by<br />
[((D1.D2).D3), ((E1.E2).E3)] =><br />
[(D1.(D2.D3)), (E1.(E2.(E3))]<br />
[(nil.D2), (nil.E2)] =><br />
[D2, E2]<br />
[nil, nil] =><br />
GO := false; Y := true;<br />
[((D1.D2).D3), (nil.E2)] =><br />
GO := false;<br />
...<br />
write Y;<br />
Programme als Daten:<br />
A = {:=,;,while,var,quote,cons,hd,tl,=?,nil,prog}<br />
· ∈ D def. für Programme / Anweisungen / Ausdrücke.<br />
readV i ;C;writeV j = (prog V i C V j)<br />
C;D = (;C D) while E do C = (while EC)<br />
V i := E = (:= V i E) V i = (var i)<br />
d = (quote d) cons EF = (cons EF)...<br />
1.2 GOTO - ähnliche Modelle<br />
L ∈ {GOT O,T M,RAM}: Gemeinsame Notation und Semantik.<br />
p ∈ L − P rog., p = I 1 ,...,I n oder 1 : I 1 ,...,m : I m , m + 1<br />
}{{}<br />
Ende des Programms<br />
:<br />
11
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Zustände: s = (<br />
l , σ )<br />
}{{} }{{}<br />
Label l∈{1,...,m+1} Speicher σ∈L−Store p<br />
p ⊢ s → s ′ p geht in einem Schritt <strong>von</strong> s nach s’ . Einschritttransition.<br />
p ⊢ s → ∗ s ′ p geht in n ≥ 0 Schritten <strong>von</strong> s nach s’ .<br />
p(x) = y(x,y ∈ L − Data, p terminiert bei Eingabe x mit Ausgabe y.)<br />
Modellabhängig:<br />
• Readin: L − Data → L − Store p<br />
• Readout: L − Store p → L − Data<br />
Damit: p(x) = y ⇔ ∃σ ∈ L − Store p : p ⊢ (1,Readin(x)) → ∗ (m + 1,σ)&Readout(y) = y<br />
(⇒ d.h. p =⊥ , wenn p bei Eingabe x nicht terminiert)<br />
GOTO - Berechnungsmodell :<br />
Def. 1.1: GOTO - Syntax.<br />
• GOTO-Data = D mit A = nil<br />
• Instruktionen: I := X := nil|X := Y |X := hdY |X := tlY |X := consY Z<br />
• Kontrollstruktur: [if X] goto l 1 [else l 2 ] mit l 1 ,l 2 ∈ {1,...,m + 1}<br />
z.B. reverse:<br />
1. Y := nil;<br />
2. if X goto 3 else 7;<br />
3. Z := hd X;<br />
4. Y := cons ZY;<br />
5. X := tl X;<br />
6. goto 2;<br />
7. X := Y;<br />
Def. 1.2: GOTO - Semantik.<br />
12
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
• Sei p = I 1 ,...,I m ,V ars(p) = {X,Z 1 ,...,Z n } mit X als Ein-/Ausgabevariable.<br />
• GOTO-Store p = V ars(p) → D<br />
• Readin(d) = [X → d,Z 1 → nil,...,Z n → nil]<br />
• Readout(σ) = σ(X)<br />
Transitionen:<br />
1.3 Die Turingmaschine<br />
I l = (X := nil) : p ⊢ (l,σ) → (l + 1,σ[X → nil])<br />
I l = (X := Y ) : p ⊢ (l,σ) → (l + 1,σ[X → Y ])<br />
I l = (X := consY Z) : p ⊢ (l,σ) → (l + 1,σ[X → (σ(Y ).σ(Z))])<br />
...<br />
⎧<br />
⎪⎨ σ(X) nil : p ⊢ (l,σ) → (l<br />
I l = (if X goto l 1 else l 2 ) :<br />
1 ,σ)<br />
⎪⎩ σ(X) = nil : p ⊢ (l,σ) → (l 2 ,σ)<br />
Def. 1.3: k ist die Anzahl der Bänder. Σ = {0,1,B}, das gesamte Alphabet.<br />
T M K -Data = {0,1} ∗<br />
T M K -Store = {(L 1 S 1 R 1 ,...,L k S k R k )} mit L i ,R i ∈ Σ ∗ ,S i ∈ Σ.<br />
L i S i R i repräsentiert das Band, S i ist die Position des Lese-/Schreibkopfes.<br />
Instruktionen :<br />
j ist die Bandnummer. Hier gibt es Labels anstatt <strong>von</strong> Zuständen.<br />
I ::== right j | lef t j | write j S | if j S goto l 1 else l 2<br />
Readin(x) = {Bx,B,...,B}<br />
Readout(L 1 S 1 R 1 ,...,L k S k R k ) = P f x(R 1 )<br />
}{{}<br />
Symbole vor erstem B<br />
⎧<br />
⎪⎨ S P f x(R ′ ) falls R = SR ′ ,S B<br />
d.h. P f x(R) = ⎪⎩ () sonst<br />
Transitionen (für k=1) :<br />
I l = right : p ⊢ (l,LSS ′ R) → (l + 1,LSS ′ R)<br />
I l = right : p ⊢ (l,LS) → (l + 1,LSB)<br />
I l = lef t : analog<br />
(später R k )<br />
13
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
I l = write S : p ⊢ (l,LS ′ R) →<br />
⎧<br />
(l + 1,LSR)<br />
⎪⎨ p ⊢ (l,LSR) → (l<br />
I l = (if S goto l 1 else l 2 ) :<br />
1 ,LSR)<br />
⎪⎩ p ⊢ (l,LS ′ R) → (l 2 ,LS ′ R)<br />
Bsp. 1.4: Band 1 nach Band 2 kopieren.<br />
0. write 1<br />
1. if1 0 goto 2 else 4<br />
2. write2 0<br />
3. goto 6<br />
4. if1 1 goto 5 else 9<br />
5. write2 1<br />
6. right2<br />
7. right1<br />
8. goto 1<br />
9.<br />
1.4 Successor Random Access Machine<br />
Successor: alle gegebenen Zahloperationen sind das Inkrement und das Dekrement.<br />
Instruktionen :<br />
I ::== X i := X i + 1 | X i := X i − 1 | if X i = 0 goto l 1 else l 2 |<br />
| X i := X j | X i := 〈X j 〉 | 〈X i 〉 := X j<br />
}{{}<br />
indirekte Zuweisung<br />
SRAM-Store: N → N<br />
Readin(x) = [0 ⊢ x,1 ⊢ 0,...]<br />
Readout(σ) = σ(0)<br />
Transitionen :<br />
I = (X i := 〈X j 〉) : p ⊢ (l,σ) → (l + 1,σ[i → σ(σ(j))])<br />
I = (〈X i 〉 = X j ) : p ⊢ (l,σ) → (l + 1,σ[σ(i) → σ(j)])<br />
14
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
1.5 Komplexitätsklassen<br />
Zeitkomplexität :<br />
Def. Zeitverbrauch/Laufzeit: GOTO - ähnliche Sprachen: p = I 1 ,...,I m .<br />
⎧<br />
⎪⎨ t wenn p ⊢ (1,Readin(d)) = s<br />
time p (d) =<br />
1 → s 2 → ... → s t = (m + 1,σ)<br />
⎪⎩ ⊥ sonst<br />
⇒ ”Kleinschrittig”<br />
Einheitskostenmodell (unit cost model): Für jede Zuweisung wird eine Kosteneinheit<br />
fällig.<br />
• WHILE: T Eσ = Größe <strong>von</strong> E.<br />
C ⊢ time σ → t wird induktiv definiert durch<br />
Zeitklassen :<br />
X := E ⊢ time σ → T Eσ + 1<br />
C ⊢ time σ → t C ⊢ σ → σ ′ D ⊢ time σ ′ → t ′<br />
C;D ⊢ time σ → t + t ′<br />
Eσ = nil<br />
while E do C ⊢ time σ → T Eσ + 1<br />
Eσ nil C;while E do C ⊢ time σ → t<br />
while E do C ⊢ time σ → T Eσ + t<br />
Def. 1.6: Ein Problem ist eine Menge A ⊆ {0,1} ∗ → kodierbar in alle Datenmodelle.<br />
⎧<br />
⎪⎨ true wenn d ∈ A (d ist ein Bitstring)<br />
p entscheidet A, falls p(d) = ⎪⎩ f alse sonst<br />
Bsp. 1.7:<br />
• SAT = {d aussagenlogische Formel|dist erfüllbar}<br />
• P RIMES = {n ∈ N|n prim}<br />
• HALT = {(p,d)| p(d) ⊥}<br />
Bei der Konversion in Bitstrings muss man beim Problem P RIMES aufpassen.<br />
Def. 1.8: Sei f : N → N L time(f (n)) = {p ∈ L − P rog| time p (d) ≤ f (|d|)∀d ∈ {0,1} ∗ }<br />
L ptime = ⋃ f P olynom Ltime(f (n)) 15
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Def. 1.9:<br />
• T IME L (f (n)) = {A ⊆ {0,1} ∗ |A wird <strong>von</strong> einem p ∈ L time(f (n)) entschieden}<br />
• P T IME L = {A ⊆ {0,1} ∗ | A wird <strong>von</strong> einem p ∈ L ptime entschieden}<br />
Robustheit: zu Zeigen ist, dass alle Berechnungsmodelle in P T IME liegen.<br />
Def. 1.10: Für Berechnungsmodelle L,M L ≺ ptime M (L ptime-reduzierbar auf M) ⇔<br />
∀p ∈ L − P rog ∃q ∈ M − P rog,f P olynom<br />
p = q ∧ ∀d ∈ {0,1} ∗ , time q (d) ≤ f (time p (d))<br />
Lemma 1.11:<br />
(a) L ≺ ptime M ⇒ P T IME L ⊆ P T IME M<br />
(b) L ≼ ptime M ∧ M ≼ ptime ⇒ P T IME L = P T IME M (der Operator ≼ ptime ist transitiv!)<br />
DER PLAN: Zeige: T M ≼ GOT O ≼ SRAM ≼ T M und GOT O ≼ W HILE ≼ GOT O ⇒<br />
Proposition 1.12:<br />
P T IME T M = P T IME GOT O = P T IME SRAM = P T IME W HILE<br />
• W HILE ≼ ptime GOT O, Beweis:<br />
(a) Ausdrücke E zerlegen in Sequenzen <strong>von</strong> Zuweisungen.<br />
(b) Ersetze while durch bedingte Sprünge.<br />
Der Blowup-Faktor ist vernachlässigbar.<br />
Proposition 1.13:<br />
• GOT O ≼ ptime W HILE, Beweis mit Böhm-Jacopini-Konstruktion:<br />
Übersetze p = I 1 ,...,I m in<br />
read X;<br />
C := 1;<br />
while C do<br />
if =? C 1 then T( 1, I1 )<br />
...<br />
if =? C m then T( m, Im )<br />
write X<br />
mit T (l,I l ) = I l ;C := l + 1mod(m + 1)} wenn I l eine Zuweisung ist, sonst<br />
T (l,if X goto l 1 else l 2 ) = {if X then C := l 1 mod(m+1) else C := l 2 mod(m+1)}<br />
Der Blowup-Faktor ist hier m, also die Länge des Programms.<br />
16
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Proposition 1.14:<br />
• T M ≼ ptime GOT O: Kodierung <strong>von</strong> Symbolen/Bändern nach D.<br />
B + = 0,0 + = 1,1 + = 2<br />
c(S 1 ,...,S k ) = (S + 1 ,...,S+ k )<br />
o.E.: k = 1 (ein Band). Repräsentation: LSR durch<br />
V ar<br />
C S +<br />
Rt C(R)<br />
Lt c(L ∇ ) = reverse (L)<br />
Übersetze p = I 1 ,...,I m in ¯p = Ī 1 ,...,Ī m gemäß<br />
I Ī<br />
right if (=? Rt nil) then Lt := cons C Lt; C := B + ;<br />
else Lt := cons C Lt; C := hd Rt, Rt := tl Rt;<br />
left analog<br />
write S C := S +<br />
if S goto l 1 else l 2 if (=?C S + ) then ¯l 1 else ¯l 2<br />
→ linearer Blowup.<br />
Proposition 1.15:<br />
• SRAM ≼ ptime T M:<br />
Beweis durch RISC − SRAM: X 0 als Akkumulator.<br />
I ::= X 0 := X i | X i := X 0 | X 0 := X 0 + 1 | X 0 := 〈X i 〉 | 〈X 0 〉 := Xi |<br />
| if X 0 goto l 1 else l 2<br />
Zum Beispiel: X j := 〈X i 〉 → X k := X 0 ; X 0 := 〈X i 〉; X j := X 0 ;X 0 := X k<br />
→ nur lineare Verlangsamung.<br />
Simulation in T M 5 (k = 5):<br />
17
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Band Inhalt, Grundposition<br />
1: Input ...BBa o ...a n BB...<br />
2: Addressen ...BBbin(b 1 )Bbin(b 2 )B...Bbin(b k )BB...<br />
3: Werte ...BBbin(c 1 )Bbin(c 2 )B...Bbin(c k )BB...<br />
4: Akku ...BBbin(σ(0))BB...<br />
5: Scratch ...BB...BB...<br />
Repräsentiert [σ ⊢ σ(0),b 1 ⊢ c 1 ,...,b k ⊢ c k ].<br />
– Abschlusscode, der am Ende ausgeführt wird: Kopiere Band 4 nach Band 1, da<br />
die Ausgabe auf Band 1 abläuft. Zeit: O(log(σ(0))).<br />
– Simulation in TM q: z.B. X 0 := X 0 + 1.<br />
* Fahre ans Ende <strong>von</strong> Band 4.<br />
* Ersetze <strong>von</strong> rechts 1 durch 0 solange möglich.<br />
* Ersetze 0 oder B durch 1.<br />
* Fahre in Grundposition.<br />
Zeit: O(log(σ(0))).<br />
– X i := X 0 .<br />
* Durchsuche Band 2 und 3 parallel bis i als b j auf Band 2 gefunden ist.<br />
* Nicht gefunden: i an Band 2 hängen, Band 4 ans Ende <strong>von</strong> Band 3 anhängen,<br />
fahre <strong>zur</strong> Grundposition.<br />
* gefunden: kopiere c j+1 , b k auf Scratch, überschreibe c j mit Akku. Kopiere<br />
Scratch hinter neue c j , fahre <strong>zur</strong> Grundposition.<br />
Zeit: O(max. Bandlänge).<br />
– X 0 := 〈X i 〉.<br />
* Durchsuche Band 2 und 3 parallel bis i als b j auf Band 2 gefunden ist.<br />
* Nicht gefunden: fertig, fahre <strong>zur</strong> Grundposition.<br />
* gefunden: kopiere c j nach Scratch, Durchsuche parallel Band 2 und 3 bis<br />
c j auf Band 2 als b p gefunden wird, nicht gefunden: 0 auf Akku, sonst:<br />
kopiere c p auf Akku, fahre <strong>zur</strong> Grundposition.<br />
Zeit: O(max. Bandlänge).<br />
Abschätzung der Bandlänge bei t ≥ n.<br />
σ(j) ≤ n + t ≤ 2t<br />
18
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Also ∃c,σ(j) 0 ⇒ j ≤ max(2t,c).<br />
⇒ Bandlänge = O(max(2t,c) · log(t)) = Zeit für Schritt t in q, also bei<br />
t = time p (d) ⇒ time q (d) = O(t · max(2t,c) · log(t)) ⇒ polynomiell.<br />
• DAG - Semantik für GOTO:<br />
Idee: spare Platz und Zeit durch Sharing.<br />
z.B.: X = cons Y Y ; X und Y sind hier Pointer auf Bäume. Jetzt wird der linke und<br />
rechte Teilbaumpointer <strong>von</strong> X jeweils auf Y umgebogen.<br />
Def. 1.16: DAG = directed acyclic graph. Der gewichtete Graph G: (V ,→) ist eine<br />
Menge <strong>von</strong> Knoten, → ist eine Menge <strong>von</strong> Kanten. Kanten sind unabhängig existierend<br />
<strong>von</strong> Knoten.<br />
→∈ e : d(e) ∈ V ,c(e) ∈ V . Lies: d(e) → e c(e)<br />
G ist azyklisch ⇔ n 0 → e 1 n 1 ... → e k n k = n 0 ⇒ k = 0, k ist die Anzahl der Schritte,<br />
man hat also keinen Schritt gemacht, denn sonst wäre der Graph zyklisch.<br />
DSG (data storage graph) ist eine Art DAG mit einem Knoten 0 ∈ V , der keine<br />
ausgehende Kante hat. Alle anderen Knoten haben zwei ausgehende Kanten, die die<br />
Labels l bzw. r haben. Optional gibt es eine Wurzel, die ein ausgewählter Knoten<br />
ist.<br />
Konversion: Zu einem Datenelement d ∈ D gibt es einen DSG dag(d) mit Wurzel.<br />
dag(nil) = 0, 0 ist hier die Wurzel.<br />
dag(d 1 .d 2 ) = (dag(d 1 ).dag(d 2 )), mit neuer gemeinsamer Wurzel.<br />
Konversion umgekehrt: δ ist ein DSG, n ist ein Knoten. unf = unfold.<br />
⎧<br />
⎪⎨ nil n = 0<br />
unf (δ,n) = ⎪⎩ (d 1 .d 2 ) wenn unf (δ,n 1 ) = d 1 und unf (δ,n 2 )<br />
[Bsp.: reverse als DAG mit Liste X = (a b)]<br />
Def. 1.17: DAG - Semantik für GOTO.<br />
Speicher für p : σ = (δ,ρ) mit δ als DSG ohne Wurzel mit der Knotenmenge V .<br />
ρ : V ars(p) → V .<br />
σ p,DAG<br />
0<br />
(d) = (δ,ρ) mit δ = dag(d),ρ(X) = Wurzel <strong>von</strong> δ und ρ(Y ) = 0 sonst.<br />
Readout(δ,ρ) = unf (δ,ρ(X)) ∈ D<br />
Instruktionen: Semantik <strong>von</strong> if X... ist wie bisher mit einer Abfrage auf ρ(X) 0.<br />
I e = (X := E): p ⊢ (l,(δ,ρ)) → (l + 1,(δ ′ ,ρ[X → n])), wenn s(δ,ρ,E) = (δ ′ ,n) mit<br />
19
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
s(δ,ρ,nil) = (δ,0)<br />
s(δ,ρ,Y ) = (δ,ρ(Y ))<br />
s(δ,ρ,cons Y Z)<br />
⎧<br />
= (δ+ frischer Knoten n, der mit l auf δ(Y ) und mit r auf δ(Z) zeigt,n)<br />
⎪⎨ (δ,n) wenn ρ(Y ) → l n<br />
s(δ,ρ,hd Y ) = ⎪⎩ (δ,0) sonst<br />
s(δ,ρ,hd Y ) analog.<br />
Korrektheit der DAG - Semantik:<br />
Def. 1.18: (δ,ρ) ∼ p σ : V ars(p) → D :⇔ unf (δ,ρ(Y )) = σ(Y ) für alle Y ∈ V ars(p)<br />
Proposition 1.19: p DAG (d) = p GOT O ,timep<br />
DAG (d) = timep<br />
GOT O (d)<br />
Beweis: Zeige<br />
(a) σ p,DAG<br />
0<br />
(d) ∼ δ p,GOT O<br />
0<br />
(d) und<br />
(b) (δ,ρ) ∼ σ ⇒ (p ⊢ (l,σ) → (l ′ ,σ ′ ) ⇔ ∃(δ ′ ,ρ ′ )p ⊢ DAG (l,(δ,ρ)) → (l ′ ,(δ ′ ,ρ ′ )) ∧<br />
(δ ′ ,ρ ′ ) ∼ σ ′ )<br />
Implementierung der DAG - Semantik in Pascal-ähnlichem Pseudocode; zunächst ohne<br />
Input. V ars(p) = {X,Z 1 ,...,Z k }<br />
// Node i ist (Hd(i), Tl(i))<br />
type Index = 0... inf, Node = 0 ... inf;<br />
vars X, Z1, ... Zk : Node;<br />
Hd, Tl : array Index of Node;<br />
Time: Index;<br />
Hd[0] := 0; Tl[0] := 0; X := 0; Z1 := 0; ... Zk := 0;<br />
Time := 1; // liefert frische Indizes<br />
1: I’1, ..., m: I’m, m + 1; writeout;<br />
I Ī, entspricht obigem I ′<br />
Z := nil Z := 0, Time := Time + 1<br />
Z := V Z := V; Time := Time + 1<br />
Z := hd V Z := Hd[V]; Time := Time + 1<br />
Tl ... ...<br />
Z := cons V W Hd[Time] := V; Tl[Time] := W; Z := Time; Time = Time + 1<br />
if Z goto l 1 else l 2 if Z 0 goto l 1 else l 2<br />
Input: (p,d) ⊢ Initialisiere X auf d, p ⊢ Pascal, Blowup: lineare Verlangsamung.<br />
Proposition 1.19: GOT O ≼ ptime SRAM<br />
20
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beweis: Implementiere obigen Pseudocode in der SRAM.<br />
• zwei unendliche Arrays: interleaving mit geraden und ungeraden Adressen<br />
• Deswegen: Zähler wird in jedem Schritt um zwei erhöht<br />
2 Ein Hierarchiesatz<br />
2.1 Berechnungsmodell I<br />
I ist das Ein-Variablen-WHILE, siehe Buch.<br />
Die Variable heißt A. WHILE ist nach I kompilierbar.<br />
p ⊢ p, V ars(p) = {X 1 ,...,X n } (<strong>von</strong> WHILE nach I). A repräsentiert hier X 1 ,...,X n .<br />
X i → hd(tl i−1 (A)) ist jetzt := X i<br />
X i := E →<br />
A := cons ∗ X 1 ,...,X i−1 E tl i (A)<br />
Blowup: time p (d) ≤ k · n 2 time p (d)<br />
2.2 Selbstinterpretation <strong>von</strong> I<br />
Zunächst:<br />
I Interpretation in WHILE.<br />
Zustand:<br />
Vl<br />
Cd<br />
St<br />
Value (Speicher), d.h. σ(A)<br />
code stack<br />
value stack<br />
Hauptschleife:<br />
u1var =><br />
read PD; (* (p.d) *)<br />
P := hd PD; (* (var 1)C(var 1) *)<br />
C:= hd (tl P);<br />
Cd := cons C nil; St := nil; Vl := tl PD;<br />
while Cd do STEP;<br />
write Vl;<br />
STEP ist rewriting ”⇒”mit Invarianten:<br />
21
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
• ([(E.Cd),St,d] ⇒ ∗ [Cd,(e.St),d]) genau dann wenn E[A → d] = e<br />
• ([(C.Cd),St,d] ⇒ ∗ [Cd,St,e]) genau dann wenn C ⊢ [A → d] → [A → e]<br />
Cr steht hier für den Codrest.<br />
STEP =><br />
rewrite [Cd, St] by<br />
[((quote d).Cr), St] => [Cr, cons d St]<br />
[((var 1).Cr), St] => [Cr, cons Vl St]<br />
[((hd E).Cr), St] => [cons* E dohd Cr, St]<br />
[(dohd.Cr), (T.St)] => [Cr, cons (hd T) St]<br />
(* analog für tl, cons etc. *)<br />
Beispiel:<br />
[((; C1 C2).Cr), St] => [cons* C1 C2 Cr, St]<br />
[((:= (var 1) E).Cr), St] => [cons* E doasgn Cr, St]<br />
[(doasgn, Cr), (T.Sr)] => { Cd := Cr, St := Sr; Vl := T }<br />
[((while E C).Cr), St] => [cons* E dowhile (while E C) Cr, St]<br />
[((dowhile.(while E C).Cr), (nil.Sr)] => [Cr, Sr]<br />
[((dowhile.(while E C).Cr), (T.Sr)] => [cons* C (while E C) Cr, Sr]<br />
[((hd (var 1)).Cr), St] => [((var 1).(dohd.Cr)), St] =><br />
=> [(dohd.Cr), (Vl.St)] => [Cr, ((hd Vl).St)]<br />
Zeitanalyse:<br />
• STEP hat keine Schleifen, läuft daher in konstanter Zeit.<br />
• höchstens zwei Durchläufe pro Operator bzw. Schritt der op. Semantik<br />
⇒ lineare Verlangsamung, Faktor unabhängig <strong>von</strong> p!<br />
Selbstinterpretation in I. u1var ∈ I-Prog.<br />
Verlangsamung: O(|V ars(u1var)| 2 ), also linear und unabhängig <strong>von</strong> p.<br />
Theorem 2.1:<br />
I hat einen effizienten Selbstinterpreter i, d.h.<br />
• i(p.d) = pd, ∀p ∈ P rog,d ∈ D<br />
• ∃a ∈ R, ∀p,d : time(p.d) ≤ a · time p (d)<br />
22
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Bemerkung 2.2:<br />
Es ist nicht klar, ob WHILE einen effizienten Selbstinterpreter hat:<br />
(p.d) ⊢ i(p.d)<br />
ist in WHILE interpretierbar und braucht polynomielle Zeit in (p.d).<br />
2.3 Zeitbeschränkte Selbstinterpretation<br />
Def. 2.3: tu (time universal program) ist ein zeitbeschränkter Selbstinterpreter, wenn für alle<br />
p ∈ I − P rog, d ∈ D, n ≥ 1 gilt, dass:<br />
⎧<br />
⎪⎨ (pd.nil) time<br />
tu((p.d).n) =<br />
p (d) ≤ n<br />
⎪⎩ nil sonst<br />
tu ist effizient, wenn time tu ((p.d).n) ≤ k min(n,time p (d))<br />
Satz 2.4: I hat einen effizienten zeitbeschränkten Selbstinterpreter.<br />
Beweis: tt. Erweiterung <strong>von</strong> u1var. Input n, Ctr := n, Ctr herunterzählen bei jedem push <strong>von</strong><br />
{quote, var, dohd, dotl, cons, doasgn, dowhile}, Abbruch bei Ctr = 0.<br />
⇒ lineare Verlangsamung, unabhänig <strong>von</strong> p. Also time tt ((p.d).n) ≤ k 1 · time p (d), ferner<br />
time tt ((p.d).n) ≤ k 2 · n mit k ′ := max(k 1 ,k 2 ) und tu := tt.<br />
2.4 Die lineare Hierarchie für I<br />
Satz 2.4:<br />
Es existiert eine Zahl b ∈ N mit ∀a: T IME I (an) ⊂ T IME I (ban).<br />
Bemerkung: b = 248<br />
Beweis<br />
durch Diagonalisierung:<br />
diag =<br />
read A;<br />
A := tu( list A A (a * |A|) ); (* erstes A Daten, zweites A Programm *)<br />
if hd A then A := false else A := true;<br />
write A;<br />
B a := {p | diag a (p) = true}<br />
23
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Behauptung: ∃b ∀a : B a ∈ T IME I (ban) − T IME I (an).<br />
Zeitanalyse für diag a (p):<br />
• Berechnung <strong>von</strong> a · |p|: c · a · |p|,<br />
• tu : k · min(a|p|,time p (p)) ≤ ka|p|.<br />
• Rest: in konstanter Zeit e.<br />
Also ist B a ∈ T IME I (ban) mit b = c + k + e (unabhängig <strong>von</strong> a).<br />
Noch zu Zeigen: B a T IME I (an).<br />
Annahme: p ∈ time I (an) entscheidet B a .<br />
Dann p ∈ B a ⇔ diag a (p) = true ⇔ p(p) = f alse, da time p (p) ≤ a|p|<br />
⇔ p entscheidet B a : p B a . <br />
3 Speicherplatz als Ressource<br />
Bestimme Komplexität als benötigten Speicherplatz abhängig vom Input.<br />
Offensichtliche Relationen zu den Zeitklassen:<br />
• Zeit O(f (n)) ⇒ Platz O(f (n))<br />
• Platz O(f (n)) ⇒ Zeit O(|Σ| f (n) )<br />
letzteres: Platz f (n) liefert O(|Σ| f (n) ) Zustände, <strong>von</strong> denen ein terminierendes Programm keinen<br />
wiederholen darf.<br />
Platzverbrauch messen:<br />
Generisch für GOTO - artige Sprachen:<br />
p = I 1 ,...I m ← L-Prog<br />
p ⊢ (1,Readin(d)) = (l 1 ,σ 1 ) → ... → s t = (m + 1,σ t )<br />
⇒ spacep(d) L = max{|σ 1 |,...,|σ t |}<br />
Def.: |σ| abhängig <strong>von</strong> L.<br />
24
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beispiel TM: |(L 1 S 1 R 1 ,...L k S k R k )| = max( |L 1 S 1 R 1 |<br />
}{{}<br />
uneindeutig<br />
,|...|,|L k S k R k |)<br />
time = O(2 space ) motiviert Interesse an SP ACE(f (n)), f (n) = o(n) mit z.B. f = log.<br />
Aber nach obiger Definition gilt stets spacep<br />
T M (d) ≥ |d|.<br />
Lösung: Readonly - Band für Eingabe, später auch Writeonly - Band für die Ausgabe.<br />
Formal: Band 1 ist die Eingabe, write 1 verboten.<br />
|(L 1 S 1 R 1 ,...L k S k R k )| = max(|L 2 S 2 R 2 |,|...|,|L k S k R k |)<br />
⇒ T M ro<br />
Proposition 3.1: Sei p ∈ T M ro -Prog, spacep<br />
T M (d) ≥ |d|. ⇒ es existiert q ∈ T M-Prog mit<br />
q = p ∃a mit spaceq<br />
T M (d) ≤ a · space T M ro<br />
p (d).<br />
Definition 3.2 der Platzklassen:<br />
space L (f (n)) = {p ∈ L − P rog | space L p(d) ≤ f (|d|)}<br />
logspace L =<br />
∞⋃<br />
space L (k · log(n))<br />
k=0<br />
SP ACE L (f (n)) = {A | A wird durch ein p ∈ space L (f (n)) entschieden}<br />
Entsprechend LOGSP ACE L , P SP ACE L .<br />
Platzverbrauch RAM:<br />
Readonly - Eingabe zählt nicht mit.<br />
∑<br />
|σ| = logσ(i),σ : N → N<br />
σ(i)0<br />
Robustheit: T M ro → SRAM: sogar CM = (Counter machine), entspricht SRAM mit Zuweisungen<br />
nur X i := X i + 1,X i := X i − 1.<br />
Band b 1 ,...,b i ,b i+1 ,...,b m wird repräsentiert durch zwei Zahlen der Basis drei, (B ̂= 0,0 ̂= 1,1 ̂=<br />
2). l = b 1 ,...,b i und r = b m ,...,b i+1 . Speicherverbrauch: logl,logr ≤ 2 (+Overhead). Obwohl<br />
die Basis drei ist, gilt das hier mit dem dualen Logarithmus. (⇒ linear erhöhter Platzbedarf).<br />
SRAM → T M: σ(i) > 0 nimmt Platz logσ(i) + 1 auf dem Band ein. Wenn σ(i) > 0 ⇒ i<br />
kommt im Programm p vor (konstanter Platzbedarf).<br />
25
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Oder: i war einmal Inhalt eines Registers, also logi ≤ spacep<br />
SRAM (d). Quadratischer Blowup<br />
für die SRAM, bei der CM nur linear.<br />
Def. 3.3: Platzverbrauch für GOT O. Schreibe in DSG δ n → ∗ m für Knoten n,m in δ, wenn<br />
m <strong>von</strong> n aus in k ≥ 0 Schritten erreichbar ist. Sei (δ,ρ) ∈ ST ORE p (ρ : V ars(p) → V , V Menge<br />
der Knoten in δ). Dann |(δ,ρ)| = #{n | ∃X ∈ V ars(p),δ(X) → ∗ n}.<br />
TM → GOTO: Repräsentiere Bänder als Listen, d.h. die Anzahl der erreichbaren Knoten ist<br />
O(Bandlänge).<br />
right: Lt := cons(Hd Rt)Lt; Rt := tl Rt<br />
GOTO → SRAM: SRAM repräsentiert zunächst auch die unerreichbaren Knoten. Lösung:<br />
garbage collection, polynomielle Erhöhung des Platzverbrauchs.<br />
Theorem 3.4:<br />
(i) Sei f (n) ≥ max(1,log(n)). Dann<br />
⋃<br />
⋃<br />
SP ACE T M ro<br />
(cf ) = SP ACE CM (cf )<br />
c<br />
Zum Bsp. ist LOGSP ACE T M = LOGSP ACE CM := LOGSP ACE.<br />
(ii) P SP ACE T M = P SP ACE SRAM = P SP ACE CM = P SP ACE GOT O := P SP ACE<br />
Inklusion zwischen Zeit- und Platzklassen<br />
Proposition 3.5: T IME T M (f ) ⊆ SP ACE T M (f ), ∀f . Insbesondere gilt P T IME ⊆ P SP ACE.<br />
Beweis: Pro Schritt wird höchstens eine Zelle beschrieben.<br />
Theorem 3.6: LOGSP ACE ⊆ P T IME<br />
Beweis: Sei A ∈ LOGSP ACE. Dann wird A entschieden durch p = I 1 ,...,I m ∈ space T M ro(k ·<br />
logn),∀k. Keine Wiederholung <strong>von</strong> Zuständen ⇒<br />
p ∈ time(<br />
da 3 k logn = n k log3 .<br />
m }{{}<br />
Prog.-Zähler<br />
· (n + 2)<br />
}{{}<br />
Pos. auf Eingabeband<br />
c<br />
· (k · logn)<br />
}{{}<br />
Pos. auf Band 2<br />
· 3 k logn<br />
}{{}<br />
Inhalt Band 2<br />
) ⊆ P T IME<br />
26
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Theorem 3.7: Sei f (n) ≥ n ⇒ SP ACE T M ⊆ ⋃ c>0 T IMET M (c f )<br />
Korollar:<br />
Beweis:<br />
m ≥ 1.<br />
P SP ACE ⊆ EXP SP ACE<br />
Abschätzung der Anzahl Zustände der 1 - Band TM, p = I 1 ,...,I m in space(f ) und<br />
3 f (|d|) · f (|d|) · (m + 1) ≤ 3 f (|d|) · 2 f (|d|) · (2m) f (|d|) = (12m) f (|d|)<br />
Bemerkung:<br />
LOGSP ACE ⊆ P T IME ⊆ P SP ACE ⊆ EXP T IME<br />
3.1 In logspace berechenbare Funktionen<br />
Wichtig:<br />
Ausgabe auf gesondertes writeonly Band.<br />
logspace = feste Anzahl Pointer in die Eingabe<br />
Proposition 3.8:<br />
berechenbar.<br />
Die Funktionen −,+,≤,∗ und das Sortieren <strong>von</strong> n-Tupeln sind in logspace<br />
Beweis:<br />
z.B. ≤ mit zwei Pointern (Zahl1, Zahl2) mit Kopie.<br />
• führende 0en überlesen<br />
• Längen vergleichen<br />
• Bei gleicher Länge <strong>von</strong> vorne Ziffern vergleichen.<br />
Lemma 3.9:<br />
Sei |f (d)| ≤ p(|d|) für ein Polynom p, dann sind folgenden Aussagen äquivalent:<br />
(i) f ist in logspace berechenbar<br />
(ii) Die Funktion λ(i,d).(i-tes Bit <strong>von</strong> f (d)) ist in logspace berechenbar.<br />
Beweis:<br />
Modifikation für q:<br />
• Präfix C := 0<br />
(i) ⇒ (ii). Sei f berechenbar durch 1 - Band TM<br />
}{{}<br />
eig. 3 Band<br />
q in Platz k logn. Eingabe X i ,I.<br />
27
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
• Ersetze lef t 3 durch C := C − 1, right 3 durch C := C + 1<br />
• Ersetze write 3 Z durch if C = I then write 3 Z<br />
Bei anständiger Programmierung des ursprüngliches Programms q gilt stets 0 ≤ C ≤ p(|X|),<br />
also ist der Platzverbrauch O(log(n)).<br />
(ii) ⇒ (i). q berechnet λ(i,d).(i-tes Bit <strong>von</strong> f (d)) in logspace.<br />
r =<br />
for C = 1 to p(|X|) do<br />
{<br />
B := q CX; if B = 0 or B = 1 then<br />
write3 B; right3;<br />
}<br />
C braucht Platz <strong>von</strong> O(logn). q umprogrammieren: Input X vom Eingabeband; Input I aus C.<br />
Platzverbrauch bleibt gleicht (bis auf C).<br />
Theorem 3.10: Seien f ,g logspace berechenbar, dann auch f ◦ g.<br />
Vorsicht: Zwischenergebnis g(x) kann nicht vollständig gespeichert werden.<br />
Beweis: TM p f berechne f , p g berechne λ(i,x).(i-tes Bit <strong>von</strong> g(x)) in logspace (nach Annahme<br />
und Lemma 3.9). Verwendung <strong>von</strong> 4-Bd. TM <strong>zur</strong> Berechnung <strong>von</strong> f ◦ g.<br />
Band Inhalt<br />
1(r/o) Eingabe<br />
2 Arbeitsband <strong>von</strong> p f<br />
3 i = Kopfposition auf Eing. g(x) <strong>von</strong> p f (binär)<br />
4 b = Symbol an i<br />
5 Arbeitsband <strong>von</strong> p g<br />
6(w/o) Ausgabe<br />
r arbeitet zunächst wie p f bis auf Ausgabe (jetzt auf Band 6) und Eingabe:<br />
• if 1 S... → if 4 S...<br />
• right 1 → i := i + 1;b := p g (x,i)<br />
}{{}<br />
auf TM<br />
28
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Modifiziere p g : Band 5 als Arbeitsband. Band 4 als Ausgabeband. Eingabe X <strong>von</strong> Band 1 und i<br />
<strong>von</strong> Band 3.<br />
Platzanalyse:<br />
Band Inhalt<br />
2 O(log(n)) da p f ∈ logspace<br />
3 O(log|g(x)|)<br />
4 O(1)<br />
5 O(log(n)) da p g ∈ logspace<br />
logspace ⊆ ptime: also |g(x)| ≤ π(|X|) mit π polynom, also log|g(x)| = O(log(|X|)) mit |X| = n.<br />
3.2 Platzhierarchien<br />
Es gelten Hierarchiesätze im wesentlichen wie für Zeitklassen mit analogen Beweisen. Lineare<br />
Hierarchien für die 1 - Band TM und die allgemeine robuste Hierarchie für space ≥ n. Insbesondere<br />
gilt P SP ACE ⊆ EXP SP ACE aber P SP ACE EXP SP ACE.<br />
4 Nichtdeterminismus<br />
Determinismus:<br />
ist die Eindeutigkeit des Nachfolgezustands.<br />
Hier: angelischer Nichtdeterminismus, also die Fähigkeit zum richtigen Raten (Gegenteil: dämonisch).<br />
Logische/Spieltheoretische Analogie: Angelisch = ∃ = Player. Dämonisch = ∀ = Opponent.<br />
Syntax: GOTO-ähnliche Sprache: l : goto l 1 orl 2<br />
Dann p ⊢ (l,σ) → (l 1 ,σ) und p ⊢ (l,σ) → (l 2 ,σ)<br />
WHILE: C ::= ....| choose C 1 or C 2 mit<br />
C i ⊢ σ → σ ′<br />
choose C 1 or C 2 ⊢ σ → σ ′ i = 1,2<br />
Definition 4.1: Eine Berechnung ist eine Sequenz <strong>von</strong> Zustandsübergängen durch ein Programm<br />
p ⊢ s 1 → s 2 → ... → s t . Diese heißt akzeptierend, wenn p = I 1 ,...,I m bei s t = (m + 1,σ)<br />
und Readout(σ) = true. p akzeptiert d, wenn eine akzeptierende Berechnung p ⊢ Readin(d) →<br />
... → s t existiert. Die Menge der akzeptierenden Zustände: Acc(p) = {d | p akzeptiert d}<br />
29
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
WHILE: p = read(X); C; write Y<br />
p(d) = {e ∈ D | ∃σ.C ⊢ [X → d] → σ,σ(Y ) = e}<br />
Acc(p) = {d | true ∈ p(d)}<br />
Beispiel 4.2: Pfadsuche. Problem: Gegeben ist ein gerichteter Graph G = (V ,E) und zwei<br />
Knoten s,t ∈ V . Entscheide, ob s → ∗ t gilt.<br />
Format: G = ( (u 1 .v 1 )<br />
}{{}<br />
Kante u 1 →v 1<br />
...(u n .v n )) ∈ D<br />
read S, T, G;<br />
W := S;<br />
while W != T do<br />
Copy := G;<br />
while Copy do (* wähle irgendeine Kante Edge *)<br />
choose Copy := tl Copy;<br />
or { Edge := hd Copy; Copy := nil }<br />
if W = hd Edge then W := tl Edge;<br />
write true;<br />
Definition 4.3:<br />
GOTO - ähnlich:<br />
Zeit/Platzverbrauch bei Nichtdeterminismus.<br />
time p (d) = min{t | ∃p ⊢ Readin(d) → ... → s t akzeptierend}<br />
Für eine Berechnung C = p ⊢ (l 1 ,σ 1 ) → ... → (l t ,σ t ) gilt |C| = max{|σ 1 |,...,|σ t |}. Es gilt:<br />
WHILE: C ⊢ σ → t σ ′ mit<br />
space p (d) = min{|C| | C = p ⊢ Readin(d) → ... → s t akzeptierend}<br />
C i ⊢σ→ t σ ′<br />
choose C 1 or C 2 ⊢σ→ t σ ′ i = 1,2<br />
time p (d) = min{t | ∃σ.C ⊢ [X → d] → t σ,σ(Y ) = true} (p = read X; C; write Y )<br />
space ähnlich.<br />
30
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Definition 4.4:<br />
Nichtdeterministische Klassen.<br />
NP T IME L = {Acc(p) | ∃ polynom f : ∀d.time p (d) ≤ f (d)}<br />
NP SP ACE L = {Acc(p) | ∃ polynom f : ∀d.space p (d) ≤ f (d) }<br />
NLOGSP ACE L = {Acc(p) | ∃k : ∀d.space p (d) ≤ k log|d| }<br />
Proposition 4.5:<br />
(i) NP T IME ist robust (TM, SRAM, GOTO, WHILE)<br />
(ii) NP SP ACE T M = NP SP ACE SRAM = NP SP ACE GOT O = NP SP ACE CM<br />
(iii) NLOGSP ACE T M = NLOGSP ACE CM<br />
Der Beweis ist wie bisher.<br />
Proposition 4.6:<br />
P T IME ⊆ NP T IME,P SP ACE ⊆ NP SP ACE,LOGSP ACE ⊆ NLOGSP ACE<br />
5 Die Backbone - Hierarchie<br />
Lemma 5.1: Normalisierung <strong>von</strong> Nichtdeterministischen TMs.<br />
TM q heißt Normalisierung, wenn<br />
(i) q akzeptiert d, gdw. q eine Berechnung der Form q ⊢ Readin(d) → ... → (m,σ) →<br />
(m,σ)... (q bleibt nicht stehen) mit Arbeitsband <strong>von</strong> σ = ...BB1BBB...<br />
(ii) p hat eine nicht-akzeptierende terminierende Berechnung für Eingabe d gdw. q eine Berechnung<br />
der Form q ⊢ Readin(d) → ... → (m−1,σ) → (m−1,σ)... mit σ = ..BB0BBB...<br />
(iii) Zeitverbrauch <strong>von</strong> q bei Erreichen <strong>von</strong> m bzw. m − 1 ist nur linear größer als der <strong>von</strong> p.<br />
Der Platzverbrauch bleibt gleich.<br />
Jedes p hat eine Normalisierung.<br />
Beweis<br />
(a) am Ende Band aufräumen<br />
(b) am Ende Instruktionen m − 1 : if 2 0 then GOT O m − 1 und m : (if 2 1 then) GOT O m<br />
Zu (a): Bandgröße mitprotokollieren → log. Overhead des Platzes. Zeit zum Löschen = O(P latz) =<br />
O(Zeit).<br />
31
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
<strong>zur</strong> Normalisierung:<br />
• Variante A: Σ ′ = Σ ∪ {X}. X ist die beiseitige Bandendemarkierung. → linearer Overhead<br />
bei Zeit. Σ ′ nach Σ kodieren: linearer Platzverbrauch.<br />
• Variante B: Bei bekannter Platzschranke f , f konstruierbar in Platz f (n) − 1.<br />
– f (|d|) hinter Ausgabe aufs Band als Cnt<br />
– Cnt nach rechts schieben; Cnt := Cnt − 1, dabei Band löschen<br />
– Ende bei Cnt = 0<br />
– 0 löschen<br />
– zum Bandanfang fahren<br />
– ohne Platzverbrauch<br />
Zustandsgraphen<br />
Definition 5.2: Gegeben TM p, Eingabe d: Eine Konfiguration (l,i,j,W ) besteht aus einem<br />
Label l, einem Arbeitsbandinhalt W ∈ Σ∗, einem i und j, die Kopfpositionen auf Eingabe- bzw.<br />
Arbeitsband.<br />
Zustandsgraph: G p (d) = gerichteter Graph (V ,E,v 0 ,v end ) mit V = V p (d) = Menge der Konfigurationen<br />
für p,d und E = E p (d) = {(C 1 ,C 2 ) | p ⊢ C 1 → C 2 } und v 0 = (1,0,0,())) und<br />
v end = (m,0,0,1)<br />
Observation: p akzeptiert d ⇔ v 0 → ∗ v end in G p (d).<br />
Definition 5.3: TM p ist f - beschränkt, wenn ∀d und für jede <strong>von</strong> v 0 erreichbare Konfiguration<br />
C = (l,i,j,W ) ∈ V p (d) gilt: |f | ≤ f (|d|) + 1<br />
→ Jedes erreichbare C ∈ V p (d) braucht Platz O(f (|d|))<br />
Erreichbarkeint in Graphen: Problem GAP (graph accessability problem).<br />
Eingabe: gerichteter Graph G = (V ,E,v 0 ,v end ) (als Liste <strong>von</strong> Knoten + Liste gerichteter Kanten<br />
(= Paare <strong>von</strong> Knoten) + 2 Kanten).<br />
Ausgabe: true wenn v 0 → ∗ v end in G.<br />
32
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Satz 5.4:<br />
GAP ∈ NLOGSP ACE. Algorithmus:<br />
w := v0<br />
while w != vend do<br />
choose w->x in E<br />
w := x<br />
write true<br />
Platz ≤ 2log(n). Gespeichert wird nur w und x.<br />
Komplemente: zu C <strong>von</strong> Problemen sind coC = {A | {0,1} ∗ − A ∈ C}. Wenn C deterministisch<br />
ist folgt C = coC (Antwort umdrehen).<br />
Satz 5.5: GAP ∈ NLOGSP ACE.<br />
Beweis: z.Z.: {0,1} ∗ − GAP ∈ NLOGSP ACE. Setze n i = #{u | v 0 → ≤i u}<br />
(v 0 → ≤i u ⇒ v 0 → ... → u)<br />
}{{}<br />
Nebenbemerkung: v 0 → ∗ v end ⇔ v 0 → ≤|V |−1 v end<br />
Algo 1: entscheide v 0 ↛ ∗ v end , wenn n |V |−1 = k<br />
≤i Knoten<br />
NoPath = true; Cnt := 0;<br />
for z = 1 to |V| do<br />
choose skip or (* z nicht erreichbar *)<br />
if v0 ->* z; (* NLOGSPACE *)<br />
then Cnt := Cnt - 1;<br />
if z = vend then NoPath := false;<br />
else abort; (* abort = while true do skip *)<br />
if Cnt != k then abort;<br />
write NoPath;<br />
Termination: genau die erreichbaren Knoten geraten.<br />
Platz: NoPath (O(1)), z(O(log(n))), Cnt(O(log(n))), v 0 → ∗ z (O(log(n))). Bleibt iterative Berechnung<br />
<strong>von</strong> n |V |−1 .<br />
n 0 = 1, dann n i = n aus n i−1 = k<br />
Nebenbemerkung: Für i ≥ 1, v 0 → ≤i z ⇔ ∃w : v 0 → ≤i−1 w,w → z<br />
33
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
n := 0<br />
for u := 1 to |V| do<br />
Cnt := 0; Foundu := false;<br />
for w := 1 to |V| do<br />
choose skip or<br />
if v0->w (u then Foundu = true<br />
else abort<br />
if Cnt != k then abort<br />
if Foundu = true then n := n + 1<br />
Platz: v 0 → ≤i−1 w, O(log(n)) (mit zusätzlichem Zähler). n,k,Cnt,w,n O(log(n)), Foundu:<br />
O(1).<br />
Band aufräumen:<br />
• ohne space overhead<br />
• bei unbekanntem Platzverbrauch<br />
• Nicht deterministisch löschen!<br />
• m − 2: choose {right 2 ; write 2 B; goto m − 2} or skip<br />
Definition 5.8: Für f : N → N ist der f-beschränkte Zustandsgraph Gp f (d) der vom Knoten<br />
C mit |C| ≤ f |d| aufgespannte Untergraph <strong>von</strong> G p (d).<br />
Erinnerung: GAP = {(N,E,v 0 ,v end ) | v 0 → ∗ v end }, GAP ∈ LOGSP ACE und<br />
GAP ∈ coNLOGSP ACE<br />
Satz 5.6: GAP ∈ P T IME<br />
Beweis, Tiefensuche:<br />
proc Main {read V ,E,v 0 ,v end<br />
for v ∈ V do Seen[v] := false;<br />
Probe(v 0 );<br />
write Seen[v end ]<br />
}<br />
proc Probe(v) {<br />
34
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
if not Seen[v] then<br />
Seen[v] := true;<br />
for all v → v ′ ∈ E do Probe(v ′ );<br />
}<br />
Zeit: ≤ |v| Aufrufe <strong>von</strong> Probe, jeweils in Zeit O(|E|).<br />
Overhead durch Rekursion: implementiere Stack auf TM, das gibt polynomiellen Overhead.<br />
Satz: GAP ∈ LOG 2 SP ACE = ⋃ h SP ACE(h(logn)2 )<br />
Algorithmus: Divide-and-Conquer.<br />
Path(v 0 ,v end ,|V |)<br />
Path(v,w,l)= (* teste v → ≤l v end *)<br />
if l = 0 then return ’v = w’<br />
if l = 1 then return ’v → w’<br />
for u ∈ V do<br />
l ′ = l div 2<br />
if Path(v,u,l ′ ) & Path(u,w,l − l ′ )<br />
then return true<br />
return false<br />
Platz: Stack mit Tiefe O(logn). Frame: v,w,l,u,Rücksprungadresse: O(logn) ⇒ O((logn) 2 )<br />
Definition:<br />
f platzkonstruierbar ⇔ f berechenbar in Platz O(f (n))<br />
Lemma 5.9: f ≥ log und platzkonstruierbar, p ein Programm. ⇒ Gp f (d) berechenbar in Zeit<br />
⋃<br />
l cf |d| und Platz O(f |d|).<br />
Beweis:<br />
• Berechne f |d|, Platz O(f |d|), Zeit 2O(f |d|)<br />
• erzeuge Knoten mit for-Schleife, Platz O(f |d|), Zeit 2O(f |d|)<br />
• erzeuge Kanten mit for-Schleife durch alle Knotenpaare (C 1 ,C 2 ) (neu generieren). Schreibe<br />
(C 1 ,C 2 ) aufs Ausgabeband, wenn p ⊢ C 1 → C 2 .<br />
}{{}<br />
Gesamtzeit: (2 O(f |d|) ) 2 · O(|d| k ) = O(2 O(f |d|) )<br />
Gesamtplatz: O(f |d|)<br />
poly. Zeit, Platz linear<br />
35
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Satz 5.10: f ≥ log platzkonstruierbar. ⇒ NSP ACE(f (n)) ⊆ ⋃ c T IME(cf (n) )<br />
Beweis: Sei p ∈ nspace(f (n)), Entscheide d ∈ Acc(p) in time(c f |d| ):<br />
• Berechne G f p (d) (Zeit 2 O(f |d|) )<br />
• Entscheide G f p (d) ∈ GAP (Zeit ploynomiell in 2 O(f |d|) , also 2 O(f |d|) , nach Satz 5.6)<br />
Korollar:<br />
Beweis:<br />
NLOGSP ACE ⊆ P T IME<br />
NSP ACE(k logn) ⊆ T IME(c k logn ) = T IME(n k logn ) ⊆ P T IME<br />
Satz 5.12 (Savitch): f ≥ log platzkonstruierbar ⇒ NSP ACE(f (n)) ⊆ ⋃ c SP ACE(cf (n)2 )<br />
Beweis: Sei p ∈ nspace(f (n)), entscheide d ∈ Acc(p) in SP ACE(cf (n) 2 )<br />
• Berechne f , Gp f (d), Platz O(f |d|), Knoten r = 2O(f |d|)<br />
Konstruktion platzbeschränkter Funktionen wie für logspace.<br />
• Entscheide G f p (d) ∈ GAP in Platz O((logr) 2 ) = O((f |d|) 2 )<br />
Korollar 5.13: P SP ACE = NSP ACE = coNP SP ACE<br />
}{{}<br />
(2)<br />
Beweis:<br />
<strong>von</strong> (2): coNP SP ACE = coP SP ACE = P SP ACE = NP SP ACE<br />
Satz 5.14 (Immerman):<br />
NP SP ACE(cf (n))<br />
⋃<br />
c<br />
f ≥ log platzkonstruierbar. ⇒ coNP SP ACE(f (n)) ⊆<br />
Korollar 5.15:<br />
NLOGSP ACE = coNLOGSP ACE<br />
Beweis:<br />
Sei p ∈ nspace(f (n)), entscheide d Acc(p) in nspace(cf (n)).<br />
• Berechne f , Gp f (d), Platz O(f |d|), Knoten r = 2O(f |d|)<br />
• Entscheide G f p (d) GAP in Platz O(logr) = O(f |d|)<br />
36
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Zusammenfassend:<br />
LOGSP ACE ⊆ NLOGSP ACE ⊆ P T IME ⊆<br />
}{{}<br />
=coNLOGSP ACE<br />
⊆ NP T IME/coNP T IME ⊆ P SP ACE = NP SP ACE ⊆ EXP T IME<br />
}{{}<br />
6 Vollständigkeit<br />
LOGSP ACE P SP ACE<br />
=coNP SP ACE<br />
NLOGSP ACE P SP ACE<br />
P T IME EXP T IME<br />
Vollständiges Problem für C = ’schwieriges’ (engl. hard) Problem in C. D.h. für A ⊆ {0,1} ∗<br />
C-vollständig ist zu Zeigen:<br />
(a) A ∈ C, ’obere Schranke’, A ist C-hart<br />
(b) B ∈ C, A ist ’härter’ als B, ’untere Schranke’<br />
’härter als’ ist definiert per Reduktion (engl. reduction from ...).<br />
Beispiel: CLIQUE ≥ SAT mit CLIQUE = {(G,k) | G hat eine k-Clique}. G ist ungerichtet.<br />
K ⊆ V und (G = (V ,E)), k-Clique, falls #K = k und ∀u,v ∈ K,{u,v} ∈ E.<br />
SAT = {ϕ CNF | ϕ erfüllbar}, CNF endliche Konjugation <strong>von</strong> Klauseln. Klausel ist eine endliche<br />
Disjunktion <strong>von</strong> Literalen. Literal ist <strong>von</strong> der Form A | ¬A.<br />
Valuation: κ : V ars(ϕ) → {T ,F}, ϕ erfüllbar ⇔ ∃κ,κ(ϕ) = T<br />
Bekannt: SAT NP-Vollständig, klar: CLIQUE ∈ NP T IME.<br />
Reduktion: SAT → CLIQUE: Gegeben ϕ = (a 11 ∨ ... ∨ a 1n1 ) ∧ ... ∧ (a k1 ∨ ... ∨ a knk )<br />
Konstruiere (G,k) mit V = Menge der Vorkommen <strong>von</strong> Literalen in ϕ = {(i,j) | i ∈ {1,...,k},j ∈<br />
{1,...,n i }}<br />
{(i 1 ,j 1 ),(i 2 ,j 2 )} ∈ E ⇔ i 1 i 2 ∧ a i1 j 1<br />
¬a i2 j 2<br />
Beispiel: ϕ = (A ∨ ¬B) ∧ (B ∨ C) ∧ (¬A ∨ ¬C)<br />
3-Clique {A,B,¬C} ̂= [A → T ,B → T ,C → F] = κ, κ(ϕ) = T<br />
Formal: z. Z. ϕ erfüllbar, genau dann wenn G eine k-Clique hat.<br />
′ ⇒ ′ Sei κ(ϕ) = T , dann existiert ∀i ∈ {1,...,k}j i ∈ {1,...,n i } mit κ(a ij ) = T , dann ist {(i,j) | i =<br />
37
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
1,...,k} k-Clique.<br />
′ ⇐ ′ Sei k ∈ V eine k-Clique ⇒ k = {(1,j 1 ),...,(k,j k )}. Wähle κ mit κ(a iji ) = T für alle i. (geht,<br />
da nie a i1 j i1<br />
= ¬a i2 j i2<br />
), κ(ϕ) = T .<br />
Definition 6.1 (Reduktion):<br />
F = ptime), A,B ⊆ {0,1} ∗ .<br />
F Klasse <strong>von</strong> Funktionen {0,1} ∗ → {0,1} ∗ (z.B. F = logspace,<br />
A ≤ F B ⇔ ∃f ∈ F , A = f −1 [B]<br />
(d.h. d ∈ A ⇔ f (d) ∈ B ).<br />
C sei eine Klasse <strong>von</strong> Problemen, dann gilt B ist F -vollständig für C ⇔<br />
(a) B ∈ C<br />
(b) B ist F -hart für C<br />
d.h. ∀A ∈ C gilt A ≤ F B.<br />
Kurznotation: C-vollst., C-hart.<br />
→ Sinnvoll, wenn C nach unten abgeschlossen unter ≤ F ist, d.h. B ∈ C ∧ A ≤ F B ⇒ A ∈ C<br />
z.B. C = P T IME, F = logspace oder C = NLOGSP ACE, F = logspace oder C = NP T IME, F =<br />
ptime.<br />
Lemma 6.2: Wenn C ⊆ D, C nach unten abgeschlossen unter ≤ F und A F - vollständig für<br />
D, dann gilt A ∈ C ⇔ C = D.<br />
Beweis: ′ ⇐ ′ trivial.<br />
′ ⇒ ′ : Sei B ∈ D, z.Z. B ∈ C. es reicht B ≤ F A √<br />
Lemma 6.3: A F - hart für C, A ≤ F B ⇒ B F -hart für C.<br />
Lemma 6.4: Wenn C komplementabgeschlossen ist (A ∈ C ⇒ {0,1} ∗ − A ∈ C), dann folgt A<br />
F -vollständig für C ⇒ {0,1} ∗ − A F -vollständig für C.<br />
Beweis: Sei B ∈ C, z.Z. B ≤ F {0,1} ∗ − A. Es gilt: {0,1} ∗ − B ≤ F A, d.h. es existiert f ∈ F mit<br />
d ∈ {0,1} ∗ − B ⇔ f (d) ∈ A<br />
d.h.<br />
und damit B ≤ F {0,1} ∗ − A.<br />
d ∈ B ⇔ f (d) ∈ {0,1} ∗ − A<br />
38
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Satz 6.5: GAP ist logspace-vollständig für NLOGSP ACE.<br />
Beweis: GAP ∈ NLOGSP ACE → siehe oben.<br />
Härte: Sei A ∈ NLOGSP ACE, z.Z. A ≤ logspace GAP .<br />
A = Acc(p) für ein p ∈ nspace(k logn). Setze f (d) = Gp<br />
k logn (d). f ist eine Reduktion <strong>von</strong> A<br />
nach GAP : d ∈ A ⇔ d ∈ Acc(p) ⇔ Gp<br />
k logn (d) ∈ GAP .<br />
}{{}<br />
Platz für f : O(logn) nach Lemma 5.9.<br />
=f (d)<br />
Korollar: GAP ∈ LOGSP ACE ⇔ LOGSP ACE = NLOGSP ACE.<br />
Beweis: LOGSP ACE nach unten abgeschlossen unter ≤ logspace wg. Abgeschlossenheit <strong>von</strong><br />
logspace unter Komplement.<br />
Beweis: ≤ F ist transitiv, da F Konkatenationsabgeschlossen ist.<br />
Sei C ∈ C, dann zeige C ≤ F A. Weil B F -hart für C, gilt: C ≤ F B.<br />
Satz 6.6: REG ∅ = {G reguläre Grammatik | L(G) ∅} ist logspace-vollständig für NLOGSP ACE,<br />
wobei G = (N,T ,P ,S).<br />
Beweis: REG ∅ ∈ NLOGSP ACE für REG ∅ ≤ logspace GAP .<br />
Gegeben: G = (N,T ,P ,S), dazu ein definierter Graph f (G) = (V ,E,S,v end ) mit V = N ∪ T ∪<br />
{ɛ} ∪ {v end } und<br />
E = {(N 1 ,N 2 ) | ∃a ∈ T ,N 1 ::= aN 2 ∈ P } ∪ {(N,a) | N ::= a ∈ P } ∪ {(N,ɛ) | N ::= ɛ ∈ P }...<br />
Es gilt: G ∈ REG ∅ ⇔ S → ∗ ɛ oder ∃a ∈ T S → ∗ a also f (G) ∈ GAP .<br />
f braucht nur Zähler, also f ∈ logspace ⇒ REG ∅ ≤ logspace GAP ⇒ REG ∅ ∈ NLOGSP ACE.<br />
Härte: GAP ≤ logspace REG ∅ .<br />
Gegeben: H = (V ,E,v 0 ,v end ). Definiere Grammatik G = f (H) durch N = V ,T = {a},P =<br />
{A ::= aB | A → B ∈ H} ∪ {v end ::= ɛ},S = v 0 . Das a ist hier nur ein Dummy und wird nicht<br />
benötigt (sonst wäre es keine reg. Grammatik).<br />
L(G) ∅ ⇔ v 0 → ∗ v end , d.h. f (G) ∈ GAP . f braucht nur Schleifenzähler, also f ∈ logspace.<br />
6.1 PTIME - Vollständigkeit<br />
Entspricht einem Mangel an effizienter Parallelisierbarkeit.<br />
39
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Definition 6.7: Boolesche Programme. BOOLE:<br />
Programme q = I 1 ,...,I m . I ::= X := E | I 1 ;I 2 | goto l | if E then I 1 else I 2<br />
E := X | true | f alse | E 1 ∧,∨,⇒,⇐ E 2 | ¬E. Semantik wie erwartet, aber keine Eingabe.<br />
q ↓: q terminiert, q ↑: q terminiert nicht.<br />
q: Wert der letzten Zuweisung, falls q terminiert, ⊥ (undef.) sonst.<br />
Anfangszustand: alle Variablen sind am Anfang f alse.<br />
Untersprachen: SBOOLE, sequentielles BOOLE. Definiert durch Ausschluss <strong>von</strong> goto.<br />
Also nicht Turingvollständig.<br />
MCIRCUIT (monotones BOOLE, monotone Schaltkreise). I ::= X := Y | X := true | X :=<br />
Y ∨,∧Z.<br />
q heißt einfach zuweisend, genau dann, wenn jede Variable X in höchstens einem X := E in<br />
q vorkommt.<br />
Größe: |q|: 1 für jedes Token (;, :=, if, 1). 1 + ⌈log(i + 1)⌉ für Var X i .<br />
Zentrales Problem: SBOOLE − COMP = {q ∈ SBOOLE | q = true}.<br />
Lemma 6.8: SBOOLE − COMP ∈ P T IME.<br />
Beweis: q ∈ SBOOLE hat zunächst polynomielle Laufzeit in |q|. Interpretation auf TM gibt<br />
polynomiellen Overhead.<br />
Lemma 6.9: Sei p ∈ ptime T M . Dann existiert f ∈ logspace mit ∀d : p(d) = true ⇔<br />
f (d) ∈ SBOOLE − COMP .<br />
Satz 6.10:<br />
SBOOLE − COMP ist logspace-vollständig für P T IME.<br />
Beweis: Sei A ∈ P T IME. Zu zeigen: A ≤ logs SBOOLE − COMP . Es existiert p ∈ ptime,<br />
es gilt: p(d) = true ⇔ d ∈ A. Sei f wie in Lemma 6.9, dann gilt: d ∈ A ⇔ p(d) = true ⇔<br />
f (d) ∈ SBOOLE − COMP .<br />
Beweis Lemma 6.9:<br />
Sei p ∈ I 1 ,...,I m ∈ time(π(n)), π Polynomiell. Konstruiere f (d) mit<br />
40
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Variable Bedingung Indizes<br />
L l Prog.-Zähler = l 1 ≤ l ≤ m + 1<br />
Ti a Zelle i enthält a ∈ Σ a ∈ Σ,−π(n) ≤ i ≤ π(n)<br />
Anzahl Variablen gesamt: 6π(n) + 4. Und: i beginnt bei Kopfposition = 0.<br />
T i := a ≡ (Ti 0 := f alse,Ti<br />
1 := f alse,Ti<br />
B := f alse,Ti<br />
a := true)<br />
T i := T j ≡ (Ti 0 := Tj 0 ,T i 1 := Tj 1 ,T i<br />
B := Tj B )<br />
Right(r) = (T −r := T −r+1 ,...,T r−1 := T r ,T r := B)<br />
Lef t(r) = (T r := T r−1 ,...,T −r+1 := T −r ,T −r := B)<br />
Dann f (a 1 ,...,a n ) = T 1 := a 1 ,...,T n = a n ,T n+1 = B,...,T π(n) = B,T 0 = B,...,T −π(n) = B<br />
L 1 = true; Makro: ST EP ,...,ST EP . T 1<br />
}{{}<br />
1 := T 1 1.<br />
π(n)−mal<br />
Zu Step: ST EP = if l 1 then I 1 else if l 2 then... if L m then I m<br />
Simulation <strong>von</strong> Instruktionen:<br />
I l<br />
I l<br />
right<br />
Right(π(n));L l := f alse;L l+1 := true<br />
left<br />
analog<br />
write a<br />
T 0 := a;L l := f alse;L l+1 := true<br />
if a goto l 1 else l 2 L l := f alse;L l1 := T0 a;L l 2<br />
:= ¬T0<br />
a<br />
Korrektheit der Bandrepräsentation: Beschriebene Zellen sind nie weiter als π(n) <strong>von</strong> der Kopfposition<br />
entfernt.<br />
Noch zu Zeigen: f ∈ logspace.<br />
Initialisierungscode per Schleife: Zähler läuft <strong>von</strong> −π(n) bis +π(n), Platz O(logn). ST EP :<br />
Zähler <strong>von</strong> 1,...,m in Platz O(1). I l hat Zähler <strong>von</strong> −π(n) bis +π(n) in Platz O(logn). π(n) -<br />
mal ST EP : Zähler, O(logn), insgesamt also f ∈ logspace.<br />
Monotone Schaltkreise<br />
Lemma 6.11: Es exisitiert f ∈ logspace,f : SBOOLE → MCURCUIT mit f (p) = p<br />
und f (p) ist einfach zuweisend.<br />
Satz 6.12: MCURCUIT − COMP := SBOOLE − COMP ∩ MCURCUIT ist P T IME -<br />
vollständig, sogar noch für MCURCUIT ≤a (MCURCUIT mit einfacher Zuweisung).<br />
41
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Schrittweise Reduktion. p n → q 1 → q 2 → q 3 → q 4 Semanti-<br />
Beweis des Lemma 6.11:<br />
kerhaltend.<br />
(a) Z := E in q 1 ⇒ E ::= X | true | X∨,∧Y | ¬X<br />
if E... in q n ⇒ E ::= X<br />
Konstruktion: Ersetze f alse durch uninitialisierte Variablen. Ersetze komplexe Terme durch<br />
Folgen <strong>von</strong> Zuweisungen, wie z.B.: X := (Y ∧ Z) ∨ (W ∧ Z) wird zu U 1 = Y ∧ Z,U 2 =<br />
W ∧ Z,X = U 1 ∨ U 2 .<br />
⇔,⇒ ersetzen durch ∧,∨,¬, z.B.: X ⇒ Y ≡ ¬X ∨ Y .<br />
Die Reduktion in logspace: Vermeide echte Rekursion mit linear tiefem Stack. Schachtelungstiefe<br />
per Zähler verfolgen, in etwa: Gesamttiefe messen (2 Zähler), Tiefste Ebene<br />
übersetzen (zählen), zweittiefste Ebene übersetzen (zählen), usw. Konstant viele Zähler, jeweils<br />
O(logn).<br />
(b) Kein if (also auch kein ; mehr) in q 2 : q 1 = I 1 ,...,I m ⇒ q 2 = GO := true,I 1 ,...,I m<br />
• if U then I else J = V := U;S := GO;GO := S ∧ V ;I;GO := S ∧ ¬V ; J;GO := S<br />
mit S,V frisch.<br />
• I,J = I;J<br />
• X := E = X := (E ∧ G) ∨ (X ∧ ¬GO)<br />
in logspace: Vermeide echte Rekursion mit Stack aus lineare vielen S. Stattdessen durchnummerierung:<br />
S = S 1 ,S 2 ,S 3 ,... Schachtelungstiefe der if s mitzählen und der aktuellen<br />
Tiefe entsprechend S verwenden.<br />
(c) Idee: führe ¬X als Var X ′ mit q 2 = I 1 ,...,I m . V ars(q 2 ) = {X 1 ,...,X k }.<br />
Dann: q 3 = X ′ 1 := true,...,X′ k := true,I 1,...,I m mit<br />
• X := true := X := true,X ′ := S,S frisch.<br />
• X := Y := X := Y ,X ′ := Y ′<br />
• X := Y ∧ Z := X := Y ∧ Z,X ′ := Y ′ ∨ Z ′<br />
• X := Y ∨ Z := X := Y ∨ Z,X ′ := Y ′ ∧ Z ′<br />
• X := ¬Y := T := Y ,X := Y ′ ,X ′ := T<br />
• X Y := X := Y ′ ,X ′ := Y<br />
Platz: Zähler 1,...,k für Präfix: O(logk), Übersetzung I → I in O(logk) (für V ar-Indices)<br />
und Programmzähler 1,...,n in O(logn)<br />
Verschärfung: q einfach zuweisend, wenn<br />
• jede Variable X taucht in q höchstens in einer Zuweisung X := E auf.<br />
42
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
• wenn in q eine Zuweisung X := E vorkommt und Y ∈ V ars(E), dann gilt:<br />
– q enthält Y := F vor X := E<br />
– q enthält keine Zuweisung an Y<br />
(d) Konstruiere q 4 einfach zuweisend (q 4 = q 3 ). Sei q 3 = I 1 ,...,I m , dann ist q 4 = I 1 ,...,I m<br />
mit<br />
• l : X := E = X l := E l mit X 1 ,...,X l (alle verschieden, l frisch)<br />
E l aus E durch Ersetzen der in E vorkommenden Variable Y .<br />
• suche in q 3 ab l rückwärts nach k : Y := D<br />
• ersetze Y durch X k , wenn gefunden<br />
Platz: Braucht nur Pointer (für das aktuelle l) und für die Rückwärtssuche und Variablenindizes<br />
⇒ O(logn)<br />
Horn - SAT<br />
Definition 6.12:<br />
Eine positive Hornklausel ist eine aussagenlogische Formel der Form<br />
C = A 1 ∧ ... ∧ A n → A 0<br />
mit A 0 ,...,A n ∈ V (Aussagenvariablen). Eine positive Hornform ist eine Konjunktion H <strong>von</strong><br />
positiven Hornklauseln.<br />
H |= A ⇔ ∀κ : V → {T ,F}<br />
Wenn κ(H) = T gilt: κ(A) = T .<br />
Bsp.: (A ∧ B → C) ∧ (A ∧ C → D) ∧ (A → B) ∧ (A) ≡ H, ⇒ H |= D<br />
Wenn H |= A, dann gilt H ∧ ¬A ist unerfüllbar.<br />
Problem: pHorn = {(H,A) | H |= A}<br />
Satz 6.13:<br />
pHorn ist P T IME-vollständig.<br />
Bemerkung 6.14: Allgemeiner kann man Erfüllbarkeit <strong>von</strong> (nicht notwendigerweise positiven)<br />
Hornformen betrachten, d.h. Konjunktionen <strong>von</strong> Hornklauseln wie A 1 ∧...∧A n → A 0 oder<br />
A 1 ∧ ... ∧ A n → ⊥.<br />
43
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Problem: HORN = {H Hornform | H erfüllbar } ist auch P T IME-vollständig. Obere Schranke<br />
wie in Satz 6.13, untere Schranke aus Satz 6.13.<br />
Beweis <strong>von</strong> Satz 6.13: Obere Schranke: Boolesches Array M[V ars(H,A)] <strong>von</strong> Markierungen<br />
wird auf f alse initialisiert.<br />
while applicable (* "solange wir können" *)<br />
pick A1 and ... and An -> A0 in H with<br />
M[A1] = true & ... & M[An] = true & M[A0] = false<br />
M[A0] = true<br />
return M[A]<br />
Schleifendurchläufe ≤ #Klauseln in H. Einzelner Schleifendurchlauf: lineare Suche durch H.<br />
Anwendungsbedingung: Schleife 1,...,n linear.<br />
Insgesamt also ptime.<br />
Zu zeigen: Algo antwortet true, gdw. H |= A.<br />
” ⇒ ” Invariante ∀V ∈ V ars(H,A),[B] = true ⇒ H |= B<br />
” ⇐ ” Algo antwortet f alse. Lies M als Valuation. Dann M(H) = true wenn<br />
C = A 1 ∧ ... ∧ A n → A 0 in H mit M(A 1 ) = true&...&M(A n ) = true, dann M(A 0 ) = true, weil<br />
die Schleife beendet wurde.<br />
Aber M(A) = f alse, folglich H ̸|= A<br />
Untere Schranke: Reduktion <strong>von</strong> MCURCUIT − COMP mit Einfachzuweisung.<br />
Sei q ∈ MCURCUIT , einfachzuweisend. q = 1 : X 1 := E 1 ,...,n : X n := E n wobei alle<br />
X 1 ,...,X n verschieden sind. Dann ist f (q) = (H,X m ) mit H ist eine Konjunktion <strong>von</strong> Hornklauseln<br />
• → X für X := true in q<br />
• Y → X für X := Y in q<br />
• Y ∧ Z → X für X := Y ∧ Z in q<br />
• Y → X,Z → X für X := Y ∨ Z in q<br />
Offenbar ist f ∈ logspace.<br />
44
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Sei q ⊢ (1,σ 0 ) → ... → (m + 1,σ m ), dann ist zu zeigen, dass<br />
f (q) ∈ pHORN<br />
}{{}<br />
H|=X m<br />
⇔ q ∈ MCURCUIT − COMP<br />
}{{}<br />
σ m (X m )=T<br />
Zeige per Induktion: H |= X i ⇔ σ i (X i ) = T .<br />
Der Schritt geht <strong>von</strong> k < i → i. Das heißt wir nehmen an, dass es für alle i < k schon gilt und<br />
zeigen es für i: Fallunterscheidung nach E i .<br />
• E i = true: Dann ist σ i (X i ) = T und H |= X i , da → X i in H<br />
• E i = Y ,Y {X 1 ,...,X m }: Dann ist σ i (X i ) = F und ...<br />
Beweis: Sei κ(V ) = F für alle Variablen V {X 1 ,...,X n },κ(X i ) = T mit (i =<br />
1,...,m). Insbesondere ist κ(Y ) = F. κ(H) = T . Also H ̸|= X i (per κ wie oben,<br />
Valuation κ(X i ) → F).<br />
... H ̸|= X i , Gegenbeispiel: κ(X j ) = T für j i,κ(V ) = F sonst. Dann κ(H) = T : klar für<br />
Klauseln ... → X j ,j i. Ferner auch okay für Y → X i wegen κ(Y ) = F.<br />
• E i = X j : Dann ist j < i. σ i (X i ) = T ⇔ σ i (X j ) = T und ⇔ j
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beweis: obere Schranke per CF ∅ ≤ logspace pHorn.<br />
Produktion N ::= A 1 ,...,A n wird in eine positive Hornklausel H übersetzt A 1 ∧ ... ∧ A n → N.<br />
A 0 ::= ɛ. Zusätzlich werden folgende Axiome hinzugefügt: → a für alle Terminalen a ∈ T . Teste<br />
ob H |= S.<br />
untere Schranke: per pHorn ≤ logspace CF ∅ . Übersetze positive Hornklausel A 1 ∧...∧A n → A 0<br />
in Produktion A 0 ::= A 1 ,...,A n mit n ≥ 0. Bei Test auf H |= A wird A das Startsymbol. Das ganze<br />
gibt jetzt die Grammatik G. L(G) ∅ (dann = {ɛ}) ⇔ H |= A.<br />
Spiele<br />
Ein zwei-Spieler Spiel G = (P 1 ,P 2 ,W 0 ,M) besteht aus folgenden Kompo-<br />
Definition 6.15:<br />
nenten:<br />
• endliche Mengen P 1 ,P 2 <strong>von</strong> Spielerpositionen für Spieler 1 bzw. Spieler 2.<br />
• eine Menge W 0 ⊆ P 1 <strong>von</strong> gewonnenen Positionen für Spieler 1 (das Spiel ist zu Ende und<br />
Spieler 1 gewinnt)<br />
• eine Menge <strong>von</strong> Zügen M ⊆ (P 1 × P 2 ) ∪ (P 2 × P 1 )<br />
Die Menge der Gewinnpositionen für Spieler 1 ist die kleinste Menge W ⊆ P 1 mit W 0 ⊆ W und<br />
∀p 1 ∈ P 1 : (∃(p 1 ,p 2 ) ∈ M : ∀(p 2 ,p 3 ) ∈ M : p 3 ∈ W ) ⇒ p 1 ∈ W<br />
Def.: V 0 ⊆ V 1 ⊆ durch V 0 ∅, V i+1 = F(V i ), Behauptung: W = ⋃ ∞<br />
i=0 V i<br />
Zu Zeigen: ∀i,V i ⊆ V i+1 Induktion: i = 0 trivial.<br />
i → i + 1: F monoton: ∀X,Y ,X ⊆ Y ⇒ F(X) ⊆ F(Y )<br />
V i+1 = F(V i ) ⊆ F(V i+1 ) = V i+1<br />
√<br />
Da P 1 endlich, exisitiert i ≤ |P 1 | mit V i = V i+1 = F(V i ) dann V j = V i ,∀j ≥ i, dann ⋃ ∞<br />
j=0 V j = V i .<br />
Insbesondere F(V i ) ⊆ V i<br />
√<br />
Noch zu Zeigen: kleinster Präfixpunkt. Sei P (Y ) ⊆ Y ⊆ P 1 , zeige V j ⊆ Y durch Induktion:<br />
Fall j = 0 trivial. Fall j → j + 1: V j+1 = F(V j ) ⊆ F(Y ) ⊆ Y √<br />
Das alles braucht nur P 1 endlich, F monoton.<br />
Allgemein: P (W ) ⊆ W bedeutet, dass W Präfixpunkt <strong>von</strong> P ist.<br />
Problem: GAME = {(G = (P 1 ,P 2 ,W 0 ,M),p ∈ P 1 ) | ”p ∈ W ”, Gewinnpos. für Spieler 1 }<br />
Satz 6.16:<br />
GAME ist P T IME - vollständig.<br />
46
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beweis:<br />
Obere Schranke.<br />
V new = ∅<br />
repeat:<br />
V = V new<br />
V new := F(V )<br />
until V = V new<br />
return ”p ∈ V ”<br />
≤ |P 1 | Schleifendurchläufe, poly. Zeit pro Durchlauf, also ptime. Korrektheit nach obigem am<br />
Ende V = Menge der Gewinnpositionen.<br />
Untere Schranke: per pHORN ≤ logspace GAME.<br />
Gegeben: (H,A), konstruiere f (H,A) = (G,A) mit G = (V ar(H,A),<br />
H }{{}<br />
Menge <strong>von</strong> positiven Hornklauseln<br />
M = {(A 0 ,A 1 ∧...∧A n → A 0 ) | A 1 ∧...∧A n → A 0 ∈ H} ∪{(A 1 ∧...∧A n → A 0 ,A i ) | i ∈ {1,...,n}}<br />
Zu zeigen: (G,A) ∈ GAME ⇔ H |= A<br />
” ⇒ ” Zeige F(Y ) ⊆ Y für Y = {B|H |= B}<br />
” ⇐ ” Fasse Gewinnpositionen W ⊆ P 1 = V ar(H,A) als Valuation auf. Zeige W (H) = T<br />
→ offenbar f ∈ logspace.<br />
6.2 NPTIME - Vollständigkeit<br />
P T IME - Urproblem: P T IME − COMP = {(p,d,π) | π poly.,p ∈ ptime(π(n)),p(d) = T }<br />
P T IME - vollständig: obere Schranke. Interpretiere p(d) für π(|d|) Schritte.<br />
Zeit polynomiell in |p|,π(|d|).<br />
Untere Schranke. Sei A ∈ P T IME, dann existiert ein p ∈ ptime(π(n)), π polynomiell, d ∈ A ⇔<br />
p(d) = T . Setze f (d) = (p,d,π), dann d ∈ A ⇔ f (d) ∈ P T IME − COMP .<br />
f ∈ logspace klar.<br />
Wiederholung: P T IME - vollständigkeit <strong>von</strong> pHORN, P T IME − COMP → SBOOLE −<br />
COMP → MCIRCUIT → pHORN<br />
Analoger Plan für NP T IME: NP T IME − COMP = {(p,d,π) | πpoly.p ∈ ntime(π(n)),d ∈<br />
Acc(p)} → SBOOLE − NONT RIV → ... → 3SAT<br />
Triviale Probleme geben immer f alse aus, egal wie die Variablen initialisiert worden<br />
sind. Bei nicht - trivialen Programmen können wir die Variablen so initialisieren,<br />
dass auch true rauskommen kann.<br />
,∅,M)<br />
47
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
SBOOLE−NONT RIV = {q ∈ SBOOLE | ∃Init = (X 1 := b 1 ,...,X n = b n ),b 1 ,...,b n ∈ {true,f alse},<br />
Init,q = T }<br />
Reduktion 1: Gegeben (p,d,π),p ∈ ntime(π(n)). Konstruiere q analog wie für ptime, mit<br />
letzter Instruktion L m+1 := L m+1 und dem nichtdeterministischen<br />
l : goto l 1 or l 2<br />
= L l := f alse;if O t then L l1 = true else L l2 = true<br />
O t ist das Orakel zum Zeitpunkt t, d.h. t − te Kopie <strong>von</strong> ST EP .<br />
V ar(q ′ ) = {X 1 ,...,X k ,O 1 ,...,O π(|d|) }<br />
q = X 1 := f alse,...,X k := f alse,q ′<br />
Dann q ∈ SBOOLE − NONT RIV ⇔ d ∈ Acc(p), q konstruierbar in logspace.<br />
Reduktion 2: Wie bisher, nur ohne if, ←,→, kompl. Ausdrücke, einfache Zuweisungen. Wir<br />
können hier nicht da<strong>von</strong> ausgehen, dass alle Variablen standartmäßig auf f alse stehen. (f alse<br />
wird nicht eleminiert, also kein Bedarf an uninitialisierten Variablen).<br />
Reduktion 3: 3SAT . Wiederholung: 3CNF ist eine Konjugation <strong>von</strong> Klauseln aus je ≤ 3<br />
Literalen. 3SAT = {ϕ 3CNF | ϕ erfüllbar } ∈ P T IME. Obere Schranke trivial.<br />
Untere Schranke: Aus q = I 1 ,...,I m ∈ SBOOLE spezifiziert mit den bekannten Einschränkungen.<br />
Konstruiere 3CNF F mit Klauseln wie bisher, plus<br />
• ¬X für X := f alse in q<br />
• ¬Y → X ≡ Y ∨ X für X := ¬Y in q<br />
F ∈ 3SAT ⇔ q ∈ SBOOLE −COMP und κ(F ) = T ⇔ X 1 := κ(X 1 ),...,X k := κ(X k ),q = T<br />
(Induktion: q tut nichts) mit V ars(q) = {X 1 ,...,X k }, wie im Horn - Fall.<br />
Satz:<br />
3SAT ist logspace-vollständig für nptime.<br />
6.3 PSPACE - vollständigkeit<br />
BOOLE: BOOLE − COMP = {p ∈ BOOLE | p = T }<br />
Satz:<br />
BOOLE − COMP ist logspace - vollständig für P SP ACE.<br />
48
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Beweis: Beachte: BOOLE − COMP ist nicht Turingmächtig, da man Variablen nur boolesche<br />
Werte und keine beliebigen Zahlen geben kann. Man kann keinen zusätzlichen Speicherplatz<br />
anfordern. Folglich ist klar, wie lang es dauert bis das Programm terminiert, wenn es denn<br />
terminiert.<br />
⇒ Wenn p = I 1 ,...,I m ∈ BOOL mit |V ars(p)| = k terminiert, dann in maximal 2 k · m Schritten.<br />
Interpretiere also p mit Timeout 2 k · m, gebe JA <strong>zur</strong>ück, wenn Endzustand (m + 1,σ) und die<br />
letzte Zuweisung true war.<br />
Platz: Wert der letzten Zuweisung: O(1). Zustand: k Variablen + Label l: O(|p|+log|p|) = O(|p|).<br />
Zähler: O(log2 k · m) = O(k + logm) = O(|p|).<br />
Untere Schranke: Sei p ∈ space T M (π(n)), π polynomiell, dann {d | p(d) = T } ≤ logspace BOOLE−<br />
COMP . Zu d ∈ {0,1} ∗ konstruiere f (d) (BOOLE) mit p(d) = T ⇔ f (d) ∈ BOOLE −<br />
COMP .<br />
Analog wie für P T IME:<br />
f (d) = Init; (* d aus Bdg., Rest des Bands leer <strong>von</strong> −π(n) bis π(n) *)<br />
L 1 = true<br />
while ¬L m+1 do STEP<br />
T 1 1 := T 1 1<br />
Korrektheit, logspace wie bisher.<br />
Korollar: BOOLE − T ERM = {p ∈ BOOLE | p ↓} (p terminiert) ist logspace - vollständig<br />
für P SP ACE.<br />
Beweis: Obere Schranke: per BOOLE − T ERM ≤ logspace BOOLE − COMP .<br />
q ∈ BOOLE − T ERM ⇔ q;X := true ∈ BOOLE − COMP .<br />
Untere Schranke: BOOLE −COMP ′ = BOOLE −COMP , eingeschränkt auf letzte Zuweisung<br />
in letzter Zeile. Nach obigen Beweis ist BOOLE − COMP ′ P SP ACE - vollständig.<br />
BOOLE − COMP ′ ≤ logspace BOOLE − T ERM<br />
q;X := E ⇔ q;X := E,m + 1, if ¬X goto m + 1 (linke Seite BOOLE − COMP ′ , rechte Seite<br />
BOOLE − T ERM).<br />
6.4 Quantifizierte Boolesche Formeln<br />
QBF : E ::= X | true | f alse | E 1 ∧ ∨ → E 2 | ¬E, ∀X.E ∃X.E<br />
49
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Valuation κ(∀X.E) = κ(E[X → true]) ∧ κ(E[X → f alse])<br />
κ(∃X.E) = κ(E[X → true]) ∨ κ(E[X → f alse])<br />
Freie Variablen: FV (X) = {X}, FV (true) = FV (f alse) = ∅,FV (E 1 ×E 2 ) = FV (E 1 )∪FV (E 2 ),FV (¬E) =<br />
FV (E) FV (∀X.E) = FV (∃X.E) = FV (E) − {X}<br />
E ist abgeschlossen ⇔ FV (E) = ∅<br />
Def.: QBF − SAT = {E ∈ QBF | ∃κ.κ(E) = true}<br />
Def.: QBT = {E ∈ QBF | E abgeschlossen, E = T } (quantifying boolean truth)<br />
QBT ≼ logspace QBF − SAT ist klar.<br />
QBF−SAT ≼ logspace QBT : E ∈ QBF−SAT (P V (E) = {X 1 ,...,X k }) ⇔ ∃X 1 ,...,∃X k : E ∈ QBT<br />
QBF ist kodierbar in ’normale’ Aussagenlogik. Übersetzung: t.<br />
t(∀X.E) = E[X → true] ∧ E[X → f alse]<br />
t(∃X.E) = E[X → true] ∨ E[X → f alse]<br />
⇒ exponentieller Blowup.<br />
Satz 6.18: QBT ist logspace-vollständig für P SP ACE.<br />
Beweis obere Schranke:<br />
(a) Eleminiere →,∧,∨,↔<br />
• FALSCH: ( E 1 ↔ E 2 durch ∃X.(E 1 → X ∧ X → E 2 ) ), wird so gelassen wie es ist<br />
(b) Eleminiere ∀X.E per ¬∃X.¬E<br />
(c) Rekursive Funktion T rue(E) für E abgeschlossen<br />
• T rue(E) = case E of E 1 ∧ E 2 → T rue(E 1 ) ∧ T rue(E 2 )<br />
• ¬E → ¬T rue(E)<br />
• true → T<br />
• ∃X.E → T rue(E[X → true]) ∨ T rue(E[X → f alse])<br />
Implementierung: linear tiefer Stack für Rekursion, lineare große Stack Frames (Ausdruck,<br />
Rücksprung).<br />
Untere Schranke: Per Reduktion <strong>von</strong> BOOLE − T ERM. Reduktion zunächst auf BOOLE − −<br />
T ERM, d.h. also BOOLE − T ERM eingeschränkt auf<br />
50
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
p = I 1 ,...,I m mit I ::= X := true | X := f alse | if X goto l 1 else l 2<br />
Dazu: Eliminiere komplexe Ausdrücke wie gehabt. Eliminiere komplexe if s durch if /goto.<br />
Emulation einfacher Ausdrücke: z.B. X := Y ∧ Z →<br />
X := false<br />
if Y goto l1 else l2<br />
l1: if Z goto l2 else l3<br />
l2: X := true<br />
l3: ...<br />
⇒ ’offensichtlich’ in logspace.<br />
Codierung eines Schritts <strong>von</strong> p := I 1 ,...,I m mit V ars(p) = {X 1 ,...,X k } in QBF mit Variablen<br />
X 1 ,...,X k ,L 1 ,...,L m (Labels).<br />
}{{} }{{}<br />
⃗X<br />
⃗L<br />
Definition: N×(⃗X,⃗L, ⃗X ′ ,⃗L ′ ), so dass p ⊢ (l,o) → (l ′ ,o ′ ) ⇒ N×(σ(X 1 ),....,σ(X n ),F,...,F,<br />
σ ′ (X 1 ),...,σ ′ (X k ),F,...,F,<br />
T<br />
}{{}<br />
l ′ -te Stelle<br />
Schreibweise: für ⃗U = (u 1 ,...,u s ), ⃗V = (v 1 ,...,v s ) wobei<br />
• ⃗U ↔ ⃗V ≡ ∧ s<br />
i=1 (u i ↔ v i ) für I ⊆ {1,...,s}<br />
• ⃗U ↔ I<br />
⃗V ≡ ∧ i=I (u i ↔ v i )<br />
• [r,w) = {r,...,w − 1} etc.<br />
• Lab(l) = L l ∧ ∧ i l ¬L i entsprechend Lab ′ (l)<br />
,F,....,F) (unterstelle p ⊢ (m + 1,σ) → (m + 1,σ))<br />
T<br />
}{{}<br />
l-te Stelle<br />
Damit N ×(⃗X,⃗L, ⃗X ′ ,⃗L ′ ) = (Lab(1)∧E 1 )∨...∨(Lab(m)∧E m )∨(Lab(m+1)∧Lab ′ (m+1)∧ ⃗X ↔ ⃗X ′ )<br />
mit<br />
,F,...,F,<br />
I l<br />
E l<br />
X i := true Lab ′ (l + 1) ∧ ⃗X ↔ [1,i)∪(i,k] X ′ ∧ X<br />
i<br />
′<br />
X i := f alse ... ∧ ¬X<br />
i<br />
′<br />
if X i goto l 1 else l 2 ((X i ∧ Lab ′ (l 1 )) ∨ (¬X i ∧ Lab ′ (l 2 ))) ∧ (⃗X ↔ ⃗X ′ )<br />
51
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Codierung der Ausführung <strong>von</strong> p:<br />
Wiederholung: wenn p terminiert, dann time(p) ≤ 2 r mit r = k⌈log(m + 1)⌉. N× ist ein binäres<br />
Prädikat N × (s,s ′ ),s,s ′ Zustände.<br />
Notation: N × n (s,s ′ ) ⇔ ∃s = s 0 ,s 1 ,...,s n = s ′ . N × (s 0 ,s 1 ) ∧ ... ∧ N × (s n−1 ,s n ).<br />
p ↓↔ ∃⃗X ′ ,⃗L ′ .N × 2r (s 0 , ⃗X ′ ,⃗L ′ ) ∧ L ′ m+1 ,s 0 = ( f alse,true, ⃗ f alse) ⃗<br />
Trick 1: Divide-and-conquer. N × 20 (s,s ′ ) = N × (s,s ′ ),N × 2r+1 (s,s ′ ) = ∃s ′′ .N × 2r (s,s ′′ ) ∧ N × 2r<br />
(s ′′ ,s ′ ) → immer noch exponentiell.<br />
Trick 2: Unformulieren in Tailrekursion. N × 2r+1 (s,s ′ ) = ∃s ′′ .∀t,w.((t = s ∧ w = s ′′ ) ∨ (t =<br />
s ′′ ∧ w = s ′ )) → N × 2r (t,w), linear groß.<br />
ALC<br />
ALC ist eine Teilsprache der Web ontology language OW L.<br />
Formeln aus dieser Sprache heißen Konzepte C.<br />
C ::= A | T | ¬C | C<br />
}{{} }{{} 1 ⊓ C 2 | ∀R.C<br />
}{{}<br />
atomare Konzepte A ∈ A<br />
Interpretation:<br />
True<br />
I besteht aus<br />
• Bereich ∆ I (Menge)<br />
• A I ⊆ ∆ I ,∀A ∈ A<br />
• R I ⊆ ∆ I × ∆ I ,∀R ∈ R<br />
Rollen R ∈ R<br />
Semantik: C I ⊆ ∆ I def. durch T I = ∆ I , (¬C) I = ∆ I − C I mit (C I 1 ⊓ CI 2 ) = CI 1 ∩ CI 2<br />
(∀R.C) I = {d ∈ ∆ I | ∀e ∈ ∆ I .(d,e) ∈ R I ⇒ e ∈ C I }<br />
Beispiel: ChessFanatic = ChessP layer ⊓ ∀hasFriend.ChessFanatic<br />
C erfüllbar ⇔ ∃I.C I ∅, zum Beispiel: ∀R.C ⊓ ∀R.D ⊓ ∀R.(C ⊓ D) ist unerfüllbar.<br />
∀R.C ⊓ ∀R.(¬C) ist erfüllbar.<br />
52
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Satz 6.19: ALC − SAT = {C | C erfüllbar} ist P SP ACE vollständig (Ladner 1977).<br />
Beweis: Obere Schranke ist ein Tableaux - System:<br />
C 1 ⊓ C 2 ,Γ<br />
C 1 ,C 2 ,Γ<br />
T ,Γ<br />
Γ<br />
¬¬C,Γ<br />
C,Γ<br />
¬(C 1 ⊓ C 2 ),Γ<br />
¬C 1 ,Γ | ¬C 2 ,Γ<br />
Γ erfolgreich, wenn keine Regel anwendbar auf Γ ist.<br />
A,¬A,Γ<br />
⊥<br />
∀R.C 1 ,...,∀R.C n ,¬∀R.D,Γ<br />
C 1 ,...,C n ,¬D<br />
Beispiel:<br />
(∀R.C ⊔ D) ⊓ ¬∀R.D<br />
∀R.C⊔D,¬∀R.D<br />
C⊔D,¬D<br />
= mit der letzten Zeile folgt...<br />
=<br />
¬(¬(¬C ⊓ ¬D))<br />
¬¬C,¬D<br />
C,¬D √<br />
| ¬¬D,¬D<br />
D,¬D<br />
⊥<br />
Algorithmus in npspace: Prüfe per Tiefensuche, dass alle Zweige erfolgreich enden. Rate bei<br />
¬(C ⊓ D). Lineare Tiefe ⇒ polynomieller Platz.<br />
Untere Schranke: Zeige QBT ≼ logspace ALC −SAT . QBF ohne Einschränkung in Normalform:<br />
Q 1 .x 1 .Q 2 .x 2 .....Q n .x n .ϕ mit Q i ∈ {∃,∀}, ϕ ist quantorenfrei.<br />
(z.B. (∃X.ϕ) ∧ π = ∃X.(ϕ ∧ π), wenn X ∈ FV (π))<br />
Idee: zu prüfende Valuation der Variablen X 1 ,...,X n haben eine Baumstruktur: z.B. ∀X 1 .∃X 1 .∀X 3 .ϕ →<br />
(Bild eines Baums an der Tafel).<br />
Beschreibe das durch ALC−Konzept. Ebenen 0,...,n markiert durch atomare Konzepte Y 0 ,...,Y n .<br />
(∀R) m .C = ∀R....∀R.C<br />
}{{}<br />
m− mal<br />
| (∀R) ≤m .C =<br />
m∧<br />
(∀R) m .C | ∃R.C = ¬∀R.¬C<br />
i=0<br />
Damit:<br />
∧<br />
(∀R) i .(Y i ∧ ¬Y j ), (i = 0,m)<br />
j¬=i<br />
(∀R) i .(Y i → ∃R.Y i+1 ), (Q i = ∃)<br />
(∀R) i .(Y i → (∃R.(Y i+1 ∧ X i )) ∧ (∃R.(Y i+1 ∧ ¬X i )))<br />
(∀R) i .((X i → (∀R) ≥m−i X i ) ∧ (¬X i → (∀R) ≤m−i ¬X i ))<br />
(∀R) m .ϕ<br />
53
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
7 Parallel computation models<br />
Definition 7.1: A P RAM is a sequence P = (π 1 ,...,π q ) of standard RAM programs (we have<br />
+ but no ·). q := q(m,n) is a function where m is the amount of registers used for the input and<br />
n is the total size of the input in bits. For a given problem we actually have a family of P RAM<br />
programs. We insist that the family needs to be uniform. That is, there is a TM that on input<br />
1 n 01 m can construct the P RAM program P m,n = (π m,n,0 ,π m,n,1 ,...,π m,n,q(m,n) ) in logarithmic<br />
space.<br />
Definition 7.2: Semantics of P RAM. A configuration of the P RAM m,n is a tuple<br />
(pc 0 ,pc 2 ,...,pc q(m,n) ) where pc i is the program counter of Π and σ : N → N is the value of<br />
the registers. The semantics of RAM π ⊢ (pc,σ) → (pc ′ ,σ ′ ) this is trivially extended to the<br />
(π 0 ,...,π q(m,n) ) ⊢ (pc 0 ,...,pc q(m,n) ) → (pc 0 ,...,pc q(m,n) ). With one catch if two or more programs<br />
(π i,1 ,...,π i,j ) want to write on step k to the same end of the store, the one with the smallest index<br />
wins.<br />
Definition 7.3: Time consumption of P RAMs. Let P = (P m,n ) be a unique family of P RAMs<br />
and let f ,g : N → N. We say that P runs in parralel time f with g processors if<br />
(i) q(m,n) < g(n)<br />
(ii) after f (n) steps we are in a configuration (pc 1 ,...,pc q(m,n) ,σ) where each pc i is the final<br />
state of π i .<br />
Example 7.4: Matrix multiplication. We are given square matrices A,B (m×m). The product<br />
C = AB is C i,j = ∑ n<br />
k=1<br />
A ik B kj .<br />
Parallelization:<br />
• create n 3 processors<br />
• in the first step we compute a matrix D (n × n × n) such that D i,j,k = A i,k · B k,j<br />
• We use n 2 of these processors to compute in steps 2ton C i,j (each processor one of the<br />
cells of C)<br />
Analysis: it runs in parallel time n with n 3 processors. The total number of operations is O(n 3 ).<br />
54
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
Example 7.5:<br />
We have a list L of n numbers. We want to sum them.<br />
• create n 2 processors<br />
• on step 1 we compute L 1 such that L 1 [i] = L[2i] + L[2i + 1] (|L| = ⌈ n 2 ⌉)<br />
• on step 2 we compute L 2 such that L 2 [i] = L 1 [2i] + L 1 [2i + 1] ... on step logn L logn has<br />
the size 1<br />
Analysis: it runs in parallel time logn with n 2 processors.<br />
Matrix multiplication can be done in logn parallels steps with n 3 proces-<br />
Observation 7.6:<br />
sors.<br />
Observation 7.7: The algorithm for summing numbers works for any associative operator<br />
⊙ (e.g. (X ⊙ Y ) ⊙ Z = X ⊙ (Y ⊙ Z)). This is the idea behind Map Reduce. We have a ’list A’ we<br />
first apply a function A → B to have ’list B’ (map step). We transform the ’list B’ into a B using<br />
a function ⊙ : B × B → B (associative), the reduce step. Finally, we need a function B → C to<br />
get the result.<br />
Example: get the longest words from a list of words. A = words, B =(set of words, N) and<br />
C =set word. f : WORD → (set of words, ). f (x) = ({x},|x|).<br />
⎧<br />
(xs,lx) if lx > ly<br />
⎪⎨<br />
(xs,lx) ⊙ (ys,lx) = (ys,ly) if ly > lx<br />
⎪⎩ (xs ∪ ys,lx) if lx == ly<br />
(associative) g : (set of words, N) → set word g(x,y) = x<br />
Look again at matrix multiplication: c · n 3 (total number of multiplications) ≤ d logn (parallel<br />
time) ·#processors ⇒ c d · n 3<br />
logn ≤ #processors<br />
Can we have matrix multiplication with parallel time O(logn) and O( n3<br />
logn ) processors?<br />
Lemma 7.8 Brent’s principle. If a algorithm runs in parallel time t on a P RAM with k processors<br />
executing a total number of X of operations, then it runs in parallel time c(t + X p ) on a<br />
P RAM with R processors (P ≤ R).<br />
Proof: Let X i be the number of operations being performed at step i, of course X = ∑ t<br />
i=1 x i .<br />
The i-th step can be simulated using only p processors.<br />
55
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
This requires time c( x i<br />
p<br />
+ 1). The total running time of the simulation is<br />
t∑<br />
i=1<br />
c( x i<br />
p + 1) = ct + c p<br />
t∑<br />
x i = ct + cX p = c(t + X p )<br />
For the case of multiplication we have t = logn,X = n 3 ,k = n 3 ,p = n3<br />
logn :<br />
i=1<br />
c(logn + n3<br />
) = c(logn + logn)<br />
n 3<br />
logn<br />
Parallel time f total number of g operations it can be done with f g processors.<br />
Definition 7.9: Bool circiuts. A boolean curcuit is a DAG where each node is a ∧− gate or<br />
a ∨− gate (in-degree 2), or a ¬− gate (with in-degree 1) or a leaf (input nodes). The size of<br />
a BC is the number of nodes and the depth is the length of the longest path. A circuit family<br />
is a sequence C = (c 0 ,c 1 ,...) where each c i is a boolean circuit with i input nodes. A familiy is<br />
uniform if there is a TM that on input 1 n outputs c n in logarithmic space. We say that the parallel<br />
time of a family c is f if the depth of c n is at most f (n), the total work is g if the size of c n is at<br />
most g(n),∀n.<br />
Definition 7.10: Nick’s Class - NC. We define NC i as the problems that can be solved by a<br />
uniform circuit family of polynomiell size (small) and O(log i n) parallel time (fast).<br />
⋃<br />
NC = NC i<br />
Theroem 7.11: A problem is in NC if it can be solved by a uniform P RAM family in<br />
polylogarithmic parallel time with polynomial many processors.<br />
Proof: ” ⇒ ” Let be c n with size n k and depth log i n. We create p p n = (π 1 ,...,π n k). Let g i be<br />
a gate c n , let d be the depth of this gate. We program π i as follows (assume g i is ∧-gate, g j and<br />
g k are the inputs of g i ).<br />
1: NOP<br />
2: NOP<br />
...<br />
3d+1: if Xj = 0 then goto end<br />
i<br />
56
Komplexität <strong>von</strong> <strong>Algorithmen</strong><br />
3d+2: if Xk = 0 then goto end<br />
3d+3: Xi = 1<br />
An induction shows that the algorithm is correct. d can be computed in logarithmic space, so all<br />
p can be computed in logspace.<br />
” ⇐ ” Let m be the number of bits in the input. After t steps the size of the largest register is n+<br />
b + t (b is the largest constant in a program). This can be proofed by induction on t. The number<br />
of registers that can be written in t steps is t · #processors. A configuration (pc 1 ,...,pc k ,σ) can<br />
be encoded with polynomially bits.<br />
One-Step-Parallel-Curcuit<br />
Input: pc 1 ,...pc k and σ 11 ,σ 12 ,....<br />
Output: pc ′ 1 ,...,pc′ k and σ ′ .<br />
Corollar 7.12:<br />
NC ⊆ P T IME. Open question: NC = P T IME?<br />
Theorem 7.13: NL ⊆ NC 2 (nondeterministic logarithmic space)<br />
Proof: We know that GAP is NL− complete. We first show that GAP is in NC 2 . Let A be the<br />
adjacency matrix and  be the addition all self-loops (Âij = 1). Consider the boolean product<br />
 2 =  and Â2 ij = ∨ n<br />
k=1<br />
(Âik ∧ Âkj).<br />
Be aware: Â 2 ij<br />
= 1 if there is a path of length at most 2 between i and j.<br />
Doing Â4 = Â2  2 we get  4 ij<br />
= 1 if there is a path of length at most 4. Â2⌈logn⌉ = Ân the<br />
adjacency matrix of the transitive closure of A. We stack logarithmically many BC of O(n 3 ) size<br />
and O(logn) depth that solve boolean matrix multiplication and get a BC with size O(logn 3 )<br />
and depth O(log 2 n) ∈ NC 2 .<br />
Let R be the logspace reduction function. We are trying to show that x is in NC 2 . BIT (a,i) =<br />
bit i of a is in logspace. BIT − of − R(x,i) = bit(R(x),i) is in logspace. The state graph of the<br />
TM for bit − of − R can be generated in logspace. The size of this graph grows polynomially<br />
with |x|.<br />
57