19.11.2014 Aufrufe

Skript zur Vorlesung Komplexit¨at von Algorithmen

Skript zur Vorlesung Komplexit¨at von Algorithmen

Skript zur Vorlesung Komplexit¨at von Algorithmen

MEHR ANZEIGEN
WENIGER ANZEIGEN

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

Hurra! Ihre Datei wurde hochgeladen und ist bereit für die Veröffentlichung.

Erfolgreich gespeichert!

Leider ist etwas schief gelaufen!