{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE StandaloneDeriving #-}
#endif
#if __GLASGOW_HASKELL__ >= 703
{-# LANGUAGE Trustworthy #-}
#endif
#if __GLASGOW_HASKELL__ >= 702
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
#endif
#include "containers.h"
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
#if !MIN_VERSION_base(4,8,0)
import qualified Data.Foldable as F
import Data.Traversable
#else
import Data.Foldable as F
#endif
import Control.DeepSeq (NFData(rnf))
import Data.Maybe
import Data.Array
import Data.List
#if MIN_VERSION_base(4,9,0)
import Data.Functor.Classes
import Data.Semigroup (Semigroup (..))
#endif
#if __GLASGOW_HASKELL__ >= 706
import GHC.Generics (Generic, Generic1)
#elif __GLASGOW_HASKELL__ >= 702
import GHC.Generics (Generic)
#endif
#ifdef __GLASGOW_HASKELL__
import Data.Data (Data)
#endif
import Data.Typeable
data SCC vertex = AcyclicSCC vertex
| CyclicSCC [vertex]
deriving (Eq, Show, Read)
INSTANCE_TYPEABLE1(SCC)
#ifdef __GLASGOW_HASKELL__
deriving instance Data vertex => Data (SCC vertex)
#endif
#if __GLASGOW_HASKELL__ >= 706
deriving instance Generic1 SCC
#endif
#if __GLASGOW_HASKELL__ >= 702
deriving instance Generic (SCC vertex)
#endif
#if MIN_VERSION_base(4,9,0)
instance Eq1 SCC where
liftEq eq (AcyclicSCC v1) (AcyclicSCC v2) = eq v1 v2
liftEq eq (CyclicSCC vs1) (CyclicSCC vs2) = liftEq eq vs1 vs2
liftEq _ _ _ = False
instance Show1 SCC where
liftShowsPrec sp _sl d (AcyclicSCC v) = showsUnaryWith sp "AcyclicSCC" d v
liftShowsPrec _sp sl d (CyclicSCC vs) = showsUnaryWith (const sl) "CyclicSCC" d vs
instance Read1 SCC where
liftReadsPrec rp rl = readsData $
readsUnaryWith rp "AcyclicSCC" AcyclicSCC <>
readsUnaryWith (const rl) "CyclicSCC" CyclicSCC
#endif
instance F.Foldable SCC where
foldr c n (AcyclicSCC v) = c v n
foldr c n (CyclicSCC vs) = foldr c n vs
instance Traversable SCC where
traverse f (AcyclicSCC vertex) = AcyclicSCC <$> f vertex
traverse _f (CyclicSCC []) = pure (CyclicSCC [])
traverse f (CyclicSCC (x : xs)) =
liftA2 (\x' xs' -> CyclicSCC (x' : xs')) (f x) (traverse f xs)
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 - a) `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 = pure
{-# 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 ]