NewSCC.hs

Plain Haskell source file: NewSCC.hs

module NewSCC (sccEq,scc) where

{- A module to find strongly connected components 
 - and perform a topological sort on them.
 - This is Lennart Augusstoson's code (from hbc?)
 - converted to Haskell by Iavor Diatchki.
 -}

import OpTypes
import Assoc 
import Products
import StateM


sccEq               :: EqOp a -> Graph a -> [Graph a]
scc                 :: Eq a => Graph a -> [Graph a]


type Graph a        = Assoc a [a]
type Numbering a    = Assoc a Int

type State a = (Int, Numbering a, Graph a, Int)
pushMany xs (x,ns,ss,y) = (x,ns,ss ++ xs,y)
minLast m (x,ns,ss,y)   = (x,ns,ss,min y m)
getNumbering x          = proj2 x


sccEq eq gG = concat $ runSt [] $ mapM (g eq gG) gG
scc         = sccEq (==)


g :: EqOp a -> Graph a -> (a,[a]) -> StateM (Numbering a) [Graph a]
g eq gG vv@(v,_)   = do 
    low <- getSt
    let found       = const (return [])
        notFound    = let (cs4, st) = searchC eq gG 1 low vv
                      in setSt (getNumbering st) >> return cs4
    maybe notFound found (lkpEq eq v low)




searchC :: EqOp a -> Graph a ->
            Int -> Numbering a -> (a,[a]) -> ([Graph a], State a)
searchC eq g n low vv@(v, es) 
    | nonfailLkpEq eq v low' == min' =
            (cs' ++ [nstack],
             (n', map (id >< const maxBound) nstack ++ low', [], min'))
    | otherwise = (cs', (n', low', nstack, min'))
    where    
    cs'     = concat cs2
    (cs2, (n', low', nstack, min'))
        = let n1 = n + 1 
              initSt = (n1, (v,n1) : low , [vv], n1)
        in runStS initSt $ mapM (f eq g) es 



f :: EqOp a -> Graph a -> a -> StateM (State a) [Graph a]
f eq g v = do
    (n, low, stack, min') <- getSt
    res <- case lkpEq eq v low of
        Nothing -> let (r,s) = searchC eq g n low (findVV eq g v)
                   in do setSt s; return r
        Just vm -> do setSt (n, low, [], vm); return []

    updSt (minLast min' . pushMany stack)
    return res


findVV :: EqOp a -> Graph a -> a -> (a, [a])
findVV eq g v = (v, nonfailLkpEq eq v g)



test = [('c', [])
       ,('a', ['b','c'])
       ,('b', ['a'])
       ]

test1 = [('a', "b")
        ,('c', "b")
        ,('b', "")
        ]

Index