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 Products((><))
import StateM
import Maybe (fromJust,listToMaybe)
sccEq :: EqOp a -> Graph a -> [Graph a]
scc :: Eq a => Graph a -> [Graph a]
lkpEq eq x xs = listToMaybe [ v | (k,v) <- xs, x `eq` k ]
nonfailLkpEq eq x = fromJust . lkpEq eq x
type Graph a = [(a, [a])]
type Numbering a = [(a, Int)]
type RW 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,ns,ss,y) = ns
sccEq eq gG = concat $ withSt [] $ 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], RW 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 withStS initSt $ mapM (f eq g) es
-- f :: EqOp a -> Graph a -> a -> StateM (RW 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', "")
]