{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__
{-# LANGUAGE Rank2Types #-}
#endif
#if __GLASGOW_HASKELL__ >= 703
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Graph(
stronglyConnComp, stronglyConnCompR, SCC(..), flattenSCC, flattenSCCs,
Graph, Table, Bounds, Edge, Vertex,
graphFromEdges, graphFromEdges', buildG, transposeG,
vertices, edges,
outdegree, indegree,
dfs, dff,
topSort,
components,
scc,
bcc,
reachable, path,
module Data.Tree
) where
#if __GLASGOW_HASKELL__
# define USE_ST_MONAD 1
#endif
#if USE_ST_MONAD
import Control.Monad.ST
import Data.Array.ST (STArray, newArray, readArray, writeArray)
#else
import Data.IntSet (IntSet)
import qualified Data.IntSet as Set
#endif
import Data.Tree (Tree(Node), Forest)
import Control.Applicative
import Control.DeepSeq (NFData(rnf))
import Data.Maybe
import Data.Array
import Data.List
data SCC vertex = AcyclicSCC vertex
| CyclicSCC [vertex]
instance NFData a => NFData (SCC a) where
rnf (AcyclicSCC v) = rnf v
rnf (CyclicSCC vs) = rnf vs
instance Functor SCC where
fmap f (AcyclicSCC v) = AcyclicSCC (f v)
fmap f (CyclicSCC vs) = CyclicSCC (fmap f vs)
flattenSCCs :: [SCC a] -> [a]
flattenSCCs = concatMap flattenSCC
flattenSCC :: SCC vertex -> [vertex]
flattenSCC (AcyclicSCC v) = [v]
flattenSCC (CyclicSCC vs) = vs
stronglyConnComp
:: Ord key
=> [(node, key, [key])]
-> [SCC node]
stronglyConnComp edges0
= map get_node (stronglyConnCompR edges0)
where
get_node (AcyclicSCC (n, _, _)) = AcyclicSCC n
get_node (CyclicSCC triples) = CyclicSCC [n | (n,_,_) <- triples]
stronglyConnCompR
:: Ord key
=> [(node, key, [key])]
-> [SCC (node, key, [key])]
stronglyConnCompR [] = []
stronglyConnCompR edges0
= map decode forest
where
(graph, vertex_fn,_) = graphFromEdges edges0
forest = scc graph
decode (Node v []) | mentions_itself v = CyclicSCC [vertex_fn v]
| otherwise = AcyclicSCC (vertex_fn v)
decode other = CyclicSCC (dec other [])
where
dec (Node v ts) vs = vertex_fn v : foldr dec vs ts
mentions_itself v = v `elem` (graph ! v)
type Vertex = Int
type Table a = Array Vertex a
type Graph = Table [Vertex]
type Bounds = (Vertex, Vertex)
type Edge = (Vertex, Vertex)
vertices :: Graph -> [Vertex]
vertices = indices
edges :: Graph -> [Edge]
edges g = [ (v, w) | v <- vertices g, w <- g!v ]
mapT :: (Vertex -> a -> b) -> Table a -> Table b
mapT f t = array (bounds t) [ (,) v (f v (t!v)) | v <- indices t ]
buildG :: Bounds -> [Edge] -> Graph
buildG bounds0 edges0 = accumArray (flip (:)) [] bounds0 edges0
transposeG :: Graph -> Graph
transposeG g = buildG (bounds g) (reverseE g)
reverseE :: Graph -> [Edge]
reverseE g = [ (w, v) | (v, w) <- edges g ]
outdegree :: Graph -> Table Int
outdegree = mapT numEdges
where numEdges _ ws = length ws
indegree :: Graph -> Table Int
indegree = outdegree . transposeG
graphFromEdges'
:: Ord key
=> [(node, key, [key])]
-> (Graph, Vertex -> (node, key, [key]))
graphFromEdges' x = (a,b) where
(a,b,_) = graphFromEdges x
graphFromEdges
:: Ord key
=> [(node, key, [key])]
-> (Graph, Vertex -> (node, key, [key]), key -> Maybe Vertex)
graphFromEdges edges0
= (graph, \v -> vertex_map ! v, key_vertex)
where
max_v = length edges0 - 1
bounds0 = (0,max_v) :: (Vertex, Vertex)
sorted_edges = sortBy lt edges0
edges1 = zipWith (,) [0..] sorted_edges
graph = array bounds0 [(,) v (mapMaybe key_vertex ks) | (,) v (_, _, ks) <- edges1]
key_map = array bounds0 [(,) v k | (,) v (_, k, _ ) <- edges1]
vertex_map = array bounds0 edges1
(_,k1,_) `lt` (_,k2,_) = k1 `compare` k2
key_vertex k = findVertex 0 max_v
where
findVertex a b | a > b
= Nothing
findVertex a b = case compare k (key_map ! mid) of
LT -> findVertex a (mid-1)
EQ -> Just mid
GT -> findVertex (mid+1) b
where
mid = (a + b) `div` 2
dff :: Graph -> Forest Vertex
dff g = dfs g (vertices g)
dfs :: Graph -> [Vertex] -> Forest Vertex
dfs g vs = prune (bounds g) (map (generate g) vs)
generate :: Graph -> Vertex -> Tree Vertex
generate g v = Node v (map (generate g) (g!v))
prune :: Bounds -> Forest Vertex -> Forest Vertex
prune bnds ts = run bnds (chop ts)
chop :: Forest Vertex -> SetM s (Forest Vertex)
chop [] = return []
chop (Node v ts : us)
= do
visited <- contains v
if visited then
chop us
else do
include v
as <- chop ts
bs <- chop us
return (Node v as : bs)
#if USE_ST_MONAD
newtype SetM s a = SetM { runSetM :: STArray s Vertex Bool -> ST s a }
instance Monad (SetM s) where
return x = SetM $ const (return x)
{-# INLINE return #-}
SetM v >>= f = SetM $ \s -> do { x <- v s; runSetM (f x) s }
{-# INLINE (>>=) #-}
instance Functor (SetM s) where
f `fmap` SetM v = SetM $ \s -> f `fmap` v s
{-# INLINE fmap #-}
instance Applicative (SetM s) where
pure x = SetM $ const (return x)
{-# INLINE pure #-}
SetM f <*> SetM v = SetM $ \s -> f s >>= (`fmap` v s)
{-# INLINE (<*>) #-}
run :: Bounds -> (forall s. SetM s a) -> a
run bnds act = runST (newArray bnds False >>= runSetM act)
contains :: Vertex -> SetM s Bool
contains v = SetM $ \ m -> readArray m v
include :: Vertex -> SetM s ()
include v = SetM $ \ m -> writeArray m v True
#else /* !USE_ST_MONAD */
newtype SetM s a = SetM { runSetM :: IntSet -> (a, IntSet) }
instance Monad (SetM s) where
return x = SetM $ \s -> (x, s)
SetM v >>= f = SetM $ \s -> case v s of (x, s') -> runSetM (f x) s'
instance Functor (SetM s) where
f `fmap` SetM v = SetM $ \s -> case v s of (x, s') -> (f x, s')
{-# INLINE fmap #-}
instance Applicative (SetM s) where
pure x = SetM $ \s -> (x, s)
{-# INLINE pure #-}
SetM f <*> SetM v = SetM $ \s -> case f s of (k, s') -> case v s' of (x, s'') -> (k x, s'')
{-# INLINE (<*>) #-}
run :: Bounds -> SetM s a -> a
run _ act = fst (runSetM act Set.empty)
contains :: Vertex -> SetM s Bool
contains v = SetM $ \ m -> (Set.member v m, m)
include :: Vertex -> SetM s ()
include v = SetM $ \ m -> ((), Set.insert v m)
#endif /* !USE_ST_MONAD */
preorder' :: Tree a -> [a] -> [a]
preorder' (Node a ts) = (a :) . preorderF' ts
preorderF' :: Forest a -> [a] -> [a]
preorderF' ts = foldr (.) id $ map preorder' ts
preorderF :: Forest a -> [a]
preorderF ts = preorderF' ts []
tabulate :: Bounds -> [Vertex] -> Table Int
tabulate bnds vs = array bnds (zipWith (,) vs [1..])
preArr :: Bounds -> Forest Vertex -> Table Int
preArr bnds = tabulate bnds . preorderF
postorder :: Tree a -> [a] -> [a]
postorder (Node a ts) = postorderF ts . (a :)
postorderF :: Forest a -> [a] -> [a]
postorderF ts = foldr (.) id $ map postorder ts
postOrd :: Graph -> [Vertex]
postOrd g = postorderF (dff g) []
topSort :: Graph -> [Vertex]
topSort = reverse . postOrd
components :: Graph -> Forest Vertex
components = dff . undirected
undirected :: Graph -> Graph
undirected g = buildG (bounds g) (edges g ++ reverseE g)
scc :: Graph -> Forest Vertex
scc g = dfs g (reverse (postOrd (transposeG g)))
reachable :: Graph -> Vertex -> [Vertex]
reachable g v = preorderF (dfs g [v])
path :: Graph -> Vertex -> Vertex -> Bool
path g v w = w `elem` (reachable g v)
bcc :: Graph -> Forest [Vertex]
bcc g = (concat . map bicomps . map (do_label g dnum)) forest
where forest = dff g
dnum = preArr (bounds g) forest
do_label :: Graph -> Table Int -> Tree Vertex -> Tree (Vertex,Int,Int)
do_label g dnum (Node v ts) = Node (v,dnum!v,lv) us
where us = map (do_label g dnum) ts
lv = minimum ([dnum!v] ++ [dnum!w | w <- g!v]
++ [lu | Node (_,_,lu) _ <- us])
bicomps :: Tree (Vertex,Int,Int) -> Forest [Vertex]
bicomps (Node (v,_,_) ts)
= [ Node (v:vs) us | (_,Node vs us) <- map collect ts]
collect :: Tree (Vertex,Int,Int) -> (Int, Tree [Vertex])
collect (Node (v,dv,lv) ts) = (lv, Node (v:vs) cs)
where collected = map collect ts
vs = concat [ ws | (lw, Node ws _) <- collected, lw<dv]
cs = concat [ if lw<dv then us else [Node (v:ws) us]
| (lw, Node ws us) <- collected ]