lattest-lib-0.1.0.0: src/Lattest/Model/Internal/NonDeterministic.hs
{- |
Non-deterministic model definitions, where observable behaviour may lead to a set of states.
These are equivalent to using Lattices with only `(\/)`, and defined in this separate module
because `(/\)` is more often the intended meaning.
-}
module Lattest.Model.Internal.NonDeterministic (
NonDet(..),
nonDet,
nonDetConcTransFromListRel
) where
import qualified Data.Set as Set
import Lattest.Model.BoundedMonad (BoundedConfiguration (..), BooleanConfiguration (..), JoinSemiLattice (..), OrdFunctor (..), OrdMonad (..))
import Lattest.Model.Symbolic.Expr (sOr, sTrue)
import Lattest.Model.Automaton (Completable (..))
import Data.Map (Map)
import Data.Maybe (fromJust, fromMaybe)
import Data.OrdMonad ((<#>))
import qualified Data.Map as Map
-- | Non-deterministic state configuration. This means that an automaton non-deterministically in a number of states, where zero states indicates the forbidden configuration, or in an explicit underspecified configuration.
data NonDet q = NonDet (Set.Set q) | UnderspecNonDet
nonDet :: Ord q => [q] -> NonDet q
nonDet = NonDet . Set.fromList
instance BoundedConfiguration NonDet where
isForbidden (NonDet s) = Set.null s
isForbidden _ = False
isUnderspecified UnderspecNonDet = True
isUnderspecified _ = False
forbidden = NonDet Set.empty
underspecified = UnderspecNonDet
instance OrdFunctor NonDet where
ordMap f (NonDet ss) = NonDet $ ordMap f ss
ordMap _ UnderspecNonDet = UnderspecNonDet
instance OrdMonad NonDet where
ordBind (NonDet ss) f = foldr (\/) (NonDet Set.empty) $ Set.map f ss
ordBind UnderspecNonDet _ = UnderspecNonDet
ordReturn s = NonDet $ Set.singleton s
instance Foldable NonDet where
foldr f q (NonDet qs) = foldr f q qs
foldr _ q _ = q
instance Show a => Show (NonDet a) where
show (NonDet a)
| Set.null a = "⊥"
| otherwise = show $ Set.toList a
show UnderspecNonDet = "⊤"
instance Ord a => Eq (NonDet a) where
UnderspecNonDet == UnderspecNonDet = True
(NonDet q1) == (NonDet q2) = q1 == q2
_ == _ = False
instance Ord a => Ord (NonDet a) where
_ <= UnderspecNonDet = True
UnderspecNonDet <= _ = False
(NonDet q1) <= (NonDet q2) = q1 <= q2
instance (Ord a) => JoinSemiLattice (NonDet a) where
(\/) (NonDet q1) (NonDet q2) = NonDet (Set.union q1 q2)
(\/) _ _ = UnderspecNonDet -- underspecification acts as top, so is absorbing w.r.t. join
instance BooleanConfiguration NonDet where
asExpr (NonDet qs) = sOr qs
asExpr UnderspecNonDet = sTrue
{- |
Create a non-deterministic concrete transition relation from an explicit list of tuples, with the destination of transitions expressed as lists of locations,
where the empty list is mapped to either `forbidden` or `underspecified`, depending on the transition label.
Having multiple occurrences of a transition label is interpreted as non-deterministic choice between the destinations.
-}
nonDetConcTransFromListRel :: (Completable t, Ord loc, Ord t) => [(loc, t, [loc])] -> (loc -> Map t (NonDet ((), loc)))
nonDetConcTransFromListRel = fromJust <$> transFromRelWith (\x y -> Just (x \/ y)) vacuousTrans listToNonDet
where
listToNonDet list@(_:_) () _ = vacuousLoc <#> NonDet (Set.fromList list)
listToNonDet [] () t = implicitDestination t
transFromRelWith :: (Ord loc, Ord t) =>
(m (tdest, loc) -> m (tdest, loc) -> Maybe (m (tdest, loc))) -- the way of combining the monadic transitions resulting from two list elements, or Nothing if they cannot be combined
-> (te -> (loc, t, tdest, loc')) -- the way of creating a 4-tuple with all the transition info from a list element
-> (loc' -> tdest -> t -> m (tdest, loc)) -- the way of creating a monadic transition result from the transition info of a list element
-> [te] -- the transition relation in a list representation
-> Maybe (loc -> Map t (m (tdest, loc))) -- a transition function, or Nothing if combining two monadic transitions failed
transFromRelWith c' fe' f' trans = do
tMapMap <- foldr (addToMap c' fe' f') (Just Map.empty) trans -- map from locations to a map from transitions to Dets
Just $ \loc -> fromMaybe Map.empty $ loc `Map.lookup` tMapMap
where
addToMap :: (Ord loc, Ord t) => (m (tdest, loc) -> m (tdest, loc) -> Maybe (m (tdest, loc))) -> (te -> (loc, t, tdest, loc')) -> (loc' -> tdest -> t -> m (tdest, loc)) -> te -> Maybe (Map loc (Map t (m (tdest, loc)))) -> Maybe (Map loc (Map t (m (tdest, loc))))
addToMap c fe f te maybeTMapMap = do
tMapMap <- maybeTMapMap
let (loc, t, tdest, loc') = fe te
case loc `Map.lookup` tMapMap of
Just tMap -> case t `Map.lookup` tMap of
Nothing -> Just $ Map.insert loc (Map.insert t (f loc' tdest t) tMap) tMapMap
Just prevLoc -> do
combinedLoc <- c prevLoc $ f loc' tdest t
Just $ Map.insert loc (Map.insert t combinedLoc tMap) tMapMap
Nothing -> Just $ Map.insert loc (Map.singleton t (f loc' tdest t)) tMapMap
vacuousTrans :: (a, b, d) -> (a, b, (), d)
vacuousTrans (a,b,c) = (a,b,(),c)
vacuousLoc :: b -> ((), b)
vacuousLoc l = ((), l)