270 likes | 383 Vues
Advanced Functional Programming. Tim Sheard Oregon Graduate Institute of Science & Technology. Lecture 17: Erwig style - Functional Graphs DFS – style of depth first search. References. The style of representing graphs, and most of the examples, come from the work of Martin Erwig
E N D
Advanced Functional Programming • Tim Sheard • Oregon Graduate Institute of Science & Technology • Lecture 17: • Erwig style - Functional Graphs • DFS – style of depth first search
References • The style of representing graphs, and most of the examples, come from the work of Martin Erwig • http://www.cs.orst.edu/~erwig/ • Functional Programming with Graphs • 2nd ACM SIGPLAN Int. Conf. on Functional Programming(ICFP'97), 52-65, 1997 • Inductive Graphs and Functional Graph Algorithms, Martin Erwig Journal of Functional Programming,
1 2 right a b left down up c 3 Graphs • Nodes = 1,2,3 • Edges = (1,2),(2,1),(3,1),(2,3) • Node Labels = a,b,c • Edge Labels = right,left,up,down
Types • type Node = Int • type LNode a = (Node,a) • type UNode = LNode () • type Edge = (Node,Node) • type LEdge b = (Node,Node,b) • type UEdge = LEdge ()
More Types • data Graph a b -- Abstract Type • --unlabled Graph • type UGraph = Graph () () • type Path = [Node] • type LPath a = [LNode a] • type UPath = [UNode]
1 right 2 a b left down up c 3 Making Graphs • ex1 = mkGraph [(1,"a"),(2,"b"),(3,"c")] • [(1,2,"right"),(2,1,"left"), • (2,3,"down"),(3,1,"up")] • Main> ex1 • 1:"a"->[("right",2)] • 2:"b"->[("left",1),("down",3)] • 3:"c"->[("up",1)]
Looking inside • noNodes :: Graph a b -> Int • nodes :: Graph a b -> [Node] • labNodes :: Graph a b -> [LNode a] • -- [(Node,a)] • edges :: Graph a b -> [Edge] • --[(Node,Node)] • labEdges :: Graph a b -> [LEdge b] • -– [(Node,Node,b)]
1 right 2 a b left down up c 3 Examples • Main> noNodes ex1 • 3 • Main> nodes ex1 • [1,2,3] • Main> labEdges ex1 • [(1,2,"right"),(2,1,"left"), • (2,3,"down"),(3,1,"up")]
Decomposing Graphs edge label • type Adj b = [(b,Node)] • type Context a b = (Adj b,Node,a,Adj b) • type MContext a b = Maybe (Context a b) • type Decomp a b = (MContext a b,Graph a b) • type GDecomp a b = (Context a b,Graph a b) • type UContext = ([Node],Node,[Node]) • type UDecomp = (Maybe UContext,UGraph) • match :: Node -> Graph a b -> Decomp a b Its predecessors The node Its succesors Its label
1 2 right a b left down up c 3 (Just(ps,n,lab,ss),ex2) = match 2 ex1 • Main> ps • [("right",1)] --predecessors • Main> ss --successors • [("left",1),("down",3)] • Main> n –- the node • 2 • Main> lab -- its label • "b" • Main> ex2 • 1:"a"->[] • 3:"c"->[("up",1)]
1 a up c 3 (Just(ps2,n2,lab2,ss2),ex3) = match 3 ex2 • Main> ps2 • [] • Main> n2 • 3 • Main> lab2 • "c" • Main> ss2 • [("up",1)] • Main> ex3 • 1:"a"->[]
Constructing Graphs Inductively • empty :: Graph a b • embed :: Context a b -> Graph a b -> Graph a b • infixr & • c & g = embed c g • ex4 = (ps2,n2,lab2,ss2) & ex3 • Main> ex4 • 1:"a"->[] • 3:"c"->[("up",1)] 1 a up c 3
Operations on graphs • -- maps on nodes • nmap :: (a->c) -> Graph a b -> Graph c b • -- maps on edges • emap :: (b->c) -> Graph a b -> Graph a c • -- graph reversal • grev :: Graph a b -> Graph a b
Example • ex5 = nmap (ord . head) ex1 • Main> ex5 • 1:97->[("right",2)] • 2:98->[("down",3),("left",1)] • 3:99->[("up",1)] • Main> ex1 • 1:"a"->[("right",2)] • 2:"b"->[("left",1),("down",3)] • 3:"c"->[("up",1)]
Example 2 • ex6 = emap length ex1 • Main> ex6 • 1:"a"->[(5,2)] • 2:"b"->[(4,3),(4,1)] • 3:"c"->[(2,1)] • Main> ex1 • 1:"a"->[("right",2)] • 2:"b"->[("left",1),("down",3)] • 3:"c"->[("up",1)]
Roll your own • mymap f g • | isEmpty g = empty • | otherwise = • let ns = nodes g • (Just(ps,n,lab,ss),g2) • = match (head ns) g • in (ps,n,f lab,ss) & (mymap f g2)
Depth First Search • data Tree a = Branch a [Tree a] deriving Show • df :: Node -> Graph b a -> (Tree b,Graph b a) • df root g = • let (Just(_,v,lab,ss), g') = match root g • (r,g1) = dff ss g' • in (Branch lab r,g1) • dff :: [(c,Node)] -> Graph b c -> ([Tree b],Graph b c) • dff [] g = ([],g) • dff ((lab,v):l) g = • let (x,g1) = df v g • (y,g2) = dff l g1 • in (x:y,g2)
Example • ex7 = fst (df 1 ex1) • Main> ex7 • Branch "c" [Branch "b" [Branch "a" []]]
Launchbury & King • “Structuring Depth-First Search Algorithms in Haskell” • David King and John Launchbury - POPL ’95 – pp 344--354 • Graph algorithms based upon Depth First Search. • Asymtotically efficient – uses lazy state
1 2 3 4 5 8 6 7 9 10 Representing Graphs • import ST • import qualified Array as A • type Vertex = Int • -- Representing graphs: • type Table a = A.Array Vertex a • type Graph = Table [Vertex] • -- Array Int [Int] Index for each node Edges (out of) that index
Functions on graphs • type Vertex = Int • type Edge = (Vertex,Vertex) • vertices :: Graph -> [Vertex] • indices :: Graph -> [Int] • edges :: Graph -> [Edge]
1 2 6 3 5 4 7 8 10 9 Building Graphs • buildG :: Bounds -> [Edge] -> Graph • graph = buildG (1,10) • [ (1, 2), (1, 6), (2, 3), • (2, 5), (3, 1), (3, 4), • (5, 4), (7, 8), (7, 10), • (8, 6), (8, 9), (8, 10) ]
1 2 6 3 5 4 7 8 10 9 DFS and Forests • data Tree a = Node a (Forest a) • type Forest a = [Tree a] • nodesTree (Node a f) ans = • nodesForest f (a:ans) • nodesForest [] ans = ans • nodesForest (t : f) ans = • nodesTree t (nodesForest f ans) • Note how any tree can be spanned • by a Forest. The Forest is not always • unique.
DFS • The DFS algorithm finds a spanning forest for a graph, from a set of roots. • dfs :: Graph -> [Vertex] -> Forest Vertex • dfs :: Graph -> [Vertex] -> Forest Vertex • dfs g vs = prune (A.bounds g) (map (generate g) vs) • generate :: Graph -> Vertex -> Tree Vertex • generate g v = Node v (map (generate g) (g `aat` v))
Sets of nodes already visited • type Set s = STArray s Vertex Bool • mkEmpty :: Bounds -> ST s (Set s) • mkEmpty bnds = newSTArray bnds False • contains :: Set s -> Vertex -> ST s Bool • contains m v = readSTArray m v • include :: Set s -> Vertex -> ST s () • include m v = writeSTArray m v True
Pruning already visited paths • prune :: Bounds -> Forest Vertex -> Forest Vertex • prune bnds ts = • runST (do { m <- mkEmpty bnds; chop m ts }) • chop :: Set s -> Forest Vertex -> ST s (Forest Vertex) • chop m [] = return [] • chop m (Node v ts : us) • do { visited <- contains m v • ; if visited • then chop m us • else do { include m v • ; as <- chop m ts • ; bs <- chop m us • ; return(Node v as : bs) • } • }
Topological Sort • postorder :: Tree a -> [a] • postorder (Node a ts) = postorderF ts ++ [a] • postorderF :: Forest a -> [a] • postorderF ts = concat (map postorder ts) • postOrd :: Graph -> [Vertex] • postOrd = postorderF . Dff • dff :: Graph -> Forest Vertex • dff g = dfs g (vertices g)