drd: Add a consistency check
[valgrind.git] / auxprogs / DotToScc.hs
bloba94434fd7bd5955f8d2a1336f84e2f1948784f36
2 -- A program for extracting strongly connected components from a .dot
3 -- file created by auxprogs/gen-mdg.
5 -- How to use: one of the following:
7 -- compile to an exe: ghc -o dottoscc DotToScc.hs
8 -- and then ./dottoscc name_of_file.dot
10 -- or interpret with runhugs:
11 -- runhugs DotToScc.hs name_of_file.dot
13 -- or run within hugs:
14 -- hugs DotToScc.hs
15 -- Main> imain "name_of_file.dot"
18 module Main where
20 import System
21 import List ( sort, nub )
23 usage :: IO ()
24 usage = putStrLn "usage: dottoscc <name_of_file.dot>"
26 main :: IO ()
27 main = do args <- getArgs
28 if length args /= 1
29 then usage
30 else imain (head args)
32 imain :: String -> IO ()
33 imain dot_file_name
34 = do edges <- read_dot_file dot_file_name
35 let sccs = gen_sccs edges
36 let pretty = showPrettily sccs
37 putStrLn pretty
38 where
39 showPrettily :: [[String]] -> String
40 showPrettily = unlines . concatMap showScc
42 showScc elems
43 = let n = length elems
45 [""]
46 ++ (if n > 1 then [" -- "
47 ++ show n ++ " modules in cycle"]
48 else [])
49 ++ map (" " ++) elems
52 -- Read a .dot file and return a list of edges
53 read_dot_file :: String{-filename-} -> IO [(String,String)]
54 read_dot_file dot_file_name
55 = do bytes <- readFile dot_file_name
56 let linez = lines bytes
57 let edges = [(s,d) | Just (s,d) <- map maybe_mk_edge linez]
58 return edges
59 where
60 -- identify lines of the form "text1 -> text2" and return
61 -- text1 and text2
62 maybe_mk_edge :: String -> Maybe (String, String)
63 maybe_mk_edge str
64 = case words str of
65 [text1, "->", text2] -> Just (text1, text2)
66 other -> Nothing
69 -- Take the list of edges and return a topologically sorted list of
70 -- sccs
71 gen_sccs :: [(String,String)] -> [[String]]
72 gen_sccs raw_edges
73 = let clean_edges = sort (nub raw_edges)
74 nodes = nub (concatMap (\(s,d) -> [s,d]) clean_edges)
75 ins v = [u | (u,w) <- clean_edges, v==w]
76 outs v = [w | (u,w) <- clean_edges, v==u]
77 components = map (sort.utSetToList) (deScc ins outs nodes)
79 components
82 --------------------------------------------------------------------
83 --------------------------------------------------------------------
84 --------------------------------------------------------------------
86 -- Graph-theoretic stuff that does the interesting stuff.
88 -- ==========================================================--
90 deScc :: (Ord a) =>
91 (a -> [a]) -> -- The "ins" map
92 (a -> [a]) -> -- The "outs" map
93 [a] -> -- The root vertices
94 [Set a] -- The topologically sorted components
96 deScc ins outs
97 = spanning . depthFirst
98 where depthFirst = snd . deDepthFirstSearch outs (utSetEmpty, [])
99 spanning = snd . deSpanningSearch ins (utSetEmpty, [])
102 -- =========================================================--
104 deDepthFirstSearch :: (Ord a) =>
105 (a -> [a]) -> -- The map,
106 (Set a, [a]) -> -- state: visited set,
107 -- current sequence of vertices
108 [a] -> -- input vertices sequence
109 (Set a, [a]) -- final state
111 deDepthFirstSearch
112 = foldl . search
113 where
114 search relation (visited, sequence) vertex
115 | utSetElementOf vertex visited = (visited, sequence )
116 | otherwise = (visited', vertex: sequence')
117 where
118 (visited', sequence')
119 = deDepthFirstSearch relation
120 (utSetUnion visited (utSetSingleton vertex), sequence)
121 (relation vertex)
124 -- ==========================================================--
126 deSpanningSearch :: (Ord a) =>
127 (a -> [a]) -> -- The map
128 (Set a, [Set a]) -> -- Current state: visited set,
129 -- current sequence of vertice sets
130 [a] -> -- Input sequence of vertices
131 (Set a, [Set a]) -- Final state
133 deSpanningSearch
134 = foldl . search
135 where
136 search relation (visited, utSetSequence) vertex
137 | utSetElementOf vertex visited = (visited, utSetSequence )
138 | otherwise = (visited', utSetFromList (vertex: sequence): utSetSequence)
139 where
140 (visited', sequence)
141 = deDepthFirstSearch relation
142 (utSetUnion visited (utSetSingleton vertex), [])
143 (relation vertex)
149 --------------------------------------------------------------------
150 --------------------------------------------------------------------
151 --------------------------------------------------------------------
152 -- Most of this set stuff isn't needed.
155 -- ====================================--
156 -- === set ===--
157 -- ====================================--
159 data Set e = MkSet [e]
161 -- ==========================================================--
163 unMkSet :: (Ord a) => Set a -> [a]
165 unMkSet (MkSet s) = s
168 -- ==========================================================--
170 utSetEmpty :: (Ord a) => Set a
172 utSetEmpty = MkSet []
175 -- ==========================================================--
177 utSetIsEmpty :: (Ord a) => Set a -> Bool
179 utSetIsEmpty (MkSet s) = s == []
182 -- ==========================================================--
184 utSetSingleton :: (Ord a) => a -> Set a
186 utSetSingleton x = MkSet [x]
189 -- ==========================================================--
191 utSetFromList :: (Ord a) => [a] -> Set a
193 utSetFromList x = (MkSet . rmdup . sort) x
194 where rmdup [] = []
195 rmdup [x] = [x]
196 rmdup (x:y:xs) | x==y = rmdup (y:xs)
197 | otherwise = x: rmdup (y:xs)
200 -- ==========================================================--
202 utSetToList :: (Ord a) => Set a -> [a]
204 utSetToList (MkSet xs) = xs
208 -- ==========================================================--
210 utSetUnion :: (Ord a) => Set a -> Set a -> Set a
212 utSetUnion (MkSet []) (MkSet []) = (MkSet [])
213 utSetUnion (MkSet []) (MkSet (b:bs)) = (MkSet (b:bs))
214 utSetUnion (MkSet (a:as)) (MkSet []) = (MkSet (a:as))
215 utSetUnion (MkSet (a:as)) (MkSet (b:bs))
216 | a < b = MkSet (a: (unMkSet (utSetUnion (MkSet as) (MkSet (b:bs)))))
217 | a == b = MkSet (a: (unMkSet (utSetUnion (MkSet as) (MkSet bs))))
218 | a > b = MkSet (b: (unMkSet (utSetUnion (MkSet (a:as)) (MkSet bs))))
221 -- ==========================================================--
223 utSetIntersection :: (Ord a) => Set a -> Set a -> Set a
225 utSetIntersection (MkSet []) (MkSet []) = (MkSet [])
226 utSetIntersection (MkSet []) (MkSet (b:bs)) = (MkSet [])
227 utSetIntersection (MkSet (a:as)) (MkSet []) = (MkSet [])
228 utSetIntersection (MkSet (a:as)) (MkSet (b:bs))
229 | a < b = utSetIntersection (MkSet as) (MkSet (b:bs))
230 | a == b = MkSet (a: (unMkSet (utSetIntersection (MkSet as) (MkSet bs))))
231 | a > b = utSetIntersection (MkSet (a:as)) (MkSet bs)
234 -- ==========================================================--
236 utSetSubtraction :: (Ord a) => Set a -> Set a -> Set a
238 utSetSubtraction (MkSet []) (MkSet []) = (MkSet [])
239 utSetSubtraction (MkSet []) (MkSet (b:bs)) = (MkSet [])
240 utSetSubtraction (MkSet (a:as)) (MkSet []) = (MkSet (a:as))
241 utSetSubtraction (MkSet (a:as)) (MkSet (b:bs))
242 | a < b = MkSet (a: (unMkSet (utSetSubtraction (MkSet as) (MkSet (b:bs)))))
243 | a == b = utSetSubtraction (MkSet as) (MkSet bs)
244 | a > b = utSetSubtraction (MkSet (a:as)) (MkSet bs)
247 -- ==========================================================--
249 utSetElementOf :: (Ord a) => a -> Set a -> Bool
251 utSetElementOf x (MkSet []) = False
252 utSetElementOf x (MkSet (y:ys)) = x==y || (x>y && utSetElementOf x (MkSet ys))
256 -- ==========================================================--
258 utSetSubsetOf :: (Ord a) => Set a -> Set a -> Bool
260 utSetSubsetOf (MkSet []) (MkSet bs) = True
261 utSetSubsetOf (MkSet (a:as)) (MkSet bs)
262 = utSetElementOf a (MkSet bs) && utSetSubsetOf (MkSet as) (MkSet bs)
265 -- ==========================================================--
267 utSetUnionList :: (Ord a) => [Set a] -> Set a
269 utSetUnionList setList = foldl utSetUnion utSetEmpty setList