Entwurfstechniken für Algorithmen II Entwurfstechniken für Algorithmen II Gliederung Algorithmen und Datenstrukturen II 1 Entwurfstechniken für Algorithmen Einführung Vorgehen Anwendung Schiebe-Puzzle D. Rösner Gierige Suche Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg Einführung Implementation Beispiel: Geldwechsel-Problem Beispiel: Prim’ MST-Algorithmus c Sommer 2009, 21. Juni 2009, 2009 D.Rösner D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche 1 Diskussion Prioritätsgesteuerte Suche Gierige Suche D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Entwurfstechniken für Algorithmen 2 Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche Suche mit Backtracking besonders gut für Spielstrategien aber: aufwändig, besonders bei grossen Suchräumen daher: Varianten, bei denen versucht wird, Aufwand zu verringern Entwurfstechnik ’Prioritätsgesteuerte Suche’ einfache Suche mit Backtracking wird auch bezeichnet als uninformierte Suche ( engl. unguided search) oder blinde Suche ( engl. blind search) Prioritätsgesteuerte Suche (engl. priority-first search): Kandidaten werden danach geordnet, wie vielversprechend sie für mögliche Lösung sind Gierige Suche (engl. greedy search): aus den unmittelbaren Nachfolgern eines Knotens wird nur die lokal beste Alternative verfolgt Grund: es wird keine Information über Unterschiede zwischen Kandidatenknoten ausgenutzt s.a. [RL99], Ch. 8.2 s.a. [RL99], Ch. 8.2.6, 8.3, 8.4 D. Rösner AuD II 2009 . . . 4 D. Rösner AuD II 2009 . . . 6 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche um aus der Funktion höherer Ordnung für Suche mit Backtracking eine allgemeine Lösung für Prioritätsgesteuerte Suche zu machen, müssen lediglich Operationen aus dem ADT Stack gegen entsprechende aus dem ADT für Prioritätswarteschlangen ausgetauscht werden bei ’Prioritätsgesteuerter Suche’ wird eine Bewertungsfunktion für Kandidatenknoten definiert eine solche Vergleichsfunktion erlaubt es, Kandidatenknoten in einer Prioritätswarteschlange nach höchster Priorität (oder niedrigsten Kosten) zu organisieren searchPfs succ goal x = search’ (enPQ x emptyPQ) 0 where search’ q t | (pqEmpty q) = [] | goal (frontPQ q) = ((frontPQ q),t+1):(search’ (dePQ q)(t+1)) | otherwise = let x = frontPQ q in search’ (foldr enPQ (dePQ q) (succ x)) (t+1) da immer der vielversprechendste Kandidat zuerst untersucht wird, wird diese Form der Suche auch best-first search genannt s.a. [RL99], Ch. 8.2 s.a. [RL99], Ch. 8.3.1 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 7 Diskussion Prioritätsgesteuerte Suche Gierige Suche D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche 8 Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche wenn bei Vergleichsoperation keine exakte Bewertung, sondern nur eine Schätzung möglich, spricht man von einer Heuristik um den vielversprechendsten (also ’kleinsten’) Knoten an die Spitze der Prioritätswarteschlange platzieren zu können Suche mit Prioritätswarteschlange unter Verwendung einer Heuristik wird auch als heuristische Suche (engl. heuristic search) bezeichnet muss eine überladene Vergleichsoperation (typischerweise <=) für Knoten definiert werden Vergleichen aller Kandidatenknoten bezüglich einer (heuristischen) Bewertungsfunktion führt zu zusätzlichem Speicher- und Zeitaufwand s.a. [RL99], Ch. 8.3.1 s.a. [RL99], Ch. 8.3.1 D. Rösner AuD II 2009 . . . 9 D. Rösner AuD II 2009 . . . 10 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche Schiebe-Puzzle mit acht Kacheln (eight-puzzle): um zu bewerten, wie nah oder fern eine Kandidatenkonfiguration vom Zielzustand ist, wird für jede Kachel die Manhattan-Distanz zwischen aktueller und Zielposition bestimmt und über diese Werte summiert in Haskell: Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Überladene Gleichheits- bzw. Ordnungsbeziehungen für Anordnungen des Schebepuzzle: instance Eq Boards where BDS(b1:_) == BDS(b2:_) = heur1 b1 == heur1 b2 heur1 :: Board -> Int heur1 b = sum [ mandist (b!i) (g8T!i) | i<-[0..8]] instance Ord Boards where BDS (b1:_) <= BDS (b2:_) = heur1 b1 <= heur1 b2 Frage: welche Verallgemeinerung ist naheliegend? ............................................ ............................................ ............................................ s.a. [RL99], Ch. 8.3.2 s.a. [RL99], Ch. 8.3.2 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 11 Diskussion Prioritätsgesteuerte Suche Gierige Suche D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche 12 Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Aufwandsangaben für Bestimmung einer Lösung: Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Variante der Heuristik: bisher wird nur die Summe der Manhattan-Abstände zur Zielposition berücksichtigt, relevant ist aber auch, ob Kacheln zwar nicht an der Endposition, aber bereits relativ zueinander in der richtigen Reihung sind. stats = (length ls , t) where (((BDS ls),t):_) = searchPfs succ8Tile goal8Tile (BDS [s8T]) Ergebnis: Main> stats (25,36) Heuristik 2 kombiniert dann beide Informationen s.a. [RL99], Ch. 8.3.2 s.a. [RL99], Ch. 8.3.2 D. Rösner AuD II 2009 . . . 13 D. Rösner AuD II 2009 . . . 14 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche Schiebe-Puzzle mit acht Kacheln (eight-puzzle): spezielle Bewertungsfunktion: Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Bewertung (score) für relative Abweichung von Endreihung score :: Position -> Position -> Int score (2,2) _ = 1 Kachel im Zentrum erhält Gewicht 1 Kachel nicht im Zentrum führt zu Gewicht 0, wenn der gemäss Zielvorgabe erwartete Nachfolger (bei Zählung im Uhrzeigersinn) unmittelbar folgt in allen anderen Fällen führt Kachel zu Gewicht 2. score score score score score score score score wichtig: diese Gewichte rechtfertigen sich aus der speziellen Zielkonstellation und sind für andere Konfigurationen anzupassen (1,3) (2,3) (3,3) (3,2) (3,1) (2,1) (1,1) (1,2) score _ _ (2,3) (3,3) (3,2) (3,1) (2,1) (1,1) (1,2) (1,3) = = = = = = = = 0 0 0 0 0 0 0 0 = 2 s.a. [RL99], Ch. 8.3.2 s.a. [RL99], Ch. 8.3.2 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 15 Diskussion Prioritätsgesteuerte Suche Gierige Suche D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche 16 Diskussion Prioritätsgesteuerte Suche Gierige Suche Prioritätsgesteuerte Suche Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Schiebe-Puzzle mit acht Kacheln (eight-puzzle): Überladen von Gleichheit- bzw. Ordnungsbeziehung: Summierung: outseq :: Board -> Int outseq b = sum [score (b!i) ((b!(i+1)))|i<-[1..7]] +score (b!8) (b!1) instance Eq Boards where BDS(b1:_) == BDS(b2:_) = heur2 b1 == heur2 b2 instance Ord Boards where BDS (b1:_) < BDS (b2:_) = heur2 b1 < heur2 b2 BDS (b1:_) <= BDS (b2:_) = heur2 b1 <= heur2 b2 Heuristik 2: heur2 :: Board -> Int heur2 b = (heur1 b) + 3*(outseq b) s.a. [RL99], Ch. 8.3.2 s.a. [RL99], Ch. 8.3.2 D. Rösner AuD II 2009 . . . 17 D. Rösner AuD II 2009 . . . 18 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prioritätsgesteuerte Suche Diskussion Prioritätsgesteuerte Suche Gierige Suche Gierige Suche beim Ansatz der gierigen Suche (engl. greedy search) wird Schiebe-Puzzle mit acht Kacheln (eight-puzzle): nach Überladen von Gleichheit- bzw. Ordnungsbeziehung: von den unmittelbaren Nachfolgern des aktuellen Knotens immer der lokal beste gewählt und alle anderen Alternativen werden aufgegeben (m.a.W. keine Verwaltung von Alternativen, kein Backtracking). Lösung wird auf einem Pfad erreicht. Main> stats (19,68) s.a. [RL99], Ch. 8.3.2 Problem: lokale Minima s.a. [RL99], Ch. 8.4 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II D. Rösner AuD II 2009 . . . 19 Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Gierige Suche 21 Diskussion Prioritätsgesteuerte Suche Gierige Suche Gierige Suche als Funktion höherer Ordnung ergibt sich das Greedy-Vorgehen durch eine leichte Modifikation der Lösung für prioritätsgesteuerte Suche: Funktion höherer Ordnung für das Greedy-Vorgehen searchGreedy :: (Ord node) => (node -> [node]) -> (node -> Bool) -> node -> [node] searchGreedy succ goal x = (search’ (enPQ x emptyPQ)) where search’ q | (pqEmpty q) = [] | goal (frontPQ q) = [frontPQ q] | otherwise = let x = frontPQ q in search’ (foldr enPQ emptyPQ (succ x)) wenn zu den Nachfolgerknoten übergegangen wird, wird eine neue Prioritätswarteschlange angelegt ( emptyPQ) und damit werden die verbliebenen Kandidaten aus dem vorausgegangenen Schritt aufgegeben ausserdem: keine Suche nach weiteren Lösungen, wenn ein Knoten den Zieltest erfüllt s.a. [RL99], Ch. 8.4 s.a. [RL99], Ch. 8.4.1 D. Rösner AuD II 2009 . . . 22 D. Rösner AuD II 2009 . . . 23 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Gierige Suche Diskussion Prioritätsgesteuerte Suche Gierige Suche Geldwechsel-Problem Ansatz: in jedem Schritt wird diejenige Münze mit höchstem Nennwert gewählt, deren Wert kleiner oder gleich dem (noch) darzustellendem Betrag ist Problem: ein Geldbetrag soll mit der kleinstmöglichen Zahl von Münzen (aus einem vorgegebenen Münzsystem) gegeben werden für Münzsysteme wie beim Euro garantiert dieses ’gierige’ Vorgehen immer eine optimale Lösung aber: es gab auch Münzsysteme, wo dies nicht der Fall ist: Beispiel: 218 Cent mit den Münzen des Euro-Systems darstellen ............................................ ............................................ ............................................ Beispiel: in England gab es Münzen der Nennwerte 30p, 24p, 12p, 6p, 3p und 1p der Greedy-Ansatz würde 48p wechseln in die drei Münzen 30p, 12p und 6p optimal wäre aber nur zwei Münzen mit 24p s.a. [RL99], Ch. 8.4.2 s.a. [RL99], Ch. 8.4.2 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Geldwechsel-Problem 25 Diskussion Prioritätsgesteuerte Suche Gierige Suche Geldwechsel-Problem Implementation einer Lösung mit Greedy Search eine Lösung ist eine Liste von Nennwerten von Münzen Implementation einer Lösung mit Greedy Search das Münzsystem: type Coin D. Rösner AuD II 2009 . . . 24 type SolChange = [Coin] = Int ein Knoten ist charakterisiert durch den verbliebenen Betrag und die bisherige Liste von Nennwerten von Münzen coins :: [Coin] coins = [1,2,5,10,20,50,100] type NodeChange = (Int , SolChange) s.a. [RL99], Ch. 8.4.2 s.a. [RL99], Ch. 8.4.2 D. Rösner AuD II 2009 . . . 26 D. Rösner AuD II 2009 . . . 27 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Geldwechsel-Problem Diskussion Prioritätsgesteuerte Suche Gierige Suche Geldwechsel-Problem Implementation einer Lösung mit Greedy Search die Nachfolger-Funktion produziert als mögliche neue Knoten alle Beträge, bei denen eine Münze vom aktuellen Betrag abgezogen werden konnte Implementation einer Lösung mit Greedy Search für Knoten vom Typ NodeChange existiert eine kanonische Ordnung nach zunächst erster Komponente, dann succCoins :: NodeChange -> [NodeChange] succCoins (r,p) = [ (r-c,c:p) | c <- coins , r - c >=0 ] ggf. nach zweiter Komponente damit Lösung: ein Zielknoten liegt vor, wenn kein zu wechselnder Betrag mehr vorliegt change :: Int -> SolChange change amount = snd(head(searchGreedy succCoins goalCoins (amount,[]))) goalCoins :: NodeChange -> Bool goalCoins (v,_) = v==0 s.a. [RL99], Ch. 8.4.2 s.a. [RL99], Ch. 8.4.2 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 28 Diskussion Prioritätsgesteuerte Suche Gierige Suche D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II Geldwechsel-Problem 29 Diskussion Prioritätsgesteuerte Suche Gierige Suche Gierige Suche Implementation einer Lösung mit Greedy Search naheliegende Verallgemeinerung: succCoins’ :: [Coin] -> NodeChange -> [NodeChange] succCoins’ coins (r,p) = [(r-c,c:p)| c <- coins , r - c >=0 ] oft lässt sich ein bekannter Algorithmus als Anwendung des Greedy-Verfahrens interpretieren change’ :: [Coin] -> Int -> SolChange change’ coins amount = snd(head(searchGreedy (succCoins’ coins) goalCoins (amount,[]))) dies gilt z.B für Prim’s Algorithmus zur Bestimmung eines minimalen aufspannenden Baumes (MST) s.a. [RL99], Ch. 8.4.3 damit: Main> change’ [1,3,6,12,24,30] 48 [6,12,30] s.a. [RL99], Ch. 8.4.2 D. Rösner AuD II 2009 . . . 30 D. Rösner AuD II 2009 . . . 31 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Graphen Diskussion Prioritätsgesteuerte Suche Gierige Suche Prim’ MST-Algorithmus Zur Erinnerung: Algorithmus von Prim (publiziert 1957) Grundidee: Welche Information enthalten die Knoten im Suchbaum? die Mengen T und R von Knoten (als Listen) das Gewicht der gewählten Kante (u, v ) mit u ∈ T und v ∈R die partielle bisherige Lösung, dargestellt als Liste von (gewichteten) Kanten es wird mit den Knoten des Graphen gearbeitet die Menge der Knoten wird dynamisch in zwei Mengen geteilt: T enthält diejenigen Knoten, die bereits im Baum sind, und R enthält diejenigen , die (noch) nicht im Baum sind als Typinfo: Ausgangspunkt, d.h. erstes Element von T , ist ein willkürlich gewählter Knoten in jedem Schritt wird aus der Menge derjenigen Kanten (u, v ) mit u ∈ T und v ∈ R die Kante mit den geringsten Kosten ausgewählt der Algorithmus endet, sobald R leer ist type Edge a b = (a,a,b) type NodeMst a b = (b , [a] ,[a], [Edge a b]) s. u.a. [RL99], Ch. 8.4.3 s. u.a. [RL99], Ch. 7.5.2 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 32 Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prim’ MST-Algorithmus Diskussion Prioritätsgesteuerte Suche Gierige Suche das Ziel ist erreicht, wenn R leer ist also: goalMst (_,_,[],_) = True goalMst _ = False (NodeMst a b) b)] r, (x,y,weight x y g):mst) (x,y)] s. u.a. [RL99], Ch. 8.4.3 D. Rösner AuD II 2009 . . . 33 Prim’ MST-Algorithmus die Bestimmung der Kandidatenknoten erfolgt unter Verwendung des Graphen: succMst :: (Ix a,Num b) => (Graph a b) -> -> [(NodeMst a succMst g (_,t,r,mst) = [(weight x y g, (y:t), delete y | x <- t , y <- r, edgeIn g D. Rösner AuD II 2009 . . . prim g = sol where [(_,_,_,sol)] = searchGreedy (succMst g) goalMst (0,[n],ns,[]) (n:ns) = nodes g s. u.a. [RL99], Ch. 8.4.3 34 D. Rösner AuD II 2009 . . . 35 Entwurfstechniken für Algorithmen II Diskussion Prioritätsgesteuerte Suche Gierige Suche Entwurfstechniken für Algorithmen II Prim’ MST-Algorithmus Diskussion Prioritätsgesteuerte Suche Gierige Suche Prim’ MST-Algorithmus Beispiel: graphEx::(Graph Int Int) graphEx = mkGraph True (1,5) [(1,2,12),(1,3,34),(1,5,78),(2,1,12),(2,5,32),(2,4,55), (3,1,34),(3,5,44),(3,4,61),(4,2,55),(4,3,61),(4,5,93), (5,1,78),(5,2,32),(5,3,44),(5,4,93)] Ergebnis: > prim graphEx [(2, 4, 55), (1, 3, 34), (2, 5, 32), (1, 2, 12)] s. u.a. [RL99], Ch. 8.4.3 s. u.a. [RL99], Ch. 8.4.3 D. Rösner AuD II 2009 . . . Entwurfstechniken für Algorithmen II 36 Diskussion Prioritätsgesteuerte Suche Gierige Suche Literatur: I Fethi Rabhi and Guy Lapalme. Algorithms – A Functional Programming Approach. Pearson Education Ltd., Essex, 1999. 2nd edition, ISBN 0-201-59604-0. D. Rösner AuD II 2009 . . . 38 D. Rösner AuD II 2009 . . . 37