{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Abstract.DPO.StateSpace
(
StateSpace
, empty
, states
, transitions
, searchForState
, toKripkeStructure
, StateSpaceBuilder
, runStateSpaceBuilder
, evalStateSpaceBuilder
, execStateSpaceBuilder
, getDpoConfig
, getProductions
, putState
, putTransition
, findIsomorphicState
, expandSuccessors
, depthSearch
) where
import Control.Monad
import qualified Control.Monad.State as Monad
import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap
import Data.Set (Set)
import qualified Data.Set as Set
import Abstract.DPO hiding (productions)
import Abstract.Morphism
import qualified Logic.Model as Logic
data StateSpace m = SS
{ states :: IntMap (State m)
, transitions :: Set (Int, Int)
, uid :: Int
, morphismsConf :: MorphismsConfig
, productions :: [Production m]
, predicates :: [(String, Production m)]
}
type State m = (Obj m, [String])
empty :: MorphismsConfig -> [Production m] -> [(String, Production m)] -> StateSpace m
empty = SS IntMap.empty Set.empty 0
searchForState :: forall m. (DPO m) => Obj m -> StateSpace m -> Maybe (Int, State m)
searchForState obj space =
let
isIso (_, (obj', _)) =
let
isomorphisms = findIsomorphisms obj obj' :: [m]
in
not (null isomorphisms)
in
case filter isIso (IntMap.toList $ states space) of
[] ->
Nothing
(state : _) ->
Just state
toKripkeStructure :: StateSpace m -> Logic.KripkeStructure String
toKripkeStructure space =
let
convertedStates =
map convertState $ IntMap.toList (states space)
convertState (index, (_, props)) =
Logic.State index props
convertedTransitions =
zipWith convertTransition [0..] $ Set.toList (transitions space)
convertTransition index (from, to) =
Logic.Transition index from to []
in
Logic.KripkeStructure convertedStates convertedTransitions
newtype StateSpaceBuilder m a = SSB
{ unSSB :: Monad.State (StateSpace m) a }
deriving ( Functor, Applicative, Monad
, (Monad.MonadState (StateSpace m))
)
runStateSpaceBuilder :: StateSpaceBuilder m a -> StateSpace m -> (a, StateSpace m)
runStateSpaceBuilder =
Monad.runState . unSSB
evalStateSpaceBuilder :: StateSpaceBuilder m a -> StateSpace m -> a
evalStateSpaceBuilder =
Monad.evalState . unSSB
execStateSpaceBuilder :: StateSpaceBuilder m a -> StateSpace m -> StateSpace m
execStateSpaceBuilder =
Monad.execState . unSSB
getDpoConfig :: StateSpaceBuilder m MorphismsConfig
getDpoConfig =
Monad.gets morphismsConf
getProductions :: StateSpaceBuilder m [Production m]
getProductions =
Monad.gets productions
getPredicates :: StateSpaceBuilder m [(String, Production m)]
getPredicates =
Monad.gets predicates
putState :: (DPO m) => Obj m -> StateSpaceBuilder m (Int, Bool)
putState object =
do
maybeIndex <- findIsomorphicState object
case maybeIndex of
Just (index, _) ->
return (index, False)
Nothing -> do
index <- Monad.gets uid
conf <- getDpoConfig
allPredicates <- getPredicates
let truePredicates = map fst . filter (isTrueAt conf object) $ allPredicates
let state = (object, truePredicates)
Monad.modify $ \space ->
space
{ states = IntMap.insert index state (states space)
, uid = uid space + 1
}
return (index, True)
where
isTrueAt conf object (_, production) =
not . null $ findApplicableMatches conf production object
putTransition :: (Int, Int) -> StateSpaceBuilder m ()
putTransition transition =
Monad.modify $ \space ->
space
{ transitions = Set.insert transition (transitions space) }
findIsomorphicState :: (DPO m) => Obj m -> StateSpaceBuilder m (Maybe (Int, State m))
findIsomorphicState obj =
Monad.gets (searchForState obj)
expandSuccessors :: forall m. DPO m => (Int, Obj m) -> StateSpaceBuilder m [(Int, Obj m, Bool)]
expandSuccessors (index, object) =
do
prods <- getProductions
successorLists <- mapM applyProduction prods
return (concat successorLists)
where
applyProduction prod =
do
conf <- getDpoConfig
forM (findApplicableMatches conf prod object) $ \match -> do
let object' = rewrite match prod
(index', isNew) <- putState object'
putTransition (index, index')
return (index', object', isNew)
depthSearch :: forall m. DPO m => Int -> Obj m -> StateSpaceBuilder m ()
depthSearch maxDepth startObject =
do
(startIndex, _) <- putState startObject
go maxDepth (startIndex, startObject)
where
go :: Int -> (Int, Obj m) -> StateSpaceBuilder m ()
go 0 _ =
return ()
go depthLeft (index, object) =
do
sucessors <- expandSuccessors (index, object)
forM_ sucessors $ \(index', object', isNew) ->
when isNew $
go (depthLeft - 1) (index', object')