Heuristische Suchverfahren versuchen, optimale oder wenigstens annähernd optimale Lösung in exponentiell großem Lösungsraum durch problemspezifische Information zu finden. I. II. Ansätze, die Lösung schrittweise konstruieren (A*, Greedy-Verfahren) Verbesserungsverfahren: starten mit zufällig gewählter vollständiger Lösung und versuchen diese zu verbessern. Zu I: Greedy Algorithmen Lösen von Optimierungsproblemen: gegeben: Gütefunktion w für Lösungen und Teillösungen optimale Lösung konstruiert durch schrittweises Erweitern einer unvollständigen Teillösung. Ausgangspunkt ist leere Lösung. Von allen Erweiterungsmöglichkeiten wird jeweils diejenige gewählt, die zu größtem (bzw. kleinstem) w-Wert führt (greedy = gefräßig, der größte Bissen wird jeweils geschluckt) Beispiele: Auftragsplanung: Gegeben: Menge A von n "Aufträgen", jeweils in einer Zeiteinheit zu bewältigen, zu jedem Auftrag i gibt es Gewinn pi und Termin di, an dem er abgeschlossen sein muss (sonst kein Gewinn). Gesucht: Menge M von Aufträgen, so dass a) M sich so sortieren lässt, dass jeder Auftrag vor seinem Abschlusstermin erledigt wird und b) der Gesamtgewinn maximal ist. Beispiel: Job 1 2 3 4 Gewinn 20 25 10 5 Lösung 3,2,4 4,2 1,2,4 Deadline 2 2 1 3 Gewinn 40 30 50 beste Lösung Greedy Algorithmus: Ordne Aufträge nach absteigenden Gewinnen: p1 ≥ p2 ≥ ...≥ pn; A := {}; for i:= 1 to n do if A {i} ist zulässige Lösung then A := A {i}; Gib A aus Bemerkung: 1. es ist wesentlich, dass eine Menge von Aufträgen erzeugt wird, die dann noch in Reihenfolge gebracht werden muss, nicht direkt eine Folge. 2. Aus diesem Algorithmus erhält man den kanonischen Greedy-Algorithmus, wenn man statt der Gewinne eine entsprechende Wertefunktion w verwendet: kanonischer Greedy Algorithmus: Gegeben: endliche Menge E von Lösungskomponenten, U Pot(E) Menge der möglichen Lösungen, Wertefunktion w: E -> R Ordne Elemente ei aus E nach absteigenden Gewinnen, so dass w(e1) ≥ w(e2) ≥ ...≥ w(en); A := {}; for i:= 1 to n do if A {i} U then A := A {i}; output A Für Korrektheitsbeweis allgemeinere Betrachtung: Sei E endliche Menge, U Menge von Teilmengen von E. (E,U) heißt Teilmengensystem, falls gilt: 1. {} U; 2. A B, B U => A U Ein Teilmengensystem heißt Matroid, wenn folgende Austauscheigenschaft gilt: X, Y U, |X| < |Y| => x Y - X: X {x} U Es gilt folgender Satz: Sei (E,U) ein Teilmengensystem. Der kanonische Greedy-Algorithmus liefert für das zugehörige Optimierungsproblem (finde für beliebige Wertefunktion w: E -> R eine Lösung, so dass die Summe der Werte ihrer Komponenten maximal ist) die optimale Lösung gdw. (E,U) ein Matroid ist. Mit diesem Satz ergibt sich Korrektheit des Auftragsplanungsalgorithmus direkt aus entsprechender Matroideigenschaft: E: Menge A von Aufträgen U: Menge L(A) von Lösungen, d.h. Aufträgen, so dass Sortierung entsprechend deadline möglich ist Es gilt offensichtlich (A, L(A)) ist Teilmengensystem. Nachweis der Austauscheigenschaft: Sei b ein Element in Y-X mit größter (= spätester) deadline. Dieses Element kann zu X hinzugefügt werden, ohne Lösungseigenschaft zu verletzen. Typ II-Verfahren: Hill Climbing Starte mit beliebiger vollständiger Lösung, modifiziere sie nach bestimmten Regeln und/oder zufällig. Wenn neu erzeugte Lösung besser ist als alte, übernimm sie und mache so weiter. Erzeuge Anfangslösung l; repeat modifiziere l zu l'; if l' besser als l then l := l’ until längere Zeit keine Verbesserung; Gib l als akzeptable Lösung aus Problem: lokale Optima, möglicherweise keine benachbarte (= durch Modifikation herstellbare) Lösung besser als aktuelle Lösung. Kann dadurch vermindert werden, dass man Verfahren wiederholt mit neuer Zufallslösung startet, bisher beste alte Lösung wird vermerkt. Beispiel: Traveling Salesman Problem (TSP) Annahme: Entfernungsmatrix symmetrisch Initialisierung: zufällig erzeugte Permutation lokale Verbesserung: wähle 2 Städte vi, vj zufällig (o.B.d.A. i < j), falls M[vi,vi+1] + M[vj,vj+1] > M[vi,vj] + M[vi+1,vj+1] so ersetze bisherige Rundreise durch v1, v2 , ... , vi , vj, vj-1,..., vi+2, vi+1, vj+1, ..., vn D.h.: vi mit vj verbunden, vi+1 mit vj+1, Teil der Rundreise zwischen vj und vi+1 andersherum. vi+1 vj vi vj+1 vi+1 vj vi vj+1 Beispiel 2: Erfüllbarkeit aussagenlogischer Formeln in 3-KNF F in 3-KNF gdw F ist Konjunktion von Disjunktionen von Literalen (aussagenlogische Variablen und deren Negation). Pro Disjunktion 3 Literale (p v ¬q v r) & (¬p v q v s) & ... Gesucht: Wahrheitsbelegung I: V -> {w,f} der Variablen, so dass Formel wahr wird (F wahr gdw. alle Disjunktionen in F wahr, Disjunktion wahr gdw. mindestens ein Literal wahr, Literal L wahr gdw. L = ¬v und I(v) = f oder L = v und I(v) = w. Algorithmus: Wähle zufällig Anfangsbelegung I while es gibt I', so daß 1) I' unterscheidet sich von I im Wahrheitswert genau einer Variable und 2) I' macht mehr Disjunktionen wahr als I I := I'; if I erfüllt alle Disjunktionen then write('erfüllbar') else write('nicht erfüllbar') Überraschend gute Ergebnisse: Wahrscheinlichtkeit, dass man für Formel mit n=200 Variablen erfüllende Interpretation nicht findet, obwohl es sie gibt etwa 2,15 · 10-16. Genetische Algorithmen Versuchen, natürliche Evolutionsprozesse nachzubilden. Nicht einzelne Lösung wird verbessert, sondern Population vom Lösungen. Sowohl zufällige Änderungen (Mutationen) als auch Kreuzungen (Cross-over) von Lösungen. Lösungen mit besten Bewertungen (Fitness) überleben jeweils. Algorithmus: erzeuge zufällig Anfangspopulation von Lösungen P = {a1,...,am}; repeat erzeuge bestimmte Anzahl zufälliger Mutationen der Lösungen in P; erzeuge bestimmte Anzahl zufälliger Kreuzungen von Lösungspaaren aus P; bewerte Fitness aller erhaltenen Lösungen; wähle die m fittesten Lösungen aus und weise diese P zu until keine weitere Verbesserung der Fitness gib die in der erhaltenen Population fitteste Lösung aus Kreuzung: einfach, wenn Lösungen als Bitstrings codiert sind: werden an geeigneter Stelle aufgeschnitten und neu zusammengesetzt. Manchmal weniger offensichtlich. Beispiel TSP. 2 Lösungen: v = (v1,..., vn) w = (w1,..., wn) Nicht einfach Vorderteil von v mit Reststück von w kombinierbar. Idee: wähle beliebigen Ausschnitt v' von v und nimm aus w der Reihe nach die Nachfolger des letzten Elements von v', die noch nicht enthalten sind. Beispiel: v = (1 5 9 7 4 6 2 3 8) w = (7 6 2 9 5 1 3 4 8) zufällig gewählte Teilfolge: 5 9 7 4 neue Rundreise: (5 9 7 4 8 6 2 1 3)