module LOAG.Graphs where
import Control.Monad.Trans (lift, MonadTrans(..))
import Control.Monad (forM, forM_)
import Control.Monad.ST
import Control.Monad.State
import CommonTypes
import Data.STRef
import Data.Maybe (catMaybes, isNothing, fromJust)
import Data.Tuple (swap)
import qualified Data.Array as A
import Data.Array.IArray (amap)
import qualified Data.IntMap as IM
import qualified Data.IntSet as IS
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Array.MArray (mapArray)
import Data.Array.ST
type Schedule = (A.Array Vertex (Maybe Int), A.Array Int [Vertex])
type Vertex = Int
type Cycle = IS.IntSet
type Vertices = IS.IntSet
type Edge = (Vertex, Vertex)
type Edges = S.Set Edge
type Graph s = (DirGraphRef s, DirGraphRef s)
type FrGraph = (DirGraph, DirGraph)
type DirGraph = A.Array Vertex Vertices
type DirGraphRef s = STArray s Vertex Vertices
addEDs :: (MonadTrans m, MonadState s (m (ST s))) => Graph s ->
[Edge] -> (m (ST s)) (Maybe (Edge, Cycle))
addEDs _ [] = return Nothing
addEDs edp (e:es) = do
res <- e `inserT` edp
case res of
Right _ -> addEDs edp es
Left c -> return $ Just (e,c)
insErt :: (MonadTrans m, MonadState s (m (ST s))) => Edge -> Graph s ->
(m (ST s)) ()
insErt (f, t) g@(ft,tf) = do
ts <- lift (readArray ft f)
fs <- lift (readArray tf t)
lift (writeArray ft f (t `IS.insert` ts))
lift (writeArray tf t (f `IS.insert` fs))
removE :: (MonadTrans m, MonadState s (m (ST s))) => Edge -> Graph s ->
(m (ST s)) ()
removE e@(f,t) g@(ft,tf) = do
ts <- lift (readArray ft f)
fs <- lift (readArray tf t)
lift (writeArray ft f (t `IS.delete` ts))
lift (writeArray tf t (f `IS.delete` fs))
revErt :: (MonadTrans m, MonadState s (m (ST s))) => Edge -> Graph s ->
(m (ST s)) ()
revErt e g = do
present <- member e g
when present $ removE e g >> insErt (swap e) g
inserT :: (MonadTrans m, MonadState s (m (ST s))) => Edge -> Graph s ->
(m (ST s)) (Either Cycle [Edge])
inserT e@(f, t) g@(gft,gtf)
| f == t = return $ Left $ IS.singleton f
| otherwise = do
present <- member e g
if present
then (return $ Right [])
else do
pointsToF <- lift (readArray gtf f)
pointsToT <- lift (readArray gtf t)
tPointsTo <- lift (readArray gft t)
let new2t = pointsToF IS.\\ pointsToT
let extraF = IS.foldl' (\acc tf -> (tf,t) : acc) [] new2t
all2tPointsTo <- lift (newSTRef [])
forM_ (IS.toList tPointsTo) $ \ft -> do
current <- lift (readSTRef all2tPointsTo)
existing <- lift (readArray gtf ft)
let new4ft = map (flip (,) ft) $ IS.toList $
(f `IS.insert` pointsToF) IS.\\ existing
lift (writeSTRef all2tPointsTo $ current ++ new4ft)
extraT <- lift (readSTRef all2tPointsTo)
let extra = extraF ++ extraT
mapM_ (`insErt` g) (e : extra)
cyclic <- member (f,f) g
if cyclic
then do
cycle <- getCycle gft
return $ Left cycle
else return $ Right extra
where
getCycle :: (MonadTrans m, MonadState s (m (ST s))) =>
STArray s Vertex Vertices -> (m (ST s)) Cycle
getCycle gft = do
ts <- lift (readArray gft f)
mnodes <- forM (IS.toList ts) $ \t' -> do
fs' <- lift (readArray gft t')
if f `IS.member` fs'
then return $ Just t'
else return $ Nothing
return $ IS.fromList $ catMaybes mnodes
member :: (MonadTrans m, MonadState s (m (ST s))) => Edge -> Graph s ->
(m (ST s)) Bool
member (f, t) (ft, tf) = do
ts <- lift (readArray ft f)
return $ IS.member t ts
fr_member :: FrGraph -> Edge -> Bool
fr_member (ft, tf) (f, t) = IS.member t (ft A.! f)
flatten :: (MonadTrans m, MonadState s (m (ST s))) => Graph s -> (m (ST s)) Edges
flatten (gft, _) = do
list <- lift (getAssocs gft)
return $ S.fromList $ concatMap
(\(f, ts) -> map ((,) f) $ IS.toList ts) list
freeze_graph :: (MonadTrans m, MonadState s (m (ST s))) =>
Graph s -> (m (ST s)) FrGraph
freeze_graph (mf, mt) = do
fr_f <- lift (freeze mf)
fr_t <- lift (freeze mt)
return (fr_f, fr_t)