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:
15 -- Main> imain "name_of_file.dot"
21 import List
( sort, nub )
24 usage
= putStrLn "usage: dottoscc <name_of_file.dot>"
27 main
= do args
<- getArgs
30 else imain
(head args
)
32 imain
:: String -> IO ()
34 = do edges
<- read_dot_file dot_file_name
35 let sccs
= gen_sccs edges
36 let pretty
= showPrettily sccs
39 showPrettily
:: [[String]] -> String
40 showPrettily
= unlines . concatMap showScc
43 = let n
= length elems
46 ++ (if n
> 1 then [" -- "
47 ++ show n
++ " modules in cycle"]
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
]
60 -- identify lines of the form "text1 -> text2" and return
62 maybe_mk_edge
:: String -> Maybe (String, String)
65 [text1
, "->", text2
] -> Just
(text1
, text2
)
69 -- Take the list of edges and return a topologically sorted list of
71 gen_sccs
:: [(String,String)] -> [[String]]
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
)
82 --------------------------------------------------------------------
83 --------------------------------------------------------------------
84 --------------------------------------------------------------------
86 -- Graph-theoretic stuff that does the interesting stuff.
88 -- ==========================================================--
91 (a
-> [a
]) -> -- The "ins" map
92 (a
-> [a
]) -> -- The "outs" map
93 [a
] -> -- The root vertices
94 [Set a
] -- The topologically sorted components
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
114 search relation
(visited
, sequence) vertex
115 | utSetElementOf vertex visited
= (visited
, sequence )
116 |
otherwise = (visited
', vertex
: sequence')
118 (visited
', sequence')
119 = deDepthFirstSearch relation
120 (utSetUnion visited
(utSetSingleton vertex
), sequence)
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
136 search relation
(visited
, utSetSequence
) vertex
137 | utSetElementOf vertex visited
= (visited
, utSetSequence
)
138 |
otherwise = (visited
', utSetFromList
(vertex
: sequence): utSetSequence
)
141 = deDepthFirstSearch relation
142 (utSetUnion visited
(utSetSingleton vertex
), [])
149 --------------------------------------------------------------------
150 --------------------------------------------------------------------
151 --------------------------------------------------------------------
152 -- Most of this set stuff isn't needed.
155 -- ====================================--
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
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