ALP I Induktion und Rekursion

Werbung
Funktionale Programmierung
ALP I
Induktion und Rekursion
SS 2011
Prof. Dr. Margarita Esponda
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Vollständige Induktion
Die Vollständige Induktion ist eine mathematische Beweistechnik,
die auf die Menge der natürlichen Zahlen spezialisiert ist.
Vorgehensweise:
1. Induktionsanfang
Text
Man zeigt die Behauptung für k=0 oder k=1 bzw. Anfangswert.
2. Induktionsschritt
Man nimmt an, die Aussage sei für
wahr und zeigt damit,
dass die Aussage für k+1 wahr ist.
Wenn beide Schritte erfolgreich durchgeführt wurden, ist die
Behauptung für alle natürlichen Zahlen gezeigt.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Vollständige Induktion
Beispiel:
Vermutung:
Die Summe der ersten n ungeraden Zahlen ist gleich n2
n
2
2i
−
1
=
n
∑
i =1
Motivation:
1
= 12
1+ 3
= 22
1+ 3+ 5
= 32
1+ 3+ 5+ 7
= 42
...
Prof. Dr. Margarita Esponda
…
Funktionale Programmierung
Vollständige Induktion
Beweis per Vollständiger Induktion:
Induktionsanfang:
n
2
2
⋅1
−
1
=
1
=
1
∑
für n=1
Induktionsschritt:
i =1
wir nehmen an, dass für n=k
dann:
k +1
k
2
2i
−
1
=
k
∑
i =1
2
2i
−
1
=
k
+ 2(k + 1) − 1
∑
i =1
= k2 + 2 ⋅ k + 2 − 1
= k2 + 2 ⋅ k + 1
daraus folgt, dass die Vermutung
= (k + 1)2
für alle
Prof. Dr. Margarita Esponda
n ∈
gilt.
Funktionale Programmierung
Vollständige Induktion
Weitere Beispiele an der Tafel!
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Strukturelle Induktion
Die Strukturelle Induktion ist eine allgemeinere Form der
Vollständigen Induktion.
Mit diesem mathematischen Beweisverfahren lassen sich
Aussagen über die Elemente von rekursiv aufgebauten
Datenmengen wie zum Beispiel Listen, Bäumen oder
Graphen beweisen.
Die Datenmengen, die damit behandelt werden, müssen
aus einer endlichen Anzahl von Konstruktionsschritten
aus Grundelementen entstehen.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Induktion über Listen
Vorgehensweise:
1. Induktionsanfang
Man zeigt eine bestimmte Eigenschaft P für die leere
Liste []
2. Induktionsschritt
Man zeigt die Eigenschaft P(x:xs) unter der Annahme,
dass P(xs) gilt.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Induktion über Listen
Beispiel:
Nehmen wir an, wir möchten zeigen, dass die Konkatenation
über Listen assoziativ ist.
Definition von (++):
(++) :: [a] -> [a] -> [a]
(++) [] ys = ys
(++) (x:xs) ys = x : (++) xs ys
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Induktion über Listen
Behauptung:
Für alle Listen xs, zs und ys über den Datentyp a gilt die
Assoziativität-Eigenschaft:
(++) ((++) xs ys) zs = (++) xs ((++) ys zs)
oder (xs ++ ys) ++ zs = xs ++ (ys ++ zs)
Beweis: (Induktion über xs)
Induktionsanfang:
(++) ((++) [] ys) zs)
=
(++) ys zs
=
(++) [] ((++) ys zs)
(++).1
(++).1
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Induktion über Listen
Induktionsschritt:
(++) (x:xs) ((++) ys zs)
(++) (x:xs) ((++) ys zs)
?
= (++) ((++) (x:xs) ys) zs
=
x : (++) xs ((++) ys zs)
=
x : (++) ((++) xs ys) zs
(++).2
Induktionsannahme
=
(++) (x:((++) xs ys)) zs
=
(++) ((++) (x:xs) ys) zs
(++).2
(++).2
weitere Beispiele an der Tafel . . .
Prof. Dr. Margarita Esponda

Funktionale Programmierung
Induktion über Bäume
Definition:
a) Ein einzelner Blatt-Knoten ist ein Baum
o
b) Falls t1, t2,…,tm Bäume sind, dann ist ihre Verknüpfung
unter einem Knoten
o
auch ein Baum (o t1, t2,…,tm )
o
t1
t2 . . . tm
Ein Baum ist balanciert, falls er ein Blatt oder von der
Form (o t1, t2,…,tm) ist, wobei t1, t2,…,tm balanciert und
von derselben Tiefe sind.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Induktion über Bäume
Behauptung:
Ein balancierter m-Baum (Baum mit maximal m Kindern pro
Knoten) mit m>0 und Tiefe n hat
Knoten
Motivation:
o
Tiefe 0
Tiefe 1
Tiefe 2
Tiefe n
Prof. Dr. Margarita Esponda
o
o
o
t1 t2 . . .tm t1 t2 . . . tm
Funktionale Programmierung
Induktion über Bäume
1.
Induktionsanfang
mit Tiefe = 0

K = Knoten =
2. Induktionsannahme
mit Tiefe = n,
K=
3. Induktionsschritt
Tiefe = n+1, K =
+m n ⋅ m
m n +1 − 1 + (m n +1 ) ⋅ (m − 1)
=
m −1

Prof. Dr. Margarita Esponda
Funktionale Programmierung
Strukturelle Induktion über Bäume
Beispiel:
data Tree a = Nil | Leaf a | Node (Tree a) (Tree a)
Vorgehensweise:
1. Induktionsanfang
1.1 Wir zeigen eine bestimmte Eigenschaft P
für den leeren Baum Nil
1.2 Wir zeigen die Eigenschaft P für ein Blatt (Leaf a)
2. Induktionsschritt
Wir zeigen die Eigenschaft P für ( Node l r ) unter der
Annahme, dass P für den Teilbaum l und für den Teilbaum
r gilt.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Das allgemeine Induktionsschema
data T a1 a2 . . . am =
C1 t11 … t1n1
| C2 t21 … t2n2
...
Vorgehensweise:
| Ck tk1 … tknk
1. Induktionsanfang
1.1 Wir zeigen eine bestimmte Eigenschaft P für alle
Basis-Daten (alle Ci ohne Rekursion)
2. Induktionsschritt
Wir zeigen die Eigenschaft P für jede rekursive Definition
(Ci ti1 … tini) unter der Annahme, dass P für ti1 … tini gilt.
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Analyse von Programmeigenschaften
- Korrektheit (wichtigste Eigenschaft!)
- Programmeigenschaften
- wie z.B. Äquivalenz zwischen Programmen
bzw. Ausdrücken
- Komplexitätsaufwand
- Speicherverbrauch
- Terminierbarkeit
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Beispiele endrekursiver Funktionen
Klassisches Beispiel einer nicht endrekursiven Definition ist:
Die Standarddefinition der reverse-Funktion
rev :: [a] -> [a]
rev [] = []
rev (x:xs) = rev xs ++ [x]
Berechnungsaufwand von rev:
Reduktionen
rev [x1, x2, …, xn] => rev [x2, …, xn] ++ [x1]
=> rev [x3, …, xn] ++ [x2] ++ [x1]
1
1
...
=> [xn] ++ [xn-1] ++ [x2] ++ [x1]
1
=> [] ++ [xn] ++ … ++ [x2] ++ [x1]
1
bis hier (n+1) Reduktionen!
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Berechnungsaufwand von rev
bis hier (n+1) Reduktionen!
(++) :: [a] -> [a] -> [a]
(++) [] ys
= ys
(++) (x:xs) ys = x:(xs ++ ys)
Reduktionen
=> [] ++ [xn] ++ [xn-1] ++ … ++ [x2] ++ [x1]
=> [xn] ++ [xn-1] ++ … ++ [x2] ++ [x1]
1
=> [xn, xn-1] ++ … ++ [x2] ++ [x1]
2
=> [xn, xn-1 ,xn-2] ++ … ++ [x2] ++ [x1]
3
=> . . .
.
=> [xn, xn-1 , … ,x1]
n
Die gesamte Anzahl der Reduktionen ist:
Prof. Dr. Margarita Esponda
Quadratischer
Ausführungsaufwand!
Funktionale Programmierung
Eine effizientere Version von rev
quickRev xs = rev_helper xs []
where
rev_helper [] ys = ys
rev_helper (x:xs) ys = rev_helper xs (x:ys)
Berechnungsaufwand:
Reduktionen
quickRev [x1, x2, …, xn] => rev_helper [x1,…,xn] []
1
=> rev_helper [x2,…,xn] (x1:[])
1
n
=> rev_helper [x3,…,xn] (x2:x1:[]) 1
...
=> (xn:, … ,x2:x1:[])
…
1
=> (xn:, … ,x2:[x1])
1
...
=> (xn:, … , x3:[x2,x1])
…
1
lineare Komplexität
Prof. Dr. Margarita Esponda
2n = O(n)
n
Funktionale Programmierung
Sind rev und quickRev äquivalent?
Zu beweisen ist:
Für alle endlichen Listen xs :: [a] gilt:
rev = quickRev
. . .Beweis an der Tafel . . .
Prof. Dr. Margarita Esponda
Funktionale Programmierung
Wichtiges Beispiel von Endrekursion
foldl-Funktion:
foldl :: (b -> a -> b) -> b -> [a] -> b
foldl f z []
= z
foldl.1
foldl f z (x:xs) = foldl f (f z x) xs
foldl.2
Hier werden Zwischenergebnisse
akkumuliert und weitergeleitet.
Mit Hilfe von Faltungs-Operatoren können sehr leicht
endrekursive Funktionen definiert werden.
Beispiel:
reverse_reloaded = foldl (flip (:)) []
flip
:: (a -> b -> c) -> b -> a -> c
flip f x y
Prof. Dr. Margarita Esponda
= fyx
Funktionale Programmierung
Berechnungsverlauf
reverse_reloaded [x1, x2, … , xn]
foldl.2
=> foldl (flip (:)) [] [x1, x2,…, xn]
=> foldl (flip (:)) ((flip (:)) [] x1) [x2,x3,…, xn]
=> foldl (flip (:)) ((:) x1 []) [x2,x3,…, xn]
=> foldl (flip (:)) (x1:[]) [x2,x3,…, xn]
=> foldl (flip (:)) [x1] [x2,x3,…, xn]
foldl.2
=> foldl (flip (:)) ((flip (:)) [x1] x2) [x3,…, xn]
=> foldl (flip (:)) ((:) x2 [x1]) [x3,…, xn]
=> foldl (flip (:)) (x2:[x1]) [x3,…, xn]
foldl.2
Prof. Dr. Margarita Esponda
=> foldl (flip (:)) [x2, x1] [x3,…, xn]
=> . . .
Berechnung der Fibonacci-Zahlen
1. Lösung
fib 0 = 0
fib.0
fib 1 = 1
fib.1
fib n = fib (n-2) + fib (n-1)
fib.2
2. Lösung
Endrekursive Funktion
fib' n = quickFib 0 1 n
where
quickFib a b 0 = a
quickFib.1
quickFib a b n = quickFib b (a+b) (n-1) quickFib.2
Funktionale Programmierung
Sind fib und fib' äquivalent?
Zu beweisen ist:
fib = fib'
Für unseren Beweis müssen wir folgende Eigenschaft der quickFibFunktion per Induktion über n zeigen.
quickFib (fib i) (fib (i+1)) n = fib (i+n)
……… ze.1
Induktionsanfang: für n = 0
quickFib (fib i) (fib (i+1)) 0 = fib i = fib (i+0)
quickFib.1
Prof. Dr. Margarita Esponda

Funktionale Programmierung
Induktions-Annahme:
quickFib (fib i) (fib (i+1)) n = fib (i+n)
Induktionsschritt:
?
quickFib (fib i) (fib (i+1)) (n+1) = fib (i+(n+1))
quickFib (fib i) (fib (i+1)) (n+1)
quickFib.2
fib.2
Induktions-Annahme
= quickFib fib (i+1) (fib (i) + fib (i+1)) n
= quickFib fib (i+1) (fib ((i+1)+1) n
= fib ((i+1) + n)
= fib (i + (n+1))
Prof. Dr. Margarita Esponda

Funktionale Programmierung
Sind fib und fib' äquivalent?
Behauptung:
fib = fib'
1. Induktionsanfang:
fib 0 = 0 = quickFib 0 1 0 = fib' 0

quickFib.1
2. Induktionsanfang:
fib 1 = 1
fib' 1
=
quickFib 0 1 1
fib'.1
=
quickFib 1 1 0
quickFib.2
= 1
quickFib.1
Prof. Dr. Margarita Esponda

Funktionale Programmierung
Induktionsannahme:
fib n = fib' n
Induktionsschritt:
?
fib (n+1) = fib' (n+1)
fib' (n+1) = quickFib 0 1 (n+1)
fib'.1
= quickFib (fib 0) (fib 1) (n+1)
fib.0 und fib.1
= fib ((n+1)+0)
aus
ze.1
= fib (n+1)
Prof. Dr. Margarita Esponda

Herunterladen