Graphen in Haskell - Otto-von-Guericke

Werbung
Graphen in Haskell
Graphen in Haskell
Gliederung
Algorithmen und Datenstrukturen II
1
Graphen in Haskell
Graphen in Haskell
ADT Graph
Implementierung
Adjazenzlisten
Adjazenzmatrix
D. Rösner
Suche
Institut für Wissens- und Sprachverarbeitung
Fakultät für Informatik
Otto-von-Guericke Universität Magdeburg
Tiefensuche
Breitensuche
Topologisches Sortieren
c
Sommer 2009, 17. April 2009, 2009
D.Rösner
D. Rösner AuD II 2009 . . .
Graphen in Haskell
1
ADT Graph
Implementierung
Suche
Topologisches Sortieren
D. Rösner AuD II 2009 . . .
Graphen in Haskell
Graphen in Haskell
2
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
im ADT Graph sollen Funktionen für die folgenden
Aufgaben realisiert werden:
im folgenden wird ein abstrakter Datentyp (ADT) für
gewichtete Graphen definiert
eine Funktion zum Erstellen eines Graphen aus der Liste
seiner (gewichteten) Kanten (mkGraph)
zu einem beliebigen Knoten wird die Liste adjazenter
Knoten geliefert (adjacent)
alle Knoten des Graphen werden geliefert (nodes)
alle Kanten des Graphen werden geliefert (edgesD, falls
gerichtet, edgesU, falls ungerichtet)
Test, ob eine bestimmte Kante im Graph existiert (edgeIn)
das Gewicht der Kante zwischen zwei Knoten wird geliefert
(weight)
Anpassung an ungewichtete Graphen durch Ignorieren der
Gewichte
Anforderungen an den Typ der Elemente eines Graphen:
Typ der Knoten n: damit Knoten als Indizes von Arrays
genutzt werden können, sollten sie zur Klasse Ix gehören
Typ der Gewichte w: Gewichte sind Zahlen ( class Num)
m.a.W. Typdefinition für Graph als type Graph n w
s. [RL99], Ch. 7.2
s. [RL99], Ch. 7.2
D. Rösner AuD II 2009 . . .
4
D. Rösner AuD II 2009 . . .
5
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Moduldefinition:
Bemerkungen:
module Graph(Graph,mkGraph,adjacent,nodes,edgesU,edgesD,edgeIn,
weight) where
import Array
...
mkGraph :: (Ix n,Num w)
=> Bool -> (n,n) -> [(n,n,w)] -> (Graph n w)
das erste Argument gibt an, ob der Graph gerichtet ist; ist
er ungerichtet, dann werden angegebene Kanten in beiden
Richtungen verwendet, sonst nur in der angegebenen
Form
die Signaturen des ADT Graph ergeben sich wie folgt:
mkGraph :: (Ix n,Num w)
=> Bool -> (n,n) -> [(n,n,w)] -> (Graph n w)
adjacent :: (Ix n,Num w) => (Graph n w) -> n -> [n]
nodes :: (Ix n,Num w) => (Graph n w) -> [n]
edgesU :: (Ix n,Num w) => (Graph n w) -> [(n,n,w)]
edgesD :: (Ix n,Num w) => (Graph n w) -> [(n,n,w)]
edgeIn :: (Ix n,Num w) => (Graph n w) -> (n,n) -> Bool
weight :: (Ix n,Num w) => n -> n -> (Graph n w) -> w
das zweite Argument gibt die Grenzen des Bereichs der
Knoten an
das dritte Argument enthält die Kanteninformation als
Tripel aus den beiden Knoten und dem Gewicht
s. [RL99], Ch. 7.2
s. [RL99], Ch. 7.2
D. Rösner AuD II 2009 . . .
6
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
D. Rösner AuD II 2009 . . .
Graphen in Haskell
Graphen
7
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
12
1
2
78
34
der gewichtete Graph aus [RL99], Fig. 7.1 (c) (s.o.) lässt
sich also wie folgt kreieren:
32
5
44
55
93
3
mkGraph False (1,5) [(1,2,12),(1,3,34),(1,5,78),
(2,4,55),(2,5,32),
(3,4,61),(3,5,44),
(4,5,93)]
4
61
s. [RL99], Ch. 7.2
Abbildung: Beispiele für Graphen: gewichteter ungerichteter Graph
(vgl. [RL99], Fig. 7.1 (c))
D. Rösner AuD II 2009 . . .
8
D. Rösner AuD II 2009 . . .
9
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell
Graphen in Haskell
Implementierung durch Adjazenzlisten
falls Liste verwendet wird, um die Knoteninfo zu verwalten:
type Graph n w =
Implementierung durch Adjazenzlisten
der Graph aus [RL99], Fig. 7.1 (c) (s.o.) lässt sich mit
Array-Funktionen direkt wie folgt kreieren:
[(n, [(n,w)])]
graphAL = array (1,5) [(1,[(2,12),(3,34),(5,78)]),
(2,[(1,12),(4,55),(5,32)]),
(3,[(1,34),(4,61),(5,44)]),
(4,[(2,55),(3,61),(5,93)]),
(5,[(1,78),(2,32),(3,44),(4,93)])]
der Aufwand für den Zugriff auf die Adjazenzliste eines
Knotens n ist dann O(|V|)
für konstanten Aufwand für den Zugriff auf die
Adjazenzliste eines Knotens empfiehlt sich als Alternative
ein Array, um die Knoteninfo zu verwalten:
type Graph n w =
ADT Graph
Implementierung
Suche
Topologisches Sortieren
weniger aufwändig ist die (ohnehin empfohlene) Nutzung
von mkGraph aus dem ADT (s.o.)
Array n [(n,w)]
s. [RL99], Ch. 7.2.2
s. [RL99], Ch. 7.2.2
D. Rösner AuD II 2009 . . .
Graphen in Haskell
11
D. Rösner AuD II 2009 . . .
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell
12
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Implementierung der Funktionen des ADT Graph durch
Adjazenzlisten
Implementierung der Funktionen des ADT Graph durch
Adjazenzlisten
mkGraph:
mkGraph dir bnds es =
accumArray (\xs x -> x:xs) [] bnds
([(x1,(x2,w)) | (x1,x2,w) <- es] ++
if dir then []
else [(x2,(x1,w))|(x1,x2,w)<-es,x1/=x2])
adjacent g v
= map fst (g!v)
nodes g
= indices g
edgeIn g (x,y) = elem y (adjacent g x)
weight x y g
= head [ c | (a,c)<-g!x , a==y]
edgesD g = [(v1,v2,w)| v1<- nodes g, (v2,w) <-g!v1]
s. [RL99], Ch. 7.2.2
edgesU g = [(v1,v2,w)| v1<- nodes g, (v2,w) <-g!v1, v1 < v2]
s. [RL99], Ch. 7.2.2
D. Rösner AuD II 2009 . . .
13
D. Rösner AuD II 2009 . . .
14
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Implementierung der Funktionen des ADT Graph mit einer
Adjazenzmatrix
Erinnerung:
Implementierung der Funktionen des ADT Graph mit einer
Adjazenzmatrix
möglicher Typ:
ob zwischen zwei Knoten eines Graphen eine Kante
vorliegt, wird durch einen Eintrag in einer
zweidimensionalen quadratischen Matrix repräsentiert
die Koordinaten repräsentieren die Knoten und es gilt, dass
im Matrixelement (i, j) genau dann ein Eintrag vorliegt,
wenn zwischen den Knoten vi und vj eine Kante existiert
type Graph n w = Array (n,n) w
zu klären ist, mit welchem Eintrag ausgedrückt wird, dass
keine Kante zwischen zwei Knoten vorliegt
um die möglichen Werte für Gewichte nicht zu sehr
einzuschränken, empfiehlt sich hier die Verwendung des
algebraischen Typs Maybe
möglicher Typ:
type Graph n w = Array (n,n) w
s. [RL99], Ch. 7.2.3
s. [RL99], Ch. 7.2.3
D. Rösner AuD II 2009 . . .
Graphen in Haskell
15
D. Rösner AuD II 2009 . . .
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell: Adjazenzmatrix
16
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell: Adjazenzmatrix
damit Implementierung von mkGraph
zunächst wird die Matrix mit Nothing vorbelegt
(emptyArray)
dann werden – mit Unterscheidung zwischen gerichtetem
und ungerichtetem Fall – Kantengewichte als Werte der
Form Just w eingefügt
Einschub:
der Typ Maybe a besteht aus den möglichen Werten
Nothing und
Just a
der Code:
in unserem Fall repräsentiert Nothing dann, dass keine
Kante
vorhandene Gewichte sind in der Form Just a in der
Matrix eingetragen vorliegt
mkGraph dir bnds@(l,u) es
= emptyArray // ([((x1,x2),Just w) |(x1,x2,w)<-es] ++
if dir then []
else
[((x2,x1),Just w) |(x1,x2,w)<-es,x1/=x2])
where
emptyArray
= array ((l,l),(u,u))
[((x1,x2),Nothing) | x1 <- range bnds,
x2 <- range bnds]
damit modifizierter Typ:
type Graph n w = Array (n,n) (Maybe w)
s. [RL99], Ch. 7.2.3
s. [RL99], Ch. 7.2.3
D. Rösner AuD II 2009 . . .
17
D. Rösner AuD II 2009 . . .
18
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell: Adjazenzmatrix
Graphen in Haskell: Adjazenzmatrix
Implementierung weiterer Funktionen des ADT Graph
Implementierung weiterer Funktionen des ADT Graph
edgesD g
= [(v1,v2,unwrap(g!(v1,v2)))
| v1 <-nodes g, v2 <- nodes g,
edgeIn g (v1,v2)]
where unwrap (Just w) = w
adjacent g v1 = [ v2 | v2 <-nodes g,(g!(v1,v2))/= Nothing]
nodes g
ADT Graph
Implementierung
Suche
Topologisches Sortieren
= range (l,u) where ((l,_),(u,_)) = bounds g
edgesU g
= [(v1,v2,unwrap(g!(v1,v2)))
| v1 <-nodes g, v2 <- range (v1,u),
edgeIn g (v1,v2)]
where (_,(u,_)) = bounds g
unwrap (Just w) = w
edgeIn g (x,y)= (g!(x,y)) /= Nothing
weight x y g
= w where (Just w) = g!(x,y)
s. [RL99], Ch. 7.2.3
s. [RL99], Ch. 7.2.3
D. Rösner AuD II 2009 . . .
Graphen in Haskell
19
ADT Graph
Implementierung
Suche
Topologisches Sortieren
D. Rösner AuD II 2009 . . .
Graphen in Haskell
Graphen in Haskell: Suche
20
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell: Suche
Variante: statt in jedem Schritt die Liste besuchter Knoten
zu durchlaufen, um den aktuellen Knoten anzuhängen
(also: vis++[c]), wird stattdessen einmal an Ende die
Liste besuchter Knoten umgedreht
zugehöriger Code:
die Funktion depthFirstSearch nimmt einen
Startknoten und einen Graphen und liefert die Liste der bei
einer Tiefensuche erreichten Knoten zurück
Variante 1:
depthFirstSearch start g = dfs [start] []
where
dfs [] vis
= vis
dfs (c:cs) vis
| elem c vis = dfs cs vis
| otherwise = dfs ((adjacent g c)++cs) (vis++[c])
depthFirstSearch’ start g = reverse (dfs [start] [])
where
dfs [] vis
= vis
dfs (c:cs) vis
| elem c vis = dfs cs vis
| otherwise = dfs ((adjacent g c)++cs) (c:vis)
s. [RL99], Ch. 7.3
s. [RL99], Ch. 7.3
D. Rösner AuD II 2009 . . .
22
D. Rösner AuD II 2009 . . .
23
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell: Suche
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell: Suche
bei Breitensuche erfolgt die Verwaltung der
Kandidatenknoten mit einer Queue (nach dem
FIFO-Prinzip)
zugehöriger Code:
Variante: die Verwaltung der Kandidatenknoten erfolgt mit
einem Stack
zugehöriger Code:
depthFirstSearch’’ start g
= reverse (dfs (push start emptyStack) [])
where
dfs s vis
| (stackEmpty s) = vis
| elem (top s) vis = dfs (pop s) vis
| otherwise = let c = top s
in dfs (foldr push (pop s) (adjacent g c))
(c:vis)
breadthFirstSearch start g
= reverse (bfs (enqueue start emptyQueue) [])
where
bfs q vis
| (queueEmpty q) = vis
| elem (front q) vis = bfs (dequeue q) vis
| otherwise = let c = front q
in bfs (foldr enqueue (dequeue q)
(adjacent g c))
(c:vis)
s. [RL99], Ch. 7.3
s. [RL99], Ch. 7.3
D. Rösner AuD II 2009 . . .
Graphen in Haskell
24
ADT Graph
Implementierung
Suche
Topologisches Sortieren
D. Rösner AuD II 2009 . . .
Graphen in Haskell
Graphen in Haskell: Topologisches Sortieren
25
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell: Topologisches Sortieren
Vorgehen:
das komplette Programm
der Algorithmus zum topologischen Sortieren arbeitet – wie
Tiefensuche und Breitensuche – mit den beiden Listen der
Kandidatenknoten und der besuchten Knoten
die Aktualisierung geschieht wie folgt:
inDegree g n
= length [t | v<-nodes g, t<-adjacent g v, (n==t)]
topologicalSort g
= tsort [n | n<-nodes g , (inDegree g n == 0)] []
where
tsort [] r
= r
tsort (c:cs) vis
| elem c vis = tsort cs vis
| otherwise = tsort cs (c:(tsort (adjacent g c) vis))
Kandidaten: (c:cs) → cs
besucht: vis → c:(tsort (adjacent g c) vis)
m.a.W.: wenn ein Knoten als besucht eingereiht wird,
geschieht dies vor seinen (rekursiv) topologisch sortierten
adjazenten Knoten
die initiale Liste von Kandidaten ergibt sich aus den Knoten
ohne vorausgehende Knoten
s. [RL99], Ch. 7.4
s. [RL99], Ch. 7.4
D. Rösner AuD II 2009 . . .
27
D. Rösner AuD II 2009 . . .
28
Graphen in Haskell
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell
Graphen in Haskell: Topologisches Sortieren
ADT Graph
Implementierung
Suche
Topologisches Sortieren
Graphen in Haskell: Topologisches Sortieren
Anwendung auf einen Graph mit Information zu
Lehrveranstaltungen
Anwendung auf einen Graph mit Information zu
Lehrveranstaltungen
data Courses = Maths | Theory | Languages | Programming
| Concurrency| Architecture | Parallelism
deriving (Eq,Ord,Enum,Ix,Show)
? topologicalSort cg
[Architecture, Programming, Concurrency,
Parallelism, Languages, Maths, Theory]
cg = mkGraph True (Maths,Parallelism)
[(Maths,Theory,1), (Languages,Theory,1),
(Programming,Languages,1),
(Programming,Concurrency,1),
(Concurrency,Parallelism,1),
(Architecture,Parallelism,1)]
s. [RL99], Ch. 7.4
s. [RL99], Ch. 7.4
D. Rösner AuD II 2009 . . .
Graphen in Haskell
29
ADT Graph
Implementierung
Suche
Topologisches Sortieren
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 . . .
31
D. Rösner AuD II 2009 . . .
30
Herunterladen