Skip to content

Commit fdf1507

Browse files
authored
Merge pull request #887 from meooow25/graph-dfs
Optimize Data.Graph.dfs
2 parents 4607c10 + 6b47338 commit fdf1507

File tree

2 files changed

+24
-24
lines changed

2 files changed

+24
-24
lines changed

containers-tests/benchmarks/Graph.hs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@ main = do
1212
evaluate $ rnf randGs
1313
defaultMain
1414
[ bgroup "buildG" $ forGs randGs $ \g -> nf (G.buildG (bounds (getG g))) (getEdges g)
15-
, bgroup "graphFromEdges" $ forGs randGs $ nf ((\(g, _, _) -> g) . G.graphFromEdges) . getAdjList
15+
, bgroup "graphFromEdges" $
16+
forGs [randG1, randG2, randG3] $ nf ((\(g, _, _) -> g) . G.graphFromEdges) . getAdjList
1617
, bgroup "dfs" $ forGs randGs $ nf (flip G.dfs [1]) . getG
1718
, bgroup "dff" $ forGs randGs $ nf G.dff . getG
1819
, bgroup "topSort" $ forGs randGs $ nf G.topSort . getG
1920
, bgroup "scc" $ forGs randGs $ nf G.scc . getG
2021
, bgroup "bcc" $ forGs [randG1, randG2] $ nf G.bcc . getG
21-
, bgroup "stronglyConnCompR" $ forGs randGs $ nf G.stronglyConnCompR . getAdjList
22+
, bgroup "stronglyConnCompR" $
23+
forGs [randG1, randG2, randG3] $ nf G.stronglyConnCompR . getAdjList
2224
]
2325
where
2426
randG1 = buildRandG 100 1000
2527
randG2 = buildRandG 100 10000
2628
randG3 = buildRandG 10000 100000
27-
randGs = [randG1, randG2, randG3]
29+
randG4 = buildRandG 100000 1000000
30+
randGs = [randG1, randG2, randG3, randG4]
2831

2932
-- Note: In practice it does not make sense to run topSort or bcc on a random
3033
-- graph. For topSort the graph should be acyclic and for bcc the graph should

containers/src/Data/Graph.hs

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -472,27 +472,24 @@ dff g = dfs g (vertices g)
472472
-- | A spanning forest of the part of the graph reachable from the listed
473473
-- vertices, obtained from a depth-first search of the graph starting at
474474
-- each of the listed vertices in order.
475-
dfs :: Graph -> [Vertex] -> Forest Vertex
476-
dfs g vs = prune (bounds g) (map (generate g) vs)
477-
478-
generate :: Graph -> Vertex -> Tree Vertex
479-
generate g v = Node v (map (generate g) (g!v))
480-
481-
prune :: Bounds -> Forest Vertex -> Forest Vertex
482-
prune bnds ts = run bnds (chop ts)
483-
484-
chop :: Forest Vertex -> SetM s (Forest Vertex)
485-
chop [] = return []
486-
chop (Node v ts : us)
487-
= do
488-
visited <- contains v
489-
if visited then
490-
chop us
491-
else do
492-
include v
493-
as <- chop ts
494-
bs <- chop us
495-
return (Node v as : bs)
475+
476+
-- This function deviates from King and Launchbury's implementation by
477+
-- bundling together the functions generate, prune, and chop for efficiency
478+
-- reasons.
479+
dfs :: Graph -> [Vertex] -> Forest Vertex
480+
dfs g vs0 = run (bounds g) $ go vs0
481+
where
482+
go :: [Vertex] -> SetM s (Forest Vertex)
483+
go [] = pure []
484+
go (v:vs) = do
485+
visited <- contains v
486+
if visited
487+
then go vs
488+
else do
489+
include v
490+
as <- go (g!v)
491+
bs <- go vs
492+
pure $ Node v as : bs
496493

497494
-- A monad holding a set of vertices visited so far.
498495
#if USE_ST_MONAD

0 commit comments

Comments
 (0)