module Simulation.Aivika.Signal
(
Signal(..),
handleSignal_,
handleSignalComposite,
SignalSource,
newSignalSource,
publishSignal,
triggerSignal,
mapSignal,
mapSignalM,
apSignal,
filterSignal,
filterSignal_,
filterSignalM,
filterSignalM_,
emptySignal,
merge2Signals,
merge3Signals,
merge4Signals,
merge5Signals,
arrivalSignal,
newSignalInTimes,
newSignalInIntegTimes,
newSignalInStartTime,
newSignalInStopTime,
newSignalInTimeGrid,
delaySignal,
delaySignalM,
SignalHistory,
signalHistorySignal,
newSignalHistory,
newSignalHistoryStartingWith,
readSignalHistory,
Signalable(..),
signalableChanged,
emptySignalable,
appendSignalable,
traceSignal) where
import Data.IORef
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.Internal.Specs
import Simulation.Aivika.Internal.Parameter
import Simulation.Aivika.Internal.Simulation
import Simulation.Aivika.Internal.Dynamics
import Simulation.Aivika.Internal.Event
import Simulation.Aivika.Internal.Arrival
import Simulation.Aivika.Composite
import qualified Simulation.Aivika.Vector as V
import qualified Simulation.Aivika.Vector.Unboxed as UV
data SignalSource a =
SignalSource { publishSignal :: Signal a,
triggerSignal :: a -> Event ()
}
data Signal a =
Signal { handleSignal :: (a -> Event ()) -> Event DisposableEvent
}
data SignalHandlerQueue a =
SignalHandlerQueue { queueList :: IORef [SignalHandler a] }
data SignalHandler a =
SignalHandler { handlerComp :: a -> Event (),
handlerRef :: IORef () }
instance Eq (SignalHandler a) where
x == y = (handlerRef x) == (handlerRef y)
handleSignal_ :: Signal a -> (a -> Event ()) -> Event ()
handleSignal_ signal h =
do x <- handleSignal signal h
return ()
handleSignalComposite :: Signal a -> (a -> Event ()) -> Composite ()
handleSignalComposite signal h =
do x <- liftEvent $ handleSignal signal h
disposableComposite x
newSignalSource :: Simulation (SignalSource a)
newSignalSource =
Simulation $ \r ->
do list <- newIORef []
let queue = SignalHandlerQueue { queueList = list }
signal = Signal { handleSignal = handle }
source = SignalSource { publishSignal = signal,
triggerSignal = trigger }
handle h =
Event $ \p ->
do x <- enqueueSignalHandler queue h
return $
DisposableEvent $
Event $ \p -> dequeueSignalHandler queue x
trigger a =
Event $ \p -> triggerSignalHandlers queue a p
return source
triggerSignalHandlers :: SignalHandlerQueue a -> a -> Point -> IO ()
{-# INLINE triggerSignalHandlers #-}
triggerSignalHandlers q a p =
do hs <- readIORef (queueList q)
forM_ hs $ \h ->
invokeEvent p $ handlerComp h a
enqueueSignalHandler :: SignalHandlerQueue a -> (a -> Event ()) -> IO (SignalHandler a)
{-# INLINE enqueueSignalHandler #-}
enqueueSignalHandler q h =
do r <- newIORef ()
let handler = SignalHandler { handlerComp = h,
handlerRef = r }
modifyIORef (queueList q) (handler :)
return handler
dequeueSignalHandler :: SignalHandlerQueue a -> SignalHandler a -> IO ()
{-# INLINE dequeueSignalHandler #-}
dequeueSignalHandler q h =
modifyIORef (queueList q) (delete h)
instance Functor Signal where
fmap = mapSignal
instance Semigroup (Signal a) where
(<>) = merge2Signals
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 Monoid (Signal a) where
mempty = emptySignal
mappend = (<>)
mconcat [] = emptySignal
mconcat (h : t) = sconcat (h :| t)
mapSignal :: (a -> b) -> Signal a -> Signal b
mapSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ h . f }
filterSignal :: (a -> Bool) -> Signal a -> Signal a
filterSignal p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h a }
filterSignal_ :: (a -> Bool) -> Signal a -> Signal ()
filterSignal_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
when (p a) $ h () }
filterSignalM :: (a -> Event Bool) -> Signal a -> Signal a
filterSignalM p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h a }
filterSignalM_ :: (a -> Event Bool) -> Signal a -> Signal ()
filterSignalM_ p m =
Signal { handleSignal = \h ->
handleSignal m $ \a ->
do x <- p a
when x $ h () }
merge2Signals :: Signal a -> Signal a -> Signal a
merge2Signals m1 m2 =
Signal { handleSignal = \h ->
do x1 <- handleSignal m1 h
x2 <- handleSignal m2 h
return $ x1 <> x2 }
merge3Signals :: Signal a -> Signal a -> Signal a -> Signal a
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 :: Signal a -> Signal a -> Signal a ->
Signal a -> Signal a
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 :: Signal a -> Signal a -> Signal a ->
Signal a -> Signal a -> Signal a
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 :: (a -> Event b) -> Signal a -> Signal b
mapSignalM f m =
Signal { handleSignal = \h ->
handleSignal m (f >=> h) }
apSignal :: Event (a -> b) -> Signal a -> Signal b
apSignal f m =
Signal { handleSignal = \h ->
handleSignal m $ \a -> do { x <- f; h (x a) } }
emptySignal :: Signal a
emptySignal =
Signal { handleSignal = \h -> return mempty }
data SignalHistory a =
SignalHistory { signalHistorySignal :: Signal a,
signalHistoryTimes :: UV.Vector Double,
signalHistoryValues :: V.Vector a }
newSignalHistory :: Signal a -> Composite (SignalHistory a)
newSignalHistory =
newSignalHistoryStartingWith Nothing
newSignalHistoryStartingWith :: Maybe a -> Signal a -> Composite (SignalHistory a)
newSignalHistoryStartingWith init signal =
do ts <- liftIO UV.newVector
xs <- liftIO V.newVector
case init of
Nothing -> return ()
Just a ->
do t <- liftDynamics time
liftIO $
do UV.appendVector ts t
V.appendVector xs a
handleSignalComposite signal $ \a ->
Event $ \p ->
do UV.appendVector ts (pointTime p)
V.appendVector xs a
return SignalHistory { signalHistorySignal = signal,
signalHistoryTimes = ts,
signalHistoryValues = xs }
readSignalHistory :: SignalHistory a -> Event (Array Int Double, Array Int a)
readSignalHistory history =
do xs <- liftIO $ UV.freezeVector (signalHistoryTimes history)
ys <- liftIO $ V.freezeVector (signalHistoryValues history)
return (xs, ys)
triggerSignalWithCurrentTime :: SignalSource Double -> Event ()
triggerSignalWithCurrentTime s =
Event $ \p -> invokeEvent p $ triggerSignal s (pointTime p)
newSignalInTimes :: [Double] -> Event (Signal Double)
newSignalInTimes xs =
do s <- liftSimulation newSignalSource
enqueueEventWithTimes xs $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInIntegTimes :: Event (Signal Double)
newSignalInIntegTimes =
do s <- liftSimulation newSignalSource
enqueueEventWithIntegTimes $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStartTime :: Event (Signal Double)
newSignalInStartTime =
do s <- liftSimulation newSignalSource
t <- liftParameter starttime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInStopTime :: Event (Signal Double)
newSignalInStopTime =
do s <- liftSimulation newSignalSource
t <- liftParameter stoptime
enqueueEvent t $ triggerSignalWithCurrentTime s
return $ publishSignal s
newSignalInTimeGrid :: Int -> Event (Signal Int)
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 a =
Signalable { readSignalable :: Event a,
signalableChanged_ :: Signal ()
}
signalableChanged :: Signalable a -> Signal a
signalableChanged x = mapSignalM (const $ readSignalable x) $ signalableChanged_ x
instance Functor Signalable where
fmap f x = x { readSignalable = fmap f (readSignalable x) }
instance Semigroup a => Semigroup (Signalable a) where
(<>) = appendSignalable
instance (Monoid a, Semigroup a) => Monoid (Signalable a) where
mempty = emptySignalable
mappend = (<>)
emptySignalable :: Monoid a => Signalable a
emptySignalable =
Signalable { readSignalable = return mempty,
signalableChanged_ = mempty }
appendSignalable :: Semigroup a => Signalable a -> Signalable a -> Signalable a
appendSignalable m1 m2 =
Signalable { readSignalable = liftM2 (<>) (readSignalable m1) (readSignalable m2),
signalableChanged_ = (signalableChanged_ m1) <> (signalableChanged_ m2) }
arrivalSignal :: Signal a -> Signal (Arrival a)
arrivalSignal m =
Signal { handleSignal = \h ->
Event $ \p ->
do r <- newIORef Nothing
invokeEvent p $
handleSignal m $ \a ->
Event $ \p ->
do t0 <- readIORef r
let t = pointTime p
writeIORef r (Just t)
invokeEvent p $
h Arrival { arrivalValue = a,
arrivalTime = t,
arrivalDelay =
case t0 of
Nothing -> Nothing
Just t0 -> Just (t - t0) }
}
delaySignal :: Double -> Signal a -> Signal a
delaySignal delta m =
Signal { handleSignal = \h ->
do r <- liftIO $ newIORef False
h <- handleSignal m $ \a ->
Event $ \p ->
invokeEvent p $
enqueueEvent (pointTime p + delta) $
do x <- liftIO $ readIORef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
(liftIO $ writeIORef r True)
}
delaySignalM :: Event Double -> Signal a -> Signal a
delaySignalM delta m =
Signal { handleSignal = \h ->
do r <- liftIO $ newIORef False
h <- handleSignal m $ \a ->
Event $ \p ->
do delta' <- invokeEvent p delta
invokeEvent p $
enqueueEvent (pointTime p + delta') $
do x <- liftIO $ readIORef r
unless x $ h a
return $ DisposableEvent $
disposeEvent h >>
(liftIO $ writeIORef r True)
}
traceSignal :: String -> Signal a -> Signal a
traceSignal message m =
Signal { handleSignal = \h ->
handleSignal m $ traceEvent message . h }