Grundlagen der Informatik 1 und 2 Zusammenfassung Florian Forster www.forster-florian.de 4. September 2002 Inhaltsverzeichnis 1 . . . . . . . . . . . . . . . 2 2 2 3 3 3 3 3 4 4 4 5 5 6 6 6 2 Syntax und Semantik 2.1 BNF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Semantik von Rekursion: Fixpunkte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 8 8 3 Rekursion 3.1 Rekursionsarten . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Korrektheit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3.3 Terminierung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 10 10 10 4 Imperative Programmierung 4.1 von-Neumann . . . . . . 4.2 Prozeduren . . . . . . . 4.3 Bindungen . . . . . . . . 4.4 Funktional vs. Imperativ 4.5 Parameterübergabe . . . 4.6 Hoare-Kalkül . . . . . . . . . . . . 11 11 11 11 11 11 12 Sortieralgorithmen 5.1 Selection Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Quick Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 Heap Sort . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 12 12 12 5 Informationssystem 1.1 Normalformsystem . . . . . . . . . . . . 1.2 Graphen . . . . . . . . . . . . . . . . . . 1.3 Transformationen . . . . . . . . . . . . . 1.4 Funktionale Programmierung . . . . . . . 1.5 Haskell . . . . . . . . . . . . . . . . . . 1.5.1 Deklarationen . . . . . . . . . . . 1.5.2 Basistypen und Typkonstruktoren 1.6 Vordefinierte Operationen . . . . . . . . . 1.7 Lokale Deklaration . . . . . . . . . . . . 1.8 Guards bzw If-Abfragen . . . . . . . . . 1.9 List Comprehension . . . . . . . . . . . . 1.10 Datentypen . . . . . . . . . . . . . . . . 1.11 Module . . . . . . . . . . . . . . . . . . 1.11.1 Sonstiges . . . . . . . . . . . . . 1.11.2 Wichtige Funktionen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Komplexität 6.1 Asymptotische Notation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6.2 P/NP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 12 13 7 Formale Sprachen und Automaten 7.1 Allgemeines . . . . . . . . . . . . . . 7.2 Reguläre Sprachen . . . . . . . . . . 7.3 Kontextfreie Sprachen . . . . . . . . 7.4 Kontextsensitive und Typ 0-Sprachen 7.5 Überblick . . . . . . . . . . . . . . . 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 13 14 16 17 18 Berechenbarkeit 8.1 Turing-Berechenbar . . . . . . . . . . . . . . 8.2 LOOP-Berechenbar . . . . . . . . . . . . . . 8.3 WHILE-Berechenbar . . . . . . . . . . . . . 8.4 GOTO-Berechenbar . . . . . . . . . . . . . . 8.5 Primitiv rekurisve und µ-rekurisve Funktionen 8.6 Die Ackermannfunktion . . . . . . . . . . . 8.7 Entscheidbarkeit,Halteproblem . . . . . . . . 8.8 Gödelsche Satz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 18 19 19 19 20 20 20 21 . . . . . . . . . . . . . . . 1 Informationssystem Eine Interpretation ist eine Zuordnung von Begriffen zu Bedeutungen (Semantik). Verschiedene Interpretation können derselben Repräsentation verschiedene Bedeutungen zuordnen. Zum Beispiel kann 1001 als „eintausend-eins“ oder als 9 interpretiert werden. Ein Informationssystem ist ein 3-Tupel (A, R, I). Hierbei ist A die Menge der Begriffe, R die Menge der Repräsentationen und I eine Relation I : R → A mit r ∈ R 7→ I(r) = a wobei a die Bedeutung von r ist. I nennen wir Interpretation. Ein Informationssystem heißt • mehrwertig wenn gilt (∃r : r ∈ R : |I(r)| > 1). Heißt also daß es für eine Repräsentation mehrere Bedeutungen gibt. Zum Beispiel kann man mit Regen den Regen meinen der vom Himmel fällt :) oder den Fluß Regen. • mehrdeutig wenn gilt I(r) = I(s)mitr 6= s, also eine Bedeutung hat mehrere Repräsentationen. Zum Beispiel kann man einen Verwandtschaftsgrad mit Opa oder Großvater bezeichnen. Die Bedutung bleibt hierbei gleich. 1.1 Normalformsystem Sei (A, R, I) ein Informationssystem und S ⊆ R eine ausgezeichnete Menge so nennen wir diese ein Normalformsystem. I|S ist dann die Standardinterpretation. 1.2 Graphen Ein Graph ist ein 2-Tupel (V, E) wobei V die Menge der Knoten (engl. vertices) und E die Menge der Kanten (engl. edges) darstellen. Es gilt E ⊆ V × V = {(u, v)|u, v ∈ V }. Für einen ungerichteten Graphen gilt (u, v ∈ V ∧ (u, v) ∈ E ⇒ (v, u) ∈ E) 2 1.3 Transformationen Eine Funktion fA heißt Äquivalenztransformation genau dann wenn (∀r : r ∈ R : I(r) = I( fA (r))) Eine Funktion fK heißt Kongruenztransformation genau dann wenn (∀s, s′ : s, s′ ∈ R : I(s) = I(s′ ) ⇔ I( fK (s)) = I( fK (s′ ))) 1.4 Funktionale Programmierung Eine totale Funktion f : A → B erfüllt folgende Bedingung (∀a : a ∈ A : (∃!b : b ∈ B : (a, b) ∈ f ) Die Substitutionsregel von Leibniz lautet (∀x, y : x, y ∈ A : x = y ⇒ f (x) = f (y)) Darstellung einer Funktion f : A → B als λ-Ausdruck f = (λa : a ∈ A : b) wobei b die Rechenvorschrift für den Parameter a ist. Die Auswertung an einer bestimmten Stelle nennt man hier Reduzierung. Beispiel: (λx :: x ∗ x)2 = x ∗ x[2/x] = 2 ∗ 2 = 4 Die formalen Parameter eines Ausdrucks nennt man gebunden die anderen frei. Freie Parameter erhalten ihre Werte aus der Umgebung. Currying ist der Prozeß, aus einer Funktion mit zwei Parametern (etwa x, y) eine Funktion mit einem Parameter x zu machen, die eine andere Prozedur mit einem Parameter y als Wert zurückgibt. 1.5 Haskell 1.5.1 Deklarationen • Wertdeklaration a :: Float -- a ist vom Typ Float a = 5.0 - 3.0 -- a erhält den Wert 2.0 • Funktionsdeklaration double :: Float -> Float double a = 2*a -- Die Funktion geht von Float nach Float -- Übergabeparameter a nehmen und 2*a zurückliefern 1.5.2 Basistypen und Typkonstruktoren • Int Ganzzahlige endliche Werte • Integer Wie Int nur unendlich • Rationale Zahlen z.B. 1%2 3 • Float Gleitpunktzahl • Double Höhere Genauigkeit als Float • Bool Wahrheitswert • Char Zeichen • Strings Zeichenkette • -> Funktion • (.,.) karthesisches Produkt • [] Liste 1.6 Vordefinierte Operationen • Bool &&, not, || • Zahlen - (sowohl ein- als auch zweistellig), +, * , ’div’, ’mod’ • String ++ (Konkatenation) • Listen [] (leere Liste]), a : [] (einfügen eines elements am Kopf) 1.7 Lokale Deklaration Entweder mit let oder mit where a :: Int a = 2 let b = a*a c = a+a in b*c a :: Int a = 2 res = b*c where b = a*a c = a+a 1.8 Guards bzw If-Abfragen summe :: Int -> Int summe n = if n == 0 then 0 else summe (n-1) + n summe :: Int -> Int summe 0 = 0 summe n | n>0 = n + summe (n-1) 4 1.9 List Comprehension [i*i | i <- [1..5]] [x | let alphabet = "abcd", i <- alphabet, j <- alphabet, k <- alphabet, let x=[i,j,k], x == reverse x] 1.10 Datentypen • Enumerationstypen data Season = Spring | Summer | Autumn | Winter deriving Show deriving Show generiert automatisdch eine Ausgaberoutine Gleichheit definieren instance Eq Season where Spring == Spring = True ... _ == _ = False Heißt das Season eine Instanz der Typklasse Eq ist und sozusagen die Vergleichbarkeitseigenschaft besitzt. Automatisch ginge dies auch mit ... deriving (Show, Eq) • Produkttypen data MyRational = Rat Int Int deriving (Show, Eq) wird dann z.B. erstellt mit Rat 2 3 Funktionen sehen z.B. so aus num :: MyRational -> Int num (Rat x y) = x • Datentypen mit Varianten data Currency = DM Double | Euro Double deriving (Show, Eq) bedeutet dann daß Euro 3 == DM 3 false liefert Mit solchen Datentypen (z.B. data Mix = Set1 Int | Set 2 Bool) kann man dann Listen des Typs Mix bilden, also Bool und Int gleichzeitig in einer Liste speichern • Polymorphe Datentypen data Maybe a = Nothing | Just a Nothing entspricht hierbei undefiniert/bottom type IntMaype = Maybe Int mit type werden nur Synonyme definiert • Rekursive Datentypen 5 Stack: data STACK a = EmptyStack | Push (a, STACK a) BinärBaum: data BTREE a = Notree | Node (BTREE a) a (BTREE a) Beblätterter Baum: date BBTREE a = BBLeaf a | BBNode (BBTREE a) (BBTREEE a) beliebiger Knotengrad data NTREE a = NNode a [NTREE a] | NNoTree type FOREST a = [ NTREE a ] 1.11 Module module Name (exports...) where . . . Anstatt die einzelnen Konstruktoren aufzuzählen die exportiert werden sollen kann man auch nur (...) für alles schreiben. In Programmen wird ein Modul dann mit import "Dateiname.hs" eingebunden. 1.11.1 Sonstiges • Haskell benutzt Typinferenz (type inference) d.h. es bestimmt den Typ jedes Ausdrucks selbst! • Ein Paar <Name,Wert> heißt Bindung, eine Liste von Bindungen Umbebung. Die Auswertung erfolgt mit sog. Formularen • Eine Signatur Σ = (S, F) besteht aus einer Menge S von Typsymbolen und einer Menge F von Funktionssymbolen. Die Rechnerstruktur einer Signatur Σ weist den Symbolen von Σ Bedeutungen zu, S eine Trägermmenge und F Funktionen. 1.11.2 Wichtige Funktionen ord :: Char -> Int -- ASCII-Code chr :: Int -> Char -- Zeichen abs :: Int -> Int abs a | a < 0 = (-a) abs a | a >= 0 = a max :: Int -> Int -> Int max a b | a < b = b max a b | a >= b = a min :: Int -> Int -> Int min a b | a < b = a min a b | a >= b = b 6 fac :: Int -> Int fac 0 = 1 fac n | n>0 = n * fac(n-1) rev :: [a] -> [a] rev [] = [] rev (x:xs) = rev xs ++ [x] map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = (f x) : (map f xs) zip zip zip zip :: [a] [] _ = - [] = (a:as) -> [b] -> [(a,b)] [] [] (b:bs) = (a,b) : zip as bs filter :: (a -> Bool) -> [a] -> [a] filter p [] = [] filter p (x:xs) = if (p x) then x : (filter p xs) else filter p xs unzip :: [(a,b)] -> ([a],[b]) unzip [] = ([], []) unzip ((a, b):rest) = let (as, bs) = unzip rest in (a:as, b:bs) app :: [a] -> [a] -> [a] app [] yl = yl app (x:xs) yl = x : app xs yl rev :: [a] -> [a] rev [] = [] rev (x:xs) = rev xs ++ [x] qsort :: Ord a => [a] -> [a] qsort [] = [] qsort (x:xs) = qsort [y | y<-xs, y<x] ++ [x] ++ qsort [y | y<-xs, y>x] breadthsearch :: (a -> Bool) -> BTREE a -> Maybe a breadthsearch p tree = let searchForest [] = Nothing searchForest (Notree : t) = searchForest t searchForest (Node l x r : t) = if p x then Just x else searchForest (t ++ [l,r]) in searchForest[tree] binarysearch :: (a -> a -> Bool) -> a -> BTREE a -> Maybe a binarysearch less item Notree = Nothing binarysearch less item (Node l x r) = if less x item then binarysearch less item r else if less item x then binarysearch less item l 7 else Just x 2 Syntax und Semantik 2.1 BNF Eine BNF-Grammatik G ist ein Quadrupel G = (N, Σ, P, s) wobei N eine Menge von Nichtterminalen, Σ eine Menge von Terminalen, P eine Menge von Produktionen, und s ∈ N das Startsymbol ist. Mit BNF-Grammatiken können kontextfreie Sprachen beschrieben werden. Kontextfrei heißen sie deshalb weil links in den Produktionen jeweils nur ein Nichtterminal steht. Ein Ableitungsbaum ist ein Baum mit folgenden Eigenschaften 1. Alle Blätter sind Terminale 2. Alle inneren Knoten sind Nichtterminale 3. Die Wurzel ist daa Startsymbol 4. Die Nachfolger müssen durch Produktionen der Grammatik entstehen Eine Grammatik heißt mehrdeutig wenn ein Wort mit mehreren Ableitungsbäumen hergeleitet werden kann. Eine Sprache die sich nur durch mehrdeutige Grammatiken definieren läßt heißt auch mehrdeutig. 2.2 Semantik von Rekursion: Fixpunkte Das Ergebnis rekursiver Funktionen kann in einer einzigen Funktion konzentriert werden. Gesucht ist also eine Funktion q. Sie wird mittels des Fixpunkt-Funktionals approximiert, d.h. eine unzureichend genaue Funktion wird an weiteren Punkten definiert. Mittels Funktions-Iteration wird das Funktional iteriert. So wird systematisch der kleinste Fixpunkt der Funktion ermittelt. Es beginnt mit der überall-nichtdefinierten Funktionen. Die Funktionen sind dabei nach der Approximationsordnung geordnet, letzlich also nach der Anzahl definierter Funktionswerte. Die Menge der enstehenden Funktion ist eine Kette, d.h. alle Elemente sind miteinander vergleichbar (die Nullfunktion ist kleiner als jede andere Funktion). Jeder Fixpunkt wird dann unter dem Fixpunktfunktional auf sich selbst abgebildet (q = Q[q]). Das Supremum der Menge der q wird kleinste Fixpunkt genannt. Dies ist die Funktion, die an den wenigsten Stellen festgelegt ist. Eine Definition kann man als Gleichung ansehen. Die Bedeutung der Definition ist durch die Lösung(en) der Gleichung gegeben Man kann beispielsweise Funktionen folgendermaßen definieren: q: → ⊥ q = (λn : n ∈ : i f n = 0 then 1 else q(n + 1)) Die Theorie zur Lösung dieser Gleichung heißt Fixpunkttheorie. Man versucht also eine Gleichung zu finden die die Definition erfüllt. Hierfür wird q zu einem zusätzlichen Parameter und man erhält daß zugehörige Fixpunktfunktional Q Q : ( → ⊥) → ( → ⊥ ) N N N Q = (λq : q ∈ N N N→N ⊥ N N : (λn : n ∈ N : i f n = 0 then 1 else q(n + 1))) Die Lösung der Gleichung sind dann alle Funktionen h die unter Q auf sich selbst abgebildet werden Q[h] = h. Um eine Lösung zu finden muss • mindestens ein Fixpunkt existieren 8 • wenn mehrere existieren, einer als Lösung ausgewählt werden • die Lösung berechenbar sein Wenn mehrere Fixpunkte existieren wird der kleinste Fixpunkt bzgl. der Approximationsordnung ausgewählt, in der eine Funktion f kleiner als eine Funktion g ist, wenn f mit g übereinstimmt aber unter Umständen an weniger Punkten definiert ist. Funktionsiteration Eine Funktion f : M → N kann wie folgt iteriert werden: (∀x : x ∈ M : f 0 (x) = x) (∀x, i : x ∈ M ∧ i ∈ N ∧ i > 0 : f i (x) = f ( f i−1 (x))) partielle Ordnung Eine Relation ⊑⊆ M × M heißt partielle Ordnung gdw.: (∀x : x ∈ M : x ⊑ x) (Reflexivität) (∀x, y : x, y ∈ M : x ⊑ y ∧ y ⊑ x ⇒ x = y) (Antisymetrie (∀x, y, z : x, y, z ∈ M : x ⊑ y ∧ y ⊑ z ⇒ x ⊑ z) (Transitivität) Bottom ⊥ erfüllt folgende Eigenschaft (∀x : x ∈ M : ⊥ ⊑ x) diskrete Ordnung Wenn gilt x1 ⊑ x2 ⇔ x1 = ⊥ ∨ x1 = x2 dann heißt ⊑ diskrete Ordnung Approximationsordnung Sei ⊑ eine diskrete Ordnung auf M und seine f , g : M → N Funktionen dann ist die Relation f ⊑ g ⇔ (∀x : x ∈ M : f (x) ⊑ g(x)) eine partielle Ordnung, die sog. Approximationsordnung. gerichte Menge,obere Schranke,Supremum Eine nichtleere Teilmenge X ⊆ M heißt gerichtet gdw. (∀x, y : x, y ∈ X : (∃z : z ∈ X : x ⊑ z ∧ y ⊑ z)) z heißt dann obere Schranke von x und y. Als Supremum einer Menge bezeichnet man die kleinste obere Schranke. Funktionsmonotonie Eine Funktion f : M → N ist monoton gdw. x ⊑ y ⇒ f (x) ⊑ f (y) bzw für ein Funktional τ f ⊑ g ⇒ τ[ f ] ⊑ τ[g] Stetigkeit Eine Funktion f : M → N ist stetig gdw. f (sup i : i ∈ N : xi ) = (sup i : i ∈ N : f (xi ) Fixpunktsatz 9 Ist τ eine stetige Abbildung üer einer vollständig geordneten Menge M mit kleinestem Element ⊥ so ist die Gleichung x = τ[x] lösbar uns es existiert ein eindeutiger kleinster Fixpunkt. 3 Rekursion 3.1 Rekursionsarten 1. Lineare Rekursion tritt auf wenn bei der Deklaration der Funktion in jedem Zweig auftretender Fallunterscheidungen der Funktionsaufruf maximal einmal auftritt. 2. Repetitive Rekursion ist ein Spezialfall der Linearen Rekursion. Hierbei erscheint in allen Funktionsaufrufen einer rekursiven Deklaration einer Funktion der rekursive Aufruf als letzte Aktion 3. Kaskadenartige Rekursion ist wenn in der Fallunterscheidung zwei oder mehrere Aufrufe der Funktion stattfinden. (Divide and Conquer!!) 4. Vernestete Rekursion ist wenn in dem rekursiven Aufruf selbst wieder ein Rekursiver Aufruf auftritt. z.B. ack ack ack ack :: Integral a => (a,a) -> a (0,y) = y+1 (x,0) = ack(x-1,1) (x,y) = ack (x-1, ack(x,y-1) -- Vernestet 5. Verschränkte Rekursion bedeutet daß in dem Aufruf von f nicht f vorkommt sondern eine Funktion g1 die dann eine Funktion g2 bis gn aufruft bis man letztendlich wieder bei f ist. Aus jeder verschränkten Rekursion kann man mit Einführung eines zusätzlichen Paramaters eine direkte Rekursion machen. 3.2 Korrektheit Sei f eine für alle x ∈ D definierte funktion und f ihre Implementation. f heißt. • partiell korrekt, wenn (∀x : x ∈ D : f(x) ist de f iniert ⇒ f (x) = f(x)) • total korrekt (∀x : x ∈ D : f(x) ist de f iniert ∧ f (x) = f(x)) Partielle Korrektheit garantiert das spezifizierte Verhalten nur wenn man Termination vorraussetzt, totale Korrektheit hingegen garantiert auch Termination. Aus partieller Korrektheit und Termination folgt deswegen totale Korrektheit. 3.3 Terminierung Für den Beweis der Terminierung benötigt man eine Abstiegsfunktion. Sei für x ∈ M f (x) = E[ f (E1 (x)), . . . , f (En (x))] eine Funktionsdeklaration mit rekursiven Aufrufen f (E1 (x)), . . . , f (En (x)), wobei die Ei (x) keine rekursiven Aufrufe von f enthalten und sei für alle im Rumpf von f auftretenden Funktionen die Terminierung bereits gezeigt. Sei Ci (x) die Bedingung unter der der rekursive Aufruf f (Ei (x)) erfolgt. Die Terminierung von f auf M ist gesichert falls es eine Abbildung h : M → N gibt, so dass gilt: (∀x, i : x ∈ M ∧ i ∈ {1, . . . , n} : Ci (x) ⇒ h(x) > h(Ei (x)) 10 4 Imperative Programmierung 4.1 von-Neumann Ein von-Neumann Rechner besitze einen linear organisierten Speicher mit wahlfreiem Zugriff (Random Access), in dem Programme und Daten abgelegt werden. Die Abarbeitung von Programmen orientiert sich daher am aktuellen Speicherzustand und bei jedem Arbeitsschritt werden Anweisungen ausgeführt die den Zustand verändern. Deshalb heißt es imperative Programmierung. 4.2 Prozeduren Als reine Prozedur bezeichnet man solche die an Stellen stehen, an denen ein Befehl erwartet wird. Hingegen stehen Funktionsprozeduren an Stellen an denen ein Ausdruck des Rückgabetyps wer Prozedur erwartet wird. Man unterscheidet bei den übergebenen Parametern zwischen Eingabeparametern, Ausgabeparametern und eine Kombination von beiden, den transienten Parametern. 4.3 Bindungen Bei statischer Bindung wird im Bereich der Prozedurdeklaration nach den Parametern gesucht, bei dynamischer Bindung hingegen in der Umgebung des Prozeduraufrufs. 4.4 Funktional vs. Imperativ Im Funktionalen gibt es • keine Programmvariablen • keine Mehrfachzuweisung • keine Schleifen (dafür Rekursion) • keine Sprünge (goto) • keine Zeiger 4.5 Parameterübergabe Als L-Wert wird die Adresse einer Variable, als R-Wert deren Wert bezeichnet. Call by Reference Der L-Wert des formalen Parameters wird auf den L-Wert des aktuellen Parameters gesetzt. Call by Name Bei einem Aufruf wird jedes Vorkommen des formalen Parameters durch den aktuellen Parameter ersetzt. (siehe inline-Funktionen in C/C++) Call by Value Der R-Wert des formalen Parameters wird auf den R-Wert des aktuellen Parameters gesetzt Call by Result Der Rückgabewert wird in den L-Wert des aktuellen Parameters geschrieben, d.h. der RWert des aktuellen Parameters wird im Prozedurrumpf nicht genutzt. Call by Value-Result Der R-Wert des aktuellen Parameters wird in den R-Wert des formalen Parameters kopiert. Am Ende wird dann der R-Wert des formalen Parameters an die Stelle des R-Werts des aktuellen Parameters kopiert. 11 4.6 Hoare-Kalkül Die Regeln sind von der Form (Precondition) Programm (Postcondition). Um einen formelen Beweis für ein Programm durchzuführen stellt man eine Precondition (Eingabe) auf und eine Postcondition (erwartete Ausgabe). Nur geht man mit Hilfe des Kalküls durch die einzelnen atomaren Programmschritte und macht aus der Precondition so die Postcondition. Da das Kalkül korrekt ist folgt nun auch die Korrektheit des Vorraussetzung . Programms bzgl. der angegebenen Conditions. Die Kalkülregeln sind von der Form axiomatischerSchlu Leere Anweisung Zuweisung {R[E/x]}x:=E{R} Komposition Auswahl Schleife true {R}skip{R} {P}S1 {Q};{Q}S2 {R} {P}S1 ;S2 {R} {P∧B}S1 {R},{P∧¬B}S2{R} {P}i f B then S1 else S2 f i{R} {I∧B}S{I},P⇒I,I∧¬B⇒R {P}while B do S od{R} Folgeregel wobei I die Schleifeninvariante ist P⇒P′ ,R′ ⇒R,{P′ }S{R′ } {P}S{R} 5 Sortieralgorithmen 5.1 Selection Sort Einfach immer das in der gegebenen Ordnung kleinste Element nach vorne ins Array holen und die Länge des zu betrachtenden Arrays verringern. Dies geschieht mit zwei For-Schleifen die maximal über die Eingabelänge n laufen also O(n2 ) und Ω(n2 ). 5.2 Quick Sort Die zu sortierende Folge a wird so in zwei Teilstücke b und c zerlegt, dass alle Elemente des ersten Stücks b kleiner oder gleich allen Elementen des zweiten Stücks c sind (Divide). Danach werden die beiden Teilstücke sortiert, und zwar rekursiv nach demselben Verfahren (Conquer). Wieder zusammengesetzt ergeben die Teilstücke die sortierte Folge (Combine). Im benötigt Quick Sort O(n log n)) da die Rekursionstiefe log n ist und in jeder Schicht n Elemente zu behandeln sind. Im schlechtesten Fall der Eingabe allerdings wie Bubble Sort O(n2 ). 5.3 Heap Sort Ein Heap ist ein Binärbaum der vollständig ist und in der untersten Ebene gefüllt wird. Bei Einfügen eines Elements am Ende wird heapify gemacht um die Heap-Eigenschaft wieder herzustellen. Hierfür wird das eingefügte Element solange mit dem Vaterknoten verglichen bis keine Vertauschung mehr nötig ist. Intern kann man einen Heap als Array repräsentieren mit Vater a[i] mit linker Sohn a[2i+1] bzw. rechter Sohn a[2i+2]. Wenn man sortieren will erstellt man einen Heap und nimmt das oberste Element raus. Dann das letzte Element im Array an die Position stellen und Heap-Eigenschaft wieder herstellen. Dann wieder Wurzel rausnehmen usw. Die Komplexität ist selbst im schlechtesten Fall O(n log n) und somit optimal. 6 Komplexität 6.1 Asymptotische Notation Mit O( f (n)) bezeichnen wir die Klasse aller Funktionen g mit der Eigenschaft ∃c > 0∃n0 > 0∀n ≥ n0 : g(n) ≤ c f (n) 12 Mit Ω( f (n)) bezeichnen wir die Klasse aller Funktionen g mit der Eigenschaft ∃c > 0∃n0 > 0∀n ≥ n0 : g(n) ≥ c f (n) Mit Θ( f (n)) bezeichen wir die Klasse O( f (n)) ∩ Ω( f (n)). 6.2 P/NP Die Klasse P sind alle Probleme A für die es eine deterministische Turingmaschine gibt die A in polynominialier Zeit löst. Die Klasse NP sind alle Probleme A für die es eine nichtdeterministische Turingmaschine gibt die A in polynominialier Zeit löst. Seien A und B Probleme, dann heißt A auf B polynominail reduzierbar -symbolisch A ≤ p B- falls es eine totale und mit polynominialer Komplexität berechenbare Funktion f gibt daß für alle Eingaben der Probleme gilt x ∈ A ⇔ f (x) ∈ B Eine Problem heißt NP-hart falls sich alle Probleme aus NP auf dieses polynominial reduzieren lassen. Ein Problem ist NP-vollständig falls es NP-hart ist und selbst in NP liegt. SAT ist das Erfüllbarkeitsproblem der Aussagenlogik ob es für eine Formel F eine Belegung gibt dass F wahr ist. SAT wurde als das NP-vollständige Problem gewählt. Die Idee die dahinter steckt ist, daß man jedes Problem mit einem Algorithmus, also auch mit einer Turingmaschine darstellen kann. Man sucht nun einen Algorithums mit polynominialer Komplexität um eine Turingmaschine als Aussagenlogische Formel darzustellen die genau dann wahr ist wenn die Turingmaschine hält. Dies ist ja dann wieder das Problem von SAT. Auf SAT führt man dann zunächst 3KNF-SAT zurück und auf dieses eine Vielzahl anderer Probleme wie TSP, Rucksack, Gerichteter Hamiltion Kreis. 7 Formale Sprachen und Automaten 7.1 Allgemeines Eine Grammatik ist ein 4-Tupel G = (V, Σ, P, S) mit folgenden Bedingungen: • V ist die endliche Menge der Variablen • Σ ist eine endliche Menge von Terminalsymbolen • Es gilt V ∩ Σ = 0/ • P ist eine endliche Menge von Produktionen der Form (V ∪ P)+ → (V ∪ P)∗ . • S ist das Startsymbol Die durch eine Grammatik G definierte Sprache L wird als L(G) = {w ∈ Σ∗ |S ⇒∗G w} dargestellt, wobei ⇒∗G bedeutet daß w durch beliebig viele Anwendung der Regeln von G aus S ableitbar ist. Die Grammatiken wurden vom Linguisten Chomsky in eine Hierachie unterteilt mit folgenden Definitionen • Zunächst ist jede Grammatik vom Typ0, sogenannte Phrasenstrukturgrammatiken • Eine Grammatik ist von Typ1 bzw. kontextsensitiv, wenn ∀w1 , w2 ∈ P : w1 → w2 ⇒ |w1 | ≤ |w2 | gilt. • Eine Typ1-Grammatik ist vom Typ2 bzw. kontextfrei, wenn ∀w1 , w2 ∈ P : w1 → w2 ⇒ w1 ∈ V gilt. 13 • Eine Typ2-Grammatik ist vom Typ3 bzw. regulär, wenn ∀w1 , w2 ∈ P : w1 → w2 ⇒ w2 ∈ Σ ∪ ΣV gilt. Die von den jeweiligen Typ-Grammatiken erzeugten Sprachen werden dann Typ-[0-3]-Sprachen genannt. Grammatiken nennen wir mehrdeutig wenn für ein Wort mehrere Syntaxbäume existieren. Das Wortproblem für Typ1 Sprachen, also die Frage ob ein Wort x ∈ L(G) gibt, ist entscheidbar. Also gibt es einen Algorithmus der bei Eingabe einer kontextsensitiven Grammatik G = (V, Σ, P, S) und eines Wortes x ∈ Σ∗ in endlicher Zeit entscheidet ob x ∈ L(G) oder x ∈ / L(G). 7.2 Reguläre Sprachen Ein deterministischer endlicher Automat (kurz DEA) ist ein 5-Tuple M = (Z, Σ, δ, z0 , E) wobei • Z eine endliche Menge von Zuständen • Σ das endliche Eingabealphabet • V ∩ Σ = 0/ • z0 ∈ Z Startzustand • E ⊆ Z die Menge der Endzustände • δ : Z × Σ → Z die Überführungsfunktion ist. Zu einem gegebenen Automaten definieren wir eine Funktion δ̂ : Z × Σ∗ → Z induktiv durch • δ̂(z, ε) = z • δ̂(z, ax) = δ̂(δ(z, a), x) Die von einem DEA Automaten dargestellte bzw. akzeptierte Sprache T (M) = {x ∈ Σ∗ |δ̂(z0 , x) ∈ E} Jede durch einen endlichen Automaten erkennbare Sprache ist regulär! Ein nichtdeterministischer endlicher Automat (kurz NEA) ist ein 5-Tuple M = (Z, Σ, δ, S, E) wobei • Z eine endliche Menge von Zuständen • Σ das endliche Eingabealphabet • V ∩ Σ = 0/ • S ⊆ Z die Menge der Startzustände • E ⊆ Z die Menge der Endzustände • δ : Z × Σ → ℘(Z) die Überführungsfunktion ist. Die Funktion δ kann wieder induktiv auf Wörter erweitert werden zu δ̂ : ℘(Z) × Σ∗ → ℘(Z) durch • δ̂(Z ′ , ε) = Z ′ f uer alle Z ′ ⊆ Z • δ̂(Z ′ , ax) = S z∈Z ′ δ̂(δ(z, a), x) / Die von einem NEA Automaten dargestellte bzw. akzeptierte Sprache T (M) = {x ∈ Σ∗ |δ̂(S, x) ∩ E 6= 0} Jede durch einen NEA akzeptierte Sprache ist auch durch einen DEA akzeptierbar! Sei ein NEA M = (Z, Σ, δ, S, E) gegeben so konstuieren wir durch die Potenzmengenkonstruktion einen DEA M ′ = (Z ′ , Σ, δ′ , z0 , E ′ ) und zwar wie folgt. 14 • Z ′ = ℘(Z) • z0 = S / • E ′ = {Y ⊆ Z|Y ∪ E 6= 0} • δ′ (Y, a) = S y∈Y δ(y, a) = δ̂(Y, a), Y ∈ Z ′ Für jede reguläre Grammatik G gibt es einen NFA M mit L(G) = T (M)! Reguläre Ausdrücke sind spezielle Formen mit denen sprachen definiert werden können. Diese Ausdrücke werden induktiv definiert und zwar • 0/ ist ein regulärer Ausdruck • ε ist ein regulärer Ausdruck • ∀a ∈ Σ ist a ein regulärer Ausdruck • wenn α und β reguläre Ausdrücke sind dann auch αβ, (α|β) und (α)∗ ) Die Semantik der regukären Ausdrücke sollte hinreichend bekannt sein. Für jede reguläre Grammatik G gibt es einen NFA M mit L(G) = T (M)! Um zu zeigen daß eine Sprache nicht regulär ist nutzt man das Pumping Lemma. Sei L eine reguläre Sprache. Dann gibt es eine Zahl n, so dass sich alle Wörter x ∈ L mit |x| ≥ n zerlegen lassen in x = uvw, dass gilt 1. |v| ≥ 1 2. |uv| ≤ n 3. Fuer alle i = 0, 1, 2, . . . gilt uvi w ∈ L Mit dem Pumping Lemma zeigt man durch Widerspruchsbeweis, daß eine Sprache nicht regulär ist. Jeder Sprache L kann man einen Äquivalenzrelation RL auf Σ∗ zuordnen und zwar das gilt: ∀z ∈ Σ∗ : xz ∈ L ⇔ yz ∈ L Eine Sprache L ist genau dann regulär, wenn der Index von RL endlich ist! Der Automat der entsteht wenn man als Zustände die Äquivalenzklassen nutzt heißt Minimalautomat und ist algorithmisch wie folgt konstruierbar: • Eingabe ist ein DFA M und man erhält die Zustände die noch verschmelzbar sind • Erstelle Tabelle von Zustandspaaren (z, z′ ) mit z 6= z′ • Markiere alla Paare die genau einen Terminalzustand enthalten • Für jedes unmarkierte Paar (z, z′ ) und jedes a ∈ Sigma teste ob (δ(z, a), δ(z, a′ )) bereits markiert ist. Wenn ja markiere auch (z, z′ ). • Wiederhole letzten Schritt bis sich keine Änderungen mehr ergeben Die unmarkierten Paare können nun verschmolzen werden. Die Zeitkomplexität des Algorithmus liegt in O(n2 ) 15 7.3 Kontextfreie Sprachen Eine kontextfreie Grammatik G mit ε ∈ / L(G) heißt Chomsky Normalform falls alle Regeln eine der beiden Formen haben A → BC A→a Zu jeder kontextfreien Grammatik G mit ε ∈ / L(G) gibt es eine Chomsky Normalform Grammatik G′ mit L(G) = L(G′ ) Eine kontextfreie Grammatik G mit ε ∈ / L(G) heißt Greibach Normalform falls alle Regeln die Form A → aB1 B2 . . . Bk (k ≥ 0) Zu jeder kontextfreien Grammatik G mit ε ∈ / L(G) gibt es eine Greibach Normalform Grammatik G′ mit ′ L(G) = L(G ) Das Pumping Lemma für kontextfreie Spachen verläuft in Analogie zu den regulären Sprachen. Sei L eine kontextfreie Sprache. Dann gibt es eine Zahl n, so dass sich alle Wörter z ∈ L mit |z| ≥ n zerlegen lassen in z = uvwxy, dass gilt 1. |vx| ≥ 1 2. |vwx| ≤ n 3. Fuer alle i = 0, 1, 2, . . . gilt uvi wxi y ∈ L Mit Hilfe des Pumping Lemmas kann man verifizieren, daß eine kontextfreie Sprache über einen einelementigen Alphabet regulär ist. Der Algorithmus für das Wortproblem hat exponentiellen Aufwand. Der CYK-Algorithmus der dieses Problem für kontextfreie Grammatiken entscheidet hat nur die Komplexität O(n3 ) 1. Sei x die Eingabe und n = |x| dann erstelle eine Matrix n × n. Hierbei ist allerdings nur die obere Diagonalhälfte interessant. Die Spalten der Matrix werden mit den einzelnen Buchstaben benannt. 2. In die erste Zeile trägt man für jeden Buchstaben alle Nichtterminale ein aus denen das Terminal direkt abgeleitet werden kann. 3. Nun geht man Zeile für Zeile vor (Laufvariable j, erste For-Schleife) 4. Für jede Zeile geht man nun Spaltenweise durch (Laufvariable i, zweite For-Schleife) 5. Nun läßt man eine Variable k von 1 bis j-1 (dritte For-Schleife) laufen und trägt Nichtterminale in [j,i] ein falls eine Regel der Form A → BC existiert mit der Eigenschaft daß B in [i,k] und C in [i+k,j-k] steht. 6. Steht nun am Ende an der Stelle [n,1] das Startsymbol ist das Wort in der Sprache. Durch die drei geschachtelten For-Schleifen erreicht man eine Zeitkomplexität von O(n3 ). Ein nichtdeterministischer Kellerautomat (PDA) wird gegeben durch ein 6-Tupel M = (Z, Σ, Γ, δ, z0 , #) mit 16 • Z die endliche Menge der Zustände • Σ das Eingabealphabet • Γ das Kelleralphabet • z0 ∈ Z der Startzustand • # ∈ Γ das unterste Kellerzeichen • σ : Z × (Σ ∪ {ε}) × Γ → ℘e (Z × Γ∗ ) die Überführungsfunktion Intuitiv bedeutet σ(z, a, A) ∋ (z′ , B1 . . . Bk ), daß wenn M sich im Zustand z befindet, a liest und A das oberste Kellerzeichen ist so kann M in den Zustand z′ übergehen und das oberste Kellerzeichen A durch B1 . . . Bk ersetzten (B1 ist dann oberstes Kellerzeichen). Sonderfälle entstehen wenn k = 0 (POP), Bk = A (PUSH) und spontane Übergänge mit δ(z, ε, A). Die von einem Kellerautomaten akzeptierte Sprache ist. N(M) = {x ∈ Σ∗ |(z0 , x, #) ⊢∗ (z, ε, ε) f uer ein z ∈ Z}. Eine Sprache ist kontextfrei genau dann wenn sie von einem PDA erkannt wird! Deterministische PDA spielen im Compilerbau eine große Rolle, da das Wortproblem in linearer Zeit lösbar ist. Ein Beispiel für eine deterministisch kontextfreie Sprache ist L = {a1 . . . an $an . . . a1 |ai ∈ Σ}. 7.4 Kontextsensitive und Typ 0-Sprachen Eine kontextsensitive Grammatik G mit ε ∈ / L(G) heißt Kuroda Normalform falls alle Regeln eine der Formen haben A→a A→B A → BC AB → CD Für jede kontextsensitive Grammatik G mit ε ∈ / L(G) gibt es eine Grammatik G′ in Kuroda Normal′ form mit L(G) = L(G ) Eine Turingmaschine (TM) ist gegeben durch ein 7-Tupel M = (Z, Σ, Γ, δ, z0 , ⋄, E). Hierbei sind • Z die endliche Zustandsmenge • Σ das Eingabealphabet • Γ ⊃ Σ das Arbeitsalphabet • z0 ∈ Z der Startzustand • ⋄ ∈ Γ − Σ das Blank • E ⊆ Z die Menge der Endzustände • δ : Z × Γ → Z × Γ × {L, N, R} im deterministischen Fall bzw. δ : Z × Γ → ℘(Z × Γ × {L, N, R}) im nichtdeterministischen Fall die Überführungsfunktion 17 Die von einer Turingmaschine M akzeptierte Sprache ist T (M) = {x ∈ Σ∗ |z0 x ⊢∗ αzβ; α, β ∈ Γ∗ ; z ∈ E} Durch TM erkennbare Sprachen sind genau die Typ 0-Sprachen! Eine Linear Beschränkte Turingmaschine (LBA) unterscheidet sich nur dadurch von einer TM, daß sie den Bandbereich auf den die Eingabe steht nie verläßt. Hierfür muß noch ein Ende-Symbol eingeführt werden. Dafür verdoppelt man das Eingabealphabet Σ zu Σ′ = Σ ∪ {â|ßnΣ}. Die Eingabe a1 a2 . . . an−1 an wird dann als a1 a2 . . . an−1aˆn aufs Band geschrieben. Es gilt also für eine LBA für alle a1 a2 . . . an−1 an ∈ Σ+ und alle Konfigurationen αzβ mit z0 a1 a2 . . . an−1 aˆn ⊢∗ αzβ daß |αβ| = n. Die von einer LBA akzeptierte Sprache ist T (M) = {a1 a2 . . . an−1 an ∈ Σ∗ |z0 a1 a2 . . . an−1 aˆn ⊢∗ αzβ; α, β ∈ Γ∗ ; z ∈ E} Die von linear beschränkten nichtdeterministischen Turingmaschinen akzeptierten Sprachen sind genau die kontextsensitiven! 7.5 Überblick Beschreibungsmittel Typ 3 reguläre Grammatiken, NFA, DFA, regulärer Ausdruck Typ 2 kontextfreie Grammatiken, PDA Typ 1 kontextsensitive Grammatiken, LBA Typ 0 Typ 0-Grammatiken, TM Abschlußeigenschaften Schnitt Vereinigung Komplement Produkt Stern Typ 3 ja ja ja ja ja Typ 2 nein ja nein ja ja Typ 1 ja ja ja ja ja Typ 0 ja ja nein ja ja Wortproblem Typ 3 lineare Komplexität (Zeichen für Zeichen vergleichen) Typ 2 O(n3 ) CYK Typ 1 exponentielle Komplexität, NP-vollständig Typ 0 unlösbar 8 Berechenbarkeit Churchsche These: Die durch die formale Definition der Turing-Berechenbarkeit erfasste Klasse von Funktionen stimmt genau mit der Klasse der im intuitiven Sinn berechenbaren Funktionen überein 8.1 Turing-Berechenbar N N Eine Funktion f : k → heißt Turing-berechenbar, falls es eine deterministische Turingmaschine M gibt, so daß für alle n1 . . . nk , m ∈ gilt N f (n1, . . . , nk ) = m ⇔ z0 bin(n1 )#bin(n2)# . . . #bin(nk ) ⊢∗ ⋄ . . . ⋄ ze bin(m) ⋄ . . .⋄ wobei ze ∈ E. Eine Funktion f : Σ∗ → Σ∗ heißt Turing-berechenbar, falls es deine deterministische Turingmaschine M gibt, so dass für alle x, y ∈ Σ∗ gilt f (x) = y ⇔ z0 x ⊢∗ ⋄ . . . ⋄ ze y ⋄ . . .⋄ wobei ze ∈ E. 18 8.2 LOOP-Berechenbar Ein LOOP-Programm ist aus folgenden Komponenten aufgebaut • Variablen x0 , x1 . . . • Konstanten 1, 2 . . . • Trennsymbole ; := • Operationszeichen + • Schlüsselwörter LOOP DO END Jede Wertzuweisung der Form xi := x j + c bzw. xi := x j − c ist ein LOOP-Programm. Falls P1 und P2 bereits LOOP-Programme sind dann auch P1 ; P2 . Falls P ein LOOP-Programm und xi eine Variable dann ist auch LOOP xi DO P END ein LOOP-Programm. Die Semantik ist offensichtlich. Anzumerken ist nur daß bei der Ausführung des LOOP schon vorher feststeht wie oft dies geschieht. Das LOOP-Programm P hat also keinen Einfluß auf die Anzahl der Durchläufe. N N Eine Funktion f : k → heißt LOOP-berechenbar, falls es ein LOOP-Programm P gibt, daß f in dem Sinne berechnet, dass P, gestartet mit n1 . . . nk in den Variablen x1 . . . xk (0 im Rest) stoppt mit dem Wert f (n1 . . . nk ) in x0 . 8.3 WHILE-Berechenbar WHILE erweitert LOOP um folgendes Konzept: Falls P ein WHILE-Programm und xi eine Variable, dann ist auch W HILE xi 6= 0 DO P END ein WHILEProgramm. N N Eine Funktion f : k → heißt WHILE-berechenbar, falls es ein WHILE-Programm P gibt, daß f in dem Sinne berechnet, dass P, gestartet mit n1 . . . nk in den Variablen x1 . . . xk (0 im Rest) stoppt mit dem Wert f (n1 . . . nk ) in x0 . Da man WHILE-Schleifen auf Mehrband-Turingmaschinen simulieren kann (i-tes Band = i-te Variable) und man jede Mehrband-Turingmaschine durch eine Ein-Band-Turingmaschine darstellen kann ist offensichtlich daß gilt: Turingmaschinen können WHILE-Programme simulieren. D.h. jede WHILE-Berechenbare Funktion ist auch Turing-berechenbar 8.4 GOTO-Berechenbar Ein GOTO-Programm ist aus folgenden Komponenten aufgebaut • Variablen x0 , x1 . . . • Konstanten 1, 2 . . . • Trennsymbole ; := • Operationszeichen + • Schlüsselwörter GOTO IF THEN HALT Wobei das Programm aus Sequenzen von Anweisungen Ai besteht die jeweils von einer Marke Mi eingeleitet werden. Als mögliche Anweisungen sind zugelassen • Zuweisung xi := x j ± c 19 • unbedingter Sprung GOT O Mi • bedingter Sprung IF xi = c T HEN GOT O Mi • Stopanweisung HALT Es gilt: GOTO-Berechenbar ⇔ Turing-berechenbar ⇔ WHILE-Berechenbar 8.5 Primitiv rekurisve und µ-rekurisve Funktionen Die Klasse der primitiv rekursiven Funktionen ist induktiv definiert 1. Alle konstanten Funktionen sind primitiv rekursiv 2. Alle identischen Abbildungen sind primitiv rekursiv 3. Die Nachfolgerfunktion sind primitiv rekursiv 4. Jede Funktion die durch Komposition von primitiv rekursiven Funktionen entsteht ist primitiv rekursiv 5. Jede Funktion dir durch so genannte primitive Rekursion entsteht ist sind primitiv rekursiv. Primitive Rekursion bedeutet daß die Definition von f (n + 1 . . . zurückgeführt wird auf f (n . . .). Formaler muß f folgendes Gleichungssystem erfüllen f (0, . . .) = g(. . .) und f (n + 1, . . .) = h( f (n, . . .), . . .) wobei h, g bereits primitiv rekursiv ist. Die Klasse der primitiv rekursiven Funktionen stimmt mit derer der LOOP-Berechenbaren überein! Sei f eine gegebene k + 1-stellige Funktion. Die Durch Anwendung des µ − Operators auf f enstehende Funktion ist g : k → mit N N g(x1 , . . . , xk ) = min{n| f (n, x1 , . . . , xk ) = 0 und f ue; alle m < n ist (m, x1 , . . . , xk ) de f iniert} Die Klasse der µ-rekursiven Funktionen stimmt mit der der WHILE-Berechenbaren überein! 8.6 Die Ackermannfunktion Die Achkermannfunktion a(0, y) = y + 1 a(x, 0 = a(x − 1, 1), x > 0 a(x, y) = a(x − 1, a(x, y − 1)), x, y > 0 ist nicht LOOP-berechenbar aber WHILE-berechenbar. Es gibt als totale Funktionen die WHILE aber nicht LOOP-berechenbar sind. 8.7 Entscheidbarkeit,Halteproblem Eine Menge A ⊆ Σ∗ heißt entscheidbar, falls die charakteristische Funktion von A, nämlich χA : Σ∗ → {0, 1}, berechenbar ist. Hierbei ist für alle w ∈ Σ∗ : ( 1, w ∈ A χA (w) = 0, w ∈ /A 20 Eine Menge A ⊆ Σ∗ heißt semi-entscheidbar, falls die charakteristische Funktion von A, nämlich χA : Σ∗ → {0, 1}, berechenbar ist. Hierbei ist für alle w ∈ Σ∗ : ( 1, w∈A χA (w) = unde f iniert, w ∈ /A Eine Sprache A ist entscheidbar wenn sowohl A als auch das Komplement semi-entscheidbar sind! Eine Sprache A ⊆ Σ∗ heißt rekursiv aufzählbar, falls A = 0/ oder falls es eine totale und berechenbare Funktion f : → Σ∗ gibt, so dass A = { f (0), f (1), . . .} N Man sagt daß f A aufzählt. Der unterschied zur einfachen Aufzählbarkeit ist, daß hier die Berechenbarkeit verlangt wird. Eins Sprache ist rekursiv aufzählbar gdw. sie semi-entscheidbar ist! ( M, f alls w Codewort von M Sei Mw = . Unter dem speziellen Halteproblem versteht man die SpraM̂sonst che K = {w ∈ {0, 1}∗ |Mw angesetzt au f w hlt} Das spezielle, das allgemeine und das Halteproblem auf leerem Band sind nicht entscheidbar 8.8 Gödelsche Satz Die Menge der wahren Arithmetischen Formeln ist nicht rekursiv aufzählbar Jedes Beweissystem für die Menge der wahren arithmetischen Formeln ist unvollständig, d.h. es bleiben immer formeln übrig die nicht beweisbar sind! 21