module Simulation.Aivika.Trans.Signal
(
Signal(..),
handleSignal_,
handleSignalComposite,
SignalSource,
newSignalSource,
newSignalSource0,
publishSignal,
triggerSignal,
mapSignal,
mapSignalM,
apSignal,
filterSignal,
filterSignal_,
filterSignalM,
filterSignalM_,
emptySignal,
merge2Signals,
merge3Signals,
merge4Signals,
merge5Signals,
arrivalSignal,
delaySignal,
delaySignalM,
SignalHistory,
signalHistorySignal,
newSignalHistory,
newSignalHistoryStartingWith,
readSignalHistory,
newSignalInTimes,
newSignalInIntegTimes,
newSignalInStartTime,
newSignalInStopTime,
newSignalInTimeGrid,
Signalable(..),
signalableChanged,
emptySignalable,
appendSignalable,
traceSignal) where
import Data.Monoid hiding ((<>))
import Data.Semigroup (Semigroup(..))
import Data.List.NonEmpty (NonEmpty((:|)))
import Data.List
import Data.Array
import Control.Monad
import Control.Monad.Trans
import Simulation.Aivika.Trans.Ref.Base
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Parameter
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Dynamics
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Composite
import Simulation.Aivika.Arrival (Arrival(..))
data SignalSource m a =
SignalSource { publishSignal :: Signal m a,
triggerSignal :: a -> Event m ()
}
data Signal m a =
Signal { handleSignal :: (a -> Event m ()) -> Event m (DisposableEvent m)
}
data SignalHandlerQueue m a =
SignalHandlerQueue { queueList :: Ref m [SignalHandler m a] }
data SignalHandler m a =
SignalHandler { handlerComp :: a -> Event m (),
handlerRef :: Ref m () }
instance MonadDES m => Eq (SignalHandler m a) where
{-# INLINE (==) #-}
x == y = (handlerRef x) == (handlerRef y)
handleSignal_ :: MonadDES m => Signal m a -> (a -> Event m ()) -> Event m ()
{-# INLINE handleSignal_ #-}
handleSignal_ signal h =
do x <- handleSignal signal h
return ()
handleSignalComposite :: MonadDES m => Signal m a -> (a -> Event m ()) -> Composite m ()
{-# INLINABLE handleSignalComposite #-}
handleSignalComposite signal h =
do x <- liftEvent $ handleSignal signal h
disposableComposite x
newSignalSource :: MonadDES m => Simulation m (SignalSource m a)
{-# INLINABLE newSignalSource #-}
newSignalSource =
do list <- newRef []
let queue = SignalHandlerQueue { queueList = list }
signal = Signal { handleSignal = handle }
source = SignalSource { publishSignal = signal,
triggerSignal = trigger }
handle h =
Event $ \p ->
do x <- invokeEvent p $ enqueueSignalHandler queue h
return $
DisposableEvent $
dequeueSignalHandler queue x
trigger a =
triggerSignalHandlers queue a
return source
newSignalSource0 :: (MonadDES m, MonadRef0 m) => m (SignalSource m a)
{-# INLINABLE newSignalSource0 #-}
newSignalSource0 =
do list <- newRef0 []
let queue = SignalHandlerQueue { queueList = list }
signal = Signal { handleSignal = handle }
source = SignalSource { publishSignal = signal,
triggerSignal = trigger }
handle h =
Event $ \p ->
do x <- invokeEvent p $ enqueueSignalHandler queue h
return $
DisposableEvent $
dequeueSignalHandler queue x
trigger a =
triggerSignalHandlers queue a
return source
triggerSignalHandlers :: MonadDES m => SignalHandlerQueue m a -> a -> Event m ()
{-# INLINABLE triggerSignalHandlers #-}
triggerSignalHandlers q a =
Event $ \p ->
do hs <- invokeEvent p $ readRef (queueList q)
forM_ hs $ \h ->
invokeEvent p $ handlerComp h a
enqueueSignalHandler :: MonadDES m => SignalHandlerQueue m a -> (a -> Event m ()) -> Event m (SignalHandler m a)
{-# INLINABLE enqueueSignalHandler #-}
enqueueSignalHandler q h =
Event $ \p ->
do r <- invokeSimulation (pointRun p) $ newRef ()
let handler = SignalHandler { handlerComp = h,
handlerRef = r }
invokeEvent p $ modifyRef (queueList q) (handler :)
return handler
dequeueSignalHandler :: MonadDES m => SignalHandlerQueue m a -> SignalHandler m a -> Event m ()
{-# INLINABLE dequeueSignalHandler #-}
dequeueSignalHandler q h =
modifyRef (queueList q) (delete h)
instance MonadDES m => Functor (Signal m) where
{-# INLINE fmap #-}
fmap = mapSignal
instance MonadDES m => Semigroup (Signal m a) where
{-# INLINE (<>) #-}
(<>) = merge2Signals
{-# INLINABLE sconcat #-}
sconcat (x1 :| []) = x1
sconcat (x1 :| [x2]) = merge2Signals x1 x2
sconcat (x1 :| [x2, x3]) = merge3Signals x1 x2 x3
sconcat (x1 :| [x2, x3, x4]) = merge4Signals x1 x2 x3 x4
sconcat (x1 :| [x2, x3, x4, x5]) = merge5Signals x1 x2 x3 x4 x5
sconcat (x1 :| (x2 : x3 : x4 : x5 : xs)) =
sconcat $ merge5Signals x1 x2 x3 x4 x5 :| xs
instance MonadDES m => Monoid (Signal m a) where
{-# INLINE mempty #-}
mempty = emptySignal
{-# INLINE mappend #-}
mappend = (<>)
{-# INLINABLE mconcat #-}
mconcat [] = mempty
mconcat (h:t) = sconcat (h :| t)
mapSignal :: MonadDES m => (a -> b) -> Signal m a -> Signal m b
{-# INLINABLE mapSignal #-}
mapSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ h . f }
filterSignal :: MonadDES m => (a -> Bool) -> Signal m a -> Signal m a
{-# INLINABLE filterSignal #-}
filterSignal p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h a }
filterSignal_ :: MonadDES m => (a -> Bool) -> Signal m a -> Signal m ()
{-# INLINABLE filterSignal_ #-}
filterSignal_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h () }
filterSignalM :: MonadDES m => (a -> Event m Bool) -> Signal m a -> Signal m a
{-# INLINABLE filterSignalM #-}
filterSignalM p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h a }
filterSignalM_ :: MonadDES m => (a -> Event m Bool) -> Signal m a -> Signal m ()
{-# INLINABLE filterSignalM_ #-}
filterSignalM_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h () }
merge2Signals :: MonadDES m => Signal m a -> Signal m a -> Signal m a
{-# INLINABLE merge2Signals #-}
merge2Signals m1 m2 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
return $ x1 <> x2 }
merge3Signals :: MonadDES m => Signal m a -> Signal m a -> Signal m a -> Signal m a
{-# INLINABLE merge3Signals #-}
merge3Signals m1 m2 m3 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
return $ x1 <> x2 <> x3 }
merge4Signals :: MonadDES m
=> Signal m a -> Signal m a -> Signal m a
-> Signal m a -> Signal m a
{-# INLINABLE merge4Signals #-}
merge4Signals m1 m2 m3 m4 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
x4 <- handleSignal m4 h
return $ x1 <> x2 <> x3 <> x4 }
merge5Signals :: MonadDES m
=> Signal m a -> Signal m a -> Signal m a
-> Signal m a -> Signal m a -> Signal m a
{-# INLINABLE merge5Signals #-}
merge5Signals m1 m2 m3 m4 m5 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
x3 <- handleSignal m3 h
x4 <- handleSignal m4 h
x5 <- handleSignal m5 h
return $ x1 <> x2 <> x3 <> x4 <> x5 }
mapSignalM :: MonadDES m => (a -> Event m b) -> Signal m a -> Signal m b
{-# INLINABLE mapSignalM #-}
mapSignalM f m =
Signal { handleSignal = \h ->
handleSignal m (f >=> h) }
apSignal :: MonadDES m => Event m (a -> b) -> Signal m a -> Signal m b
{-# INLINABLE apSignal #-}
apSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ \a -> do { x <- f; h (x a) } }
emptySignal :: MonadDES m => Signal m a
{-# INLINABLE emptySignal #-}
emptySignal =
Signal { handleSignal = \h -> return mempty }
data SignalHistory m a =
SignalHistory { signalHistorySignal :: Signal m a,
signalHistoryTimes :: Ref m [Double],
signalHistoryValues :: Ref m [a] }
newSignalHistory :: MonadDES m => Signal m a -> Composite m (SignalHistory m a)
{-# INLINABLE newSignalHistory #-}
newSignalHistory =
newSignalHistoryStartingWith Nothing
newSignalHistoryStartingWith :: MonadDES m => Maybe a -> Signal m a -> Composite m (SignalHistory m a)
{-# INLINABLE newSignalHistoryStartingWith #-}
newSignalHistoryStartingWith init signal =
do ts <- liftSimulation $ newRef []
xs <- liftSimulation $ newRef []
case init of
Nothing -> return ()
Just a ->
liftEvent $
do t <- liftDynamics time
modifyRef ts (t :)
modifyRef xs (a :)
handleSignalComposite signal $ \a ->
do t <- liftDynamics time
modifyRef ts (t :)
modifyRef xs (a :)
return SignalHistory { signalHistorySignal = signal,
signalHistoryTimes = ts,
signalHistoryValues = xs }
readSignalHistory :: MonadDES m => SignalHistory m a -> Event m (Array Int Double, Array Int a)
{-# INLINABLE readSignalHistory #-}
readSignalHistory history =
do xs0 <- readRef (signalHistoryTimes history)
ys0 <- readRef (signalHistoryValues history)
let n = length xs0
xs = listArray (0, n - 1) (reverse xs0)
ys = listArray (0, n - 1) (reverse ys0)
return (xs, ys)
triggerSignalWithCurrentTime :: MonadDES m => SignalSource m Double -> Event m ()
{-# INLINABLE triggerSignalWithCurrentTime #-}
triggerSignalWithCurrentTime s =
Event $ \p -> invokeEvent p $ triggerSignal s (pointTime p)
newSignalInTimes :: MonadDES m => [Double] -> Event m (Signal m Double)
{-# INLINABLE newSignalInTimes #-}
newSignalInTimes xs =
do s <- liftSimulation newSignalSource
enqueueEventWithTimes xs $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInIntegTimes :: MonadDES m => Event m (Signal m Double)
{-# INLINABLE newSignalInIntegTimes #-}
newSignalInIntegTimes =
do s <- liftSimulation newSignalSource
enqueueEventWithIntegTimes $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStartTime :: MonadDES m => Event m (Signal m Double)
{-# INLINABLE newSignalInStartTime #-}
newSignalInStartTime =
do s <- liftSimulation newSignalSource
t <- liftParameter starttime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStopTime :: MonadDES m => Event m (Signal m Double)
{-# INLINABLE newSignalInStopTime #-}
newSignalInStopTime =
do s <- liftSimulation newSignalSource
t <- liftParameter stoptime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInTimeGrid :: MonadDES m => Int -> Event m (Signal m Int)
{-# INLINABLE newSignalInTimeGrid #-}
newSignalInTimeGrid n =
do sc <- liftParameter simulationSpecs
s <- liftSimulation newSignalSource
let loop [] = return ()
loop ((i, t) : xs) = enqueueEvent t $
do triggerSignal s i
loop xs
loop $ timeGrid sc n
return $ publishSignal s
data Signalable m a =
Signalable { readSignalable :: Event m a,
signalableChanged_ :: Signal m ()
}
signalableChanged :: MonadDES m => Signalable m a -> Signal m a
{-# INLINABLE signalableChanged #-}
signalableChanged x = mapSignalM (const $ readSignalable x) $ signalableChanged_ x
instance Functor m => Functor (Signalable m) where
{-# INLINE fmap #-}
fmap f x = x { readSignalable = fmap f (readSignalable x) }
instance (MonadDES m, Semigroup a) => Semigroup (Signalable m a) where
{-# INLINE (<>) #-}
(<>) = appendSignalable
instance (MonadDES m, Monoid a, Semigroup a) => Monoid (Signalable m a) where
{-# INLINE mempty #-}
mempty = emptySignalable
{-# INLINE mappend #-}
mappend = (<>)
emptySignalable :: (MonadDES m, Monoid a) => Signalable m a
{-# INLINABLE emptySignalable #-}
emptySignalable =
Signalable { readSignalable = return mempty,
signalableChanged_ = mempty }
appendSignalable :: (MonadDES m, Semigroup a) => Signalable m a -> Signalable m a -> Signalable m a
{-# INLINABLE appendSignalable #-}
appendSignalable m1 m2 =
Signalable { readSignalable = liftM2 (<>) (readSignalable m1) (readSignalable m2),
signalableChanged_ = (signalableChanged_ m1) <> (signalableChanged_ m2) }
arrivalSignal :: MonadDES m => Signal m a -> Signal m (Arrival a)
{-# INLINABLE arrivalSignal #-}
arrivalSignal m =
Signal { handleSignal = \h ->
do r <- liftSimulation $ newRef Nothing
handleSignal m $ \a ->
Event $ \p ->
do t0 <- invokeEvent p $ readRef r
let t = pointTime p
invokeEvent p $ writeRef r (Just t)
invokeEvent p $
h Arrival { arrivalValue = a,
arrivalTime = t,
arrivalDelay =
case t0 of
Nothing -> Nothing
Just t0 -> Just (t - t0) } }
delaySignal :: MonadDES m => Double -> Signal m a -> Signal m a
{-# INLINABLE delaySignal #-}
delaySignal delta m =
Signal { handleSignal = \h ->
do r <- liftSimulation $ newRef False
h <- handleSignal m $ \a ->
Event $ \p ->
invokeEvent p $
enqueueEvent (pointTime p + delta) $
do x <- readRef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
writeRef r True
}
delaySignalM :: MonadDES m => Event m Double -> Signal m a -> Signal m a
{-# INLINABLE delaySignalM #-}
delaySignalM delta m =
Signal { handleSignal = \h ->
do r <- liftSimulation $ newRef False
h <- handleSignal m $ \a ->
Event $ \p ->
do delta' <- invokeEvent p delta
invokeEvent p $
enqueueEvent (pointTime p + delta') $
do x <- readRef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
writeRef r True
}
traceSignal :: MonadDES m => String -> Signal m a -> Signal m a
{-# INLINABLE traceSignal #-}
traceSignal message m =
Signal { handleSignal = \h ->
handleSignal m $ traceEvent message . h }