File: SCC.hs

package info (click to toggle)
haskell-graphscc 1.0.4-9
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 64 kB
  • sloc: haskell: 192; makefile: 4
file content (84 lines) | stat: -rw-r--r-- 3,094 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
{-# LANGUAGE CPP, Safe #-}
module Data.Graph.SCC
  ( scc
  , sccList
  , sccListR
  , sccGraph
  , stronglyConnComp
  , stronglyConnCompR
  ) where

#ifdef USE_MAPS
import Data.Graph.MapSCC
#else
import Data.Graph.ArraySCC
#endif
import Data.Graph(SCC(..),Graph,Vertex,graphFromEdges')

import Data.Array as A
import Data.List(nub)

-- | Compute the list of strongly connected components of a graph.
-- The components are topologically sorted:
-- if v1 in C1 points to v2 in C2, then C2 will come before C1 in the list.
sccList :: Graph -> [SCC Vertex]
sccList g = reverse $ map (to_scc g lkp) cs
  where (cs,lkp) = scc g

-- | Compute the list of strongly connected components of a graph.
-- Each component contains the adjecency information from the original graph.
-- The components are topologically sorted:
-- if v1 in C1 points to v2 in C2, then C2 will come before C1 in the list.
sccListR :: Graph -> [SCC (Vertex,[Vertex])]
sccListR g = reverse $ map cvt cs
  where (cs,lkp) = scc g
        cvt (n,[v]) = let adj = g ! v
                      in if  n `elem` map lkp adj
                           then CyclicSCC [(v,adj)]
                           else AcyclicSCC (v,adj)
        cvt (_,vs)  = CyclicSCC [ (v, g ! v) | v <- vs ]

-- | Quotient a graph with the relation that relates vertices that
-- belong to the same SCC.  The vertices in the new graph are the
-- SCCs of the old graph, and there is an edge between two components,
-- if there is an edge between any of their vertices.
-- The entries in the resulting list are in reversed-topologically sorted:
-- if v1 in C1 points to v2 in C2, then C1 will come before C2 in the list.
sccGraph :: Graph -> [(SCC Int, Int, [Int])]
sccGraph g = map to_node cs
  where (cs,lkp) = scc g
        to_node x@(n,this) = ( to_scc g lkp x
                             , n
                             , nub $ concatMap (map lkp . (g !)) this
                             )


stronglyConnComp :: Ord key => [(node, key, [key])] -> [SCC node]
stronglyConnComp es = reverse $ map cvt cs
  where (g,back)    = graphFromEdges' es
        (cs,lkp)    = scc g
        cvt (n,[v]) = let (node,_,_) = back v
                      in if n `elem` map lkp (g ! v)
                            then CyclicSCC [node]
                            else AcyclicSCC node
        cvt (_,vs)  = CyclicSCC [ node | (node,_,_) <- map back vs ]


stronglyConnCompR :: Ord key => [(node, key, [key])] -> [SCC (node, key, [key])]
stronglyConnCompR es = reverse $ map cvt cs
  where (g,back)    = graphFromEdges' es
        (cs,lkp)    = scc g
        cvt (n,[v]) = if n `elem` map lkp (g ! v)
                         then CyclicSCC [back v]
                         else AcyclicSCC (back v)
        cvt (_,vs)  = CyclicSCC (map back vs)



--------------------------------------------------------------------------------
to_scc :: Graph -> (Vertex -> Int) -> (Int,[Vertex]) -> SCC Vertex
to_scc g lkp (n,[v]) = if n `elem` map lkp (g ! v) then CyclicSCC [v]
                                                   else AcyclicSCC v
to_scc _ _ (_,vs)    = CyclicSCC vs