Home | History | Annotate | Download | only in auxprogs
      1 
      2 -- A program for extracting strongly connected components from a .dot
      3 -- file created by auxprogs/gen-mdg.
      4 
      5 -- How to use: one of the following:
      6 
      7 -- compile to an exe:   ghc -o dottoscc DotToScc.hs
      8 --    and then    ./dottoscc name_of_file.dot
      9 
     10 -- or interpret with runhugs:
     11 --    runhugs DotToScc.hs name_of_file.dot
     12 
     13 -- or run within hugs:
     14 --    hugs DotToScc.hs
     15 --    Main> imain "name_of_file.dot"
     16 
     17 
     18 module Main where
     19 
     20 import System
     21 import List ( sort, nub )
     22 
     23 usage :: IO ()
     24 usage = putStrLn "usage: dottoscc <name_of_file.dot>"
     25 
     26 main :: IO ()
     27 main = do args <- getArgs
     28           if length args /= 1
     29            then usage
     30            else imain (head args)
     31 
     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
     41 
     42         showScc elems
     43            = let n = length elems 
     44              in
     45                 [""]
     46                 ++ (if n > 1 then ["   -- " 
     47                                    ++ show n ++ " modules in cycle"] 
     48                              else [])
     49                 ++ map ("   " ++) elems
     50 
     51 
     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
     67 
     68 
     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)
     78      in
     79          components
     80 
     81 
     82 --------------------------------------------------------------------
     83 --------------------------------------------------------------------
     84 --------------------------------------------------------------------
     85 
     86 -- Graph-theoretic stuff that does the interesting stuff.
     87 
     88 -- ==========================================================--
     89 --
     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
     95 
     96 deScc ins outs
     97    = spanning . depthFirst
     98      where depthFirst = snd . deDepthFirstSearch outs (utSetEmpty, [])
     99            spanning   = snd . deSpanningSearch   ins  (utSetEmpty, [])
    100 
    101 
    102 -- =========================================================--
    103 --
    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
    110 
    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)
    122 
    123 
    124 -- ==========================================================--
    125 --
    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
    132 
    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)
    144 
    145 
    146 
    147 
    148 
    149 --------------------------------------------------------------------
    150 --------------------------------------------------------------------
    151 --------------------------------------------------------------------
    152 -- Most of this set stuff isn't needed.
    153 
    154 
    155 -- ====================================--
    156 -- === set                          ===--
    157 -- ====================================--
    158 
    159 data Set e = MkSet [e]
    160 
    161 -- ==========================================================--
    162 --
    163 unMkSet :: (Ord a) => Set a -> [a]
    164 
    165 unMkSet (MkSet s) = s
    166 
    167 
    168 -- ==========================================================--
    169 --
    170 utSetEmpty :: (Ord a) => Set a
    171 
    172 utSetEmpty = MkSet []
    173 
    174 
    175 -- ==========================================================--
    176 --
    177 utSetIsEmpty :: (Ord a) => Set a -> Bool
    178 
    179 utSetIsEmpty (MkSet s) = s == []
    180 
    181 
    182 -- ==========================================================--
    183 --
    184 utSetSingleton :: (Ord a) => a -> Set a
    185 
    186 utSetSingleton x = MkSet [x]
    187 
    188 
    189 -- ==========================================================--
    190 --
    191 utSetFromList :: (Ord a) => [a] -> Set a
    192 
    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)
    198 
    199 
    200 -- ==========================================================--
    201 --
    202 utSetToList :: (Ord a) => Set a -> [a]
    203 
    204 utSetToList (MkSet xs) = xs
    205 
    206 
    207 
    208 -- ==========================================================--
    209 --
    210 utSetUnion :: (Ord a) => Set a -> Set a -> Set a
    211 
    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))))
    219 
    220 
    221 -- ==========================================================--
    222 --
    223 utSetIntersection :: (Ord a) => Set a -> Set a -> Set a
    224 
    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)
    232 
    233 
    234 -- ==========================================================--
    235 --
    236 utSetSubtraction :: (Ord a) => Set a -> Set a -> Set a
    237 
    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)
    245 
    246 
    247 -- ==========================================================--
    248 --
    249 utSetElementOf :: (Ord a) => a -> Set a -> Bool
    250 
    251 utSetElementOf x (MkSet [])       = False
    252 utSetElementOf x (MkSet (y:ys))   = x==y || (x>y && utSetElementOf x (MkSet ys))
    253 
    254 
    255 
    256 -- ==========================================================--
    257 --
    258 utSetSubsetOf :: (Ord a) => Set a -> Set a -> Bool
    259 
    260 utSetSubsetOf (MkSet [])        (MkSet bs) = True
    261 utSetSubsetOf (MkSet (a:as))    (MkSet bs)
    262     = utSetElementOf a (MkSet bs) && utSetSubsetOf (MkSet as) (MkSet bs)
    263 
    264 
    265 -- ==========================================================--
    266 --
    267 utSetUnionList :: (Ord a) => [Set a] -> Set a
    268 
    269 utSetUnionList setList = foldl utSetUnion utSetEmpty setList
    270 
    271 
    272