aivika-transformers 4.6.1 → 5.0.1
raw patch · 10 files changed
+690/−41 lines, 10 filesdep ~aivikaPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: aivika
API changes (from Hackage documentation)
- Simulation.Aivika.Trans.Processor: processorSignaling :: MonadDES m => Processor m a b -> Signal m a -> Process m (Signal m b)
- Simulation.Aivika.Trans.Processor: signalProcessor :: MonadDES m => (Signal m a -> Signal m b) -> Processor m a b
+ Simulation.Aivika.Trans.Arrival: arrivalTimerChannel :: MonadDES m => ArrivalTimer m -> Channel m (Arrival a) (Arrival a)
+ Simulation.Aivika.Trans.Arrival: arrivalTimerSignal :: MonadDES m => ArrivalTimer m -> Signal m (Arrival a) -> Signal m (Arrival a)
+ Simulation.Aivika.Trans.Channel: Channel :: (Signal m a -> Composite m (Signal m b)) -> Channel m a b
+ Simulation.Aivika.Trans.Channel: [runChannel] :: Channel m a b -> Signal m a -> Composite m (Signal m b)
+ Simulation.Aivika.Trans.Channel: delayChannel :: MonadDES m => Double -> Channel m a a
+ Simulation.Aivika.Trans.Channel: delayChannelM :: MonadDES m => Event m Double -> Channel m a a
+ Simulation.Aivika.Trans.Channel: instance Simulation.Aivika.Trans.DES.MonadDES m => Control.Category.Category (Simulation.Aivika.Trans.Channel.Channel m)
+ Simulation.Aivika.Trans.Channel: newtype Channel m a b
+ Simulation.Aivika.Trans.Channel: sinkSignal :: MonadDES m => Signal m a -> Composite m ()
+ Simulation.Aivika.Trans.Channel: traceChannel :: MonadDES m => String -> Channel m a b -> Channel m a b
+ Simulation.Aivika.Trans.Composite: data Composite m a
+ Simulation.Aivika.Trans.Composite: disposableComposite :: Monad m => DisposableEvent m -> Composite m ()
+ Simulation.Aivika.Trans.Composite: instance (GHC.Base.Monad m, Control.Monad.Fix.MonadFix (Simulation.Aivika.Trans.Internal.Types.Event m)) => Control.Monad.Fix.MonadFix (Simulation.Aivika.Trans.Composite.Composite m)
+ Simulation.Aivika.Trans.Composite: instance (GHC.Base.Monad m, Control.Monad.IO.Class.MonadIO (Simulation.Aivika.Trans.Internal.Types.Event m)) => Control.Monad.IO.Class.MonadIO (Simulation.Aivika.Trans.Composite.Composite m)
+ Simulation.Aivika.Trans.Composite: instance Control.Monad.Trans.Class.MonadTrans Simulation.Aivika.Trans.Composite.Composite
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => GHC.Base.Applicative (Simulation.Aivika.Trans.Composite.Composite m)
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => GHC.Base.Functor (Simulation.Aivika.Trans.Composite.Composite m)
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => GHC.Base.Monad (Simulation.Aivika.Trans.Composite.Composite m)
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => Simulation.Aivika.Trans.Comp.MonadCompTrans Simulation.Aivika.Trans.Composite.Composite m
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => Simulation.Aivika.Trans.Internal.Dynamics.DynamicsLift Simulation.Aivika.Trans.Composite.Composite m
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => Simulation.Aivika.Trans.Internal.Event.EventLift Simulation.Aivika.Trans.Composite.Composite m
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => Simulation.Aivika.Trans.Internal.Parameter.ParameterLift Simulation.Aivika.Trans.Composite.Composite m
+ Simulation.Aivika.Trans.Composite: instance GHC.Base.Monad m => Simulation.Aivika.Trans.Internal.Simulation.SimulationLift Simulation.Aivika.Trans.Composite.Composite m
+ Simulation.Aivika.Trans.Composite: runComposite :: Composite m a -> DisposableEvent m -> Event m (a, DisposableEvent m)
+ Simulation.Aivika.Trans.Composite: runCompositeInStartTime_ :: MonadDES m => Composite m a -> Simulation m a
+ Simulation.Aivika.Trans.Composite: runCompositeInStopTime_ :: MonadDES m => Composite m a -> Simulation m a
+ Simulation.Aivika.Trans.Composite: runComposite_ :: Monad m => Composite m a -> Event m a
+ Simulation.Aivika.Trans.Processor: channelProcessor :: MonadDES m => Channel m a b -> Processor m a b
+ Simulation.Aivika.Trans.Processor: processorChannel :: MonadDES m => Processor m a b -> Channel m a b
+ Simulation.Aivika.Trans.Processor: queuedChannelProcessor :: MonadDES m => (b -> Event m ()) -> Process m b -> Channel m a b -> Processor m a b
+ Simulation.Aivika.Trans.Processor: queuedProcessorChannel :: MonadDES m => (a -> Event m ()) -> (Process m a) -> Processor m a b -> Channel m a b
+ Simulation.Aivika.Trans.Signal.Random: newRandomBetaSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomBinomialSignal :: MonadDES m => Double -> Int -> Composite m (Signal m (Arrival Int))
+ Simulation.Aivika.Trans.Signal.Random: newRandomDiscreteSignal :: MonadDES m => DiscretePDF Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomErlangSignal :: MonadDES m => Double -> Int -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomExponentialSignal :: MonadDES m => Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomGammaSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomLogNormalSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomNormalSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomPoissonSignal :: MonadDES m => Double -> Composite m (Signal m (Arrival Int))
+ Simulation.Aivika.Trans.Signal.Random: newRandomSignal :: MonadDES m => Parameter m (Double, a) -> Composite m (Signal m (Arrival a))
+ Simulation.Aivika.Trans.Signal.Random: newRandomTriangularSignal :: MonadDES m => Double -> Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomUniformIntSignal :: MonadDES m => Int -> Int -> Composite m (Signal m (Arrival Int))
+ Simulation.Aivika.Trans.Signal.Random: newRandomUniformSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Signal.Random: newRandomWeibullSignal :: MonadDES m => Double -> Double -> Composite m (Signal m (Arrival Double))
+ Simulation.Aivika.Trans.Stream: queuedSignalStream :: MonadDES m => (a -> Event m ()) -> Process m a -> Signal m a -> Composite m (Stream m a)
- Simulation.Aivika.Trans.Stream: signalStream :: MonadDES m => Signal m a -> Process m (Stream m a)
+ Simulation.Aivika.Trans.Stream: signalStream :: MonadDES m => Signal m a -> Composite m (Stream m a)
- Simulation.Aivika.Trans.Stream: streamSignal :: MonadDES m => Stream m a -> Process m (Signal m a)
+ Simulation.Aivika.Trans.Stream: streamSignal :: MonadDES m => Stream m a -> Composite m (Signal m a)
Files
- CHANGELOG.md +19/−0
- Simulation/Aivika/Trans.hs +6/−0
- Simulation/Aivika/Trans/Arrival.hs +29/−0
- Simulation/Aivika/Trans/Channel.hs +89/−0
- Simulation/Aivika/Trans/Composite.hs +161/−0
- Simulation/Aivika/Trans/Processor.hs +78/−18
- Simulation/Aivika/Trans/Signal/Random.hs +264/−0
- Simulation/Aivika/Trans/Stream.hs +37/−20
- Simulation/Aivika/Trans/Stream/Random.hs +2/−1
- aivika-transformers.cabal +5/−2
CHANGELOG.md view
@@ -1,4 +1,23 @@ +Version 5.0+-----++* Added the Composite monad transformer.++* Added the Channel computation.++* Breaking change: modified signatures of functions signalStream and streamSignal.++* Breaking change: the signalProcessor function is replaced with channelProcessor.++* Breaking change: the processorSignaling function is replaced with processorChannel.++* Added module Signal.Random.++* Added functions arrivalTimerSignal and arrivalTimerChannel.++* Added functions queuedSignalStream, queuedProcessorChannel and queuedChannelProcessor.+ Version 4.6 -----
Simulation/Aivika/Trans.hs view
@@ -16,8 +16,10 @@ module Simulation.Aivika.Trans.Activity.Random, module Simulation.Aivika.Trans.Agent, module Simulation.Aivika.Trans.Arrival,+ module Simulation.Aivika.Trans.Channel, module Simulation.Aivika.Trans.Circuit, module Simulation.Aivika.Trans.Comp,+ module Simulation.Aivika.Trans.Composite, module Simulation.Aivika.Trans.Cont, module Simulation.Aivika.Trans.DES, module Simulation.Aivika.Trans.Dynamics,@@ -50,6 +52,7 @@ module Simulation.Aivika.Trans.Server, module Simulation.Aivika.Trans.Server.Random, module Simulation.Aivika.Trans.Signal,+ module Simulation.Aivika.Trans.Signal.Random, module Simulation.Aivika.Trans.Simulation, module Simulation.Aivika.Trans.Specs, module Simulation.Aivika.Trans.Statistics,@@ -66,8 +69,10 @@ import Simulation.Aivika.Trans.Activity.Random import Simulation.Aivika.Trans.Agent import Simulation.Aivika.Trans.Arrival+import Simulation.Aivika.Trans.Channel import Simulation.Aivika.Trans.Circuit import Simulation.Aivika.Trans.Comp+import Simulation.Aivika.Trans.Composite import Simulation.Aivika.Trans.Cont import Simulation.Aivika.Trans.DES import Simulation.Aivika.Trans.Dynamics@@ -100,6 +105,7 @@ import Simulation.Aivika.Trans.Server import Simulation.Aivika.Trans.Server.Random import Simulation.Aivika.Trans.Signal+import Simulation.Aivika.Trans.Signal.Random import Simulation.Aivika.Trans.Simulation import Simulation.Aivika.Trans.Specs import Simulation.Aivika.Trans.Statistics
Simulation/Aivika/Trans/Arrival.hs view
@@ -18,6 +18,8 @@ ArrivalTimer, newArrivalTimer, arrivalTimerProcessor,+ arrivalTimerSignal,+ arrivalTimerChannel, arrivalProcessingTime, arrivalProcessingTimeChanged, arrivalProcessingTimeChanged_) where@@ -29,11 +31,13 @@ import Simulation.Aivika.Trans.Simulation import Simulation.Aivika.Trans.Dynamics import Simulation.Aivika.Trans.Event+import Simulation.Aivika.Trans.Composite import Simulation.Aivika.Trans.Processor import Simulation.Aivika.Trans.Stream import Simulation.Aivika.Trans.Statistics import Simulation.Aivika.Trans.Ref import Simulation.Aivika.Trans.Signal+import Simulation.Aivika.Trans.Channel import Simulation.Aivika.Trans.DES import Simulation.Aivika.Arrival (Arrival(..)) @@ -82,3 +86,28 @@ addSamplingStats (t - arrivalTime a) triggerSignal (arrivalProcessingTimeChangedSource timer) () return (a, Cons $ loop xs)++-- | Return a signal that actually measures how much time has passed from+-- the time of arriving the events.+--+-- Note that the statistics is counted each time you subscribe to the output signal.+-- For example, if you subscribe twice then the statistics counting is duplicated.+-- Ideally, you should subscribe to the output signal only once.+arrivalTimerSignal :: MonadDES m => ArrivalTimer m -> Signal m (Arrival a) -> Signal m (Arrival a)+{-# INLINABLE arrivalTimerSignal #-}+arrivalTimerSignal timer sa =+ Signal { handleSignal = \h ->+ handleSignal sa $ \a ->+ do t <- liftDynamics time+ modifyRef (arrivalProcessingTimeRef timer) $+ addSamplingStats (t - arrivalTime a)+ h a+ }++-- | Like 'arrivalTimerSignal' but measures how much time has passed from+-- the time of arriving the events in the channel.+arrivalTimerChannel :: MonadDES m => ArrivalTimer m -> Channel m (Arrival a) (Arrival a)+{-# INLINABLE arrivalTimerChannel #-}+arrivalTimerChannel timer =+ Channel $ \sa ->+ return $ arrivalTimerSignal timer sa
+ Simulation/Aivika/Trans/Channel.hs view
@@ -0,0 +1,89 @@++-- |+-- Module : Simulation.Aivika.Trans.Channel+-- Copyright : Copyright (c) 2009-2016, David Sorokin <david.sorokin@gmail.com>+-- License : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability : experimental+-- Tested with: GHC 8.0.1+--+-- The module defines a channel that transforms one 'Signal' to another+-- within the 'Composite' computation.+--+module Simulation.Aivika.Trans.Channel+ (-- * Channel Computation+ Channel(..),+ -- * Delay Channel+ delayChannel,+ delayChannelM,+ -- * Sinking Signal+ sinkSignal,+ -- * Debugging+ traceChannel) where++import qualified Control.Category as C+import Control.Monad++import Simulation.Aivika.Trans.DES+import Simulation.Aivika.Trans.Simulation+import Simulation.Aivika.Trans.Dynamics+import Simulation.Aivika.Trans.Event+import Simulation.Aivika.Trans.Signal+import Simulation.Aivika.Trans.Composite++-- | It allows representing a signal transformation.+newtype Channel m a b =+ Channel { runChannel :: Signal m a -> Composite m (Signal m b)+ -- ^ Run the channel transform.+ }++instance MonadDES m => C.Category (Channel m) where++ {-# INLINE id #-}+ id = Channel return++ {-# INLINE (.) #-}+ (Channel g) . (Channel f) =+ Channel $ \a -> f a >>= g++-- | Return a delayed signal.+--+-- This is actually the 'delaySignal' function wrapped in the 'Channel' type. +delayChannel :: MonadDES m+ => Double -- ^ the delay+ -> Channel m a a -- ^ the delay channel+{-# INLINABLE delayChannel #-}+delayChannel delay =+ Channel $ \a -> return $ delaySignal delay a++-- | Like 'delayChannel', but it re-computes the delay each time.+--+-- This is actually the 'delaySignalM' function wrapped in the 'Channel' type. +delayChannelM :: MonadDES m+ => Event m Double -- ^ the delay+ -> Channel m a a -- ^ the delay channel+{-# INLINABLE delayChannelM #-}+delayChannelM delay =+ Channel $ \a -> return $ delaySignalM delay a++-- | Sink the signal. It returns a computation that subscribes to+-- the signal and then ignores the received data. The resulting+-- computation can be a moving force to simulate the whole system of+-- the interconnected signals and channels.+sinkSignal :: MonadDES m => Signal m a -> Composite m ()+{-# INLINABLE sinkSignal #-}+sinkSignal a =+ do h <- liftEvent $+ handleSignal a $+ const $ return ()+ disposableComposite h+ +-- | Show the debug message with the current simulation time,+-- when emitting the output signal.+traceChannel :: MonadDES m => String -> Channel m a b -> Channel m a b+{-# INLINABLE traceChannel #-}+traceChannel message (Channel f) =+ Channel $ \a ->+ do b <- f a+ return $+ traceSignal message b
+ Simulation/Aivika/Trans/Composite.hs view
@@ -0,0 +1,161 @@++{-# LANGUAGE MultiParamTypeClasses, FlexibleContexts, FlexibleInstances, UndecidableInstances, RecursiveDo #-}++-- |+-- Module : Simulation.Aivika.Trans.Composite+-- Copyright : Copyright (c) 2009-2016, David Sorokin <david.sorokin@gmail.com>+-- License : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability : experimental+-- Tested with: GHC 8.0.1+--+-- It defines the 'Composite' monad transformer that allows constructing components which+-- can be then destroyed in case of need.+--+module Simulation.Aivika.Trans.Composite+ (-- * Composite Monad+ Composite,+ runComposite,+ runComposite_,+ runCompositeInStartTime_,+ runCompositeInStopTime_,+ disposableComposite) where++import Data.Monoid++import Control.Exception+import Control.Monad+import Control.Monad.Trans+import Control.Monad.Fix+import Control.Applicative++import Simulation.Aivika.Trans.Comp+import Simulation.Aivika.Trans.DES+import Simulation.Aivika.Trans.Parameter+import Simulation.Aivika.Trans.Simulation+import Simulation.Aivika.Trans.Dynamics+import Simulation.Aivika.Trans.Event++-- | It represents a composite which can be then destroyed in case of need.+newtype Composite m a = Composite { runComposite :: DisposableEvent m -> Event m (a, DisposableEvent m)+ -- ^ Run the computation returning the result+ -- and some 'DisposableEvent' that being applied+ -- destroys the composite, for example, unsubscribes+ -- from signals or cancels the processes.+ --+ }++-- | Like 'runComposite' but retains the composite parts during the simulation.+runComposite_ :: Monad m => Composite m a -> Event m a+{-# INLINABLE runComposite_ #-}+runComposite_ m =+ do (a, _) <- runComposite m mempty+ return a++-- | Like 'runComposite_' but runs the computation in the start time.+runCompositeInStartTime_ :: MonadDES m => Composite m a -> Simulation m a+{-# INLINABLE runCompositeInStartTime_ #-}+runCompositeInStartTime_ = runEventInStartTime . runComposite_++-- | Like 'runComposite_' but runs the computation in the stop time.+runCompositeInStopTime_ :: MonadDES m => Composite m a -> Simulation m a+{-# INLINABLE runCompositeInStopTime_ #-}+runCompositeInStopTime_ = runEventInStopTime . runComposite_++-- | When destroying the composite, the specified action will be applied.+disposableComposite :: Monad m => DisposableEvent m -> Composite m ()+{-# INLINABLE disposableComposite #-}+disposableComposite h = Composite $ \h0 -> return ((), h0 <> h)++instance Monad m => Functor (Composite m) where++ {-# INLINE fmap #-}+ fmap f (Composite m) =+ Composite $ \h0 ->+ do (a, h) <- m h0+ return (f a, h)++instance Monad m => Applicative (Composite m) where++ {-# INLINE pure #-}+ pure = return++ {-# INLINE (<*>) #-}+ (<*>) = ap++instance Monad m => Monad (Composite m) where++ {-# INLINE return #-}+ return a = Composite $ \h0 -> return (a, h0)++ {-# INLINE (>>=) #-}+ (Composite m) >>= k =+ Composite $ \h0 ->+ do (a, h) <- m h0+ let Composite m' = k a+ (b, h') <- m' h+ return (b, h')++instance (Monad m, MonadIO (Event m)) => MonadIO (Composite m) where++ {-# INLINE liftIO #-}+ liftIO m =+ Composite $ \h0 ->+ do a <- liftIO m+ return (a, h0)++instance (Monad m, MonadFix (Event m)) => MonadFix (Composite m) where++ {-# INLINABLE mfix #-}+ mfix f =+ Composite $ \h0 ->+ do rec (a, h) <- runComposite (f a) h0+ return (a, h)++instance MonadTrans Composite where++ {-# INLINE lift #-}+ lift m =+ Composite $ \h0 ->+ do a <- lift m+ return (a, h0)++instance Monad m => MonadCompTrans Composite m where++ {-# INLINE liftComp #-}+ liftComp m =+ Composite $ \h0 ->+ do a <- liftComp m+ return (a, h0)++instance Monad m => ParameterLift Composite m where++ {-# INLINE liftParameter #-}+ liftParameter m =+ Composite $ \h0 ->+ do a <- liftParameter m+ return (a, h0)++instance Monad m => SimulationLift Composite m where++ {-# INLINE liftSimulation #-}+ liftSimulation m =+ Composite $ \h0 ->+ do a <- liftSimulation m+ return (a, h0)++instance Monad m => DynamicsLift Composite m where++ {-# INLINE liftDynamics #-}+ liftDynamics m =+ Composite $ \h0 ->+ do a <- liftDynamics m+ return (a, h0)++instance Monad m => EventLift Composite m where++ {-# INLINE liftEvent #-}+ liftEvent m =+ Composite $ \h0 ->+ do a <- liftEvent m+ return (a, h0)
Simulation/Aivika/Trans/Processor.hs view
@@ -46,24 +46,30 @@ joinProcessor, -- * Failover failoverProcessor,- -- * Integrating with Signals- signalProcessor,- processorSignaling,+ -- * Integrating with Signals and Channels+ channelProcessor,+ processorChannel,+ queuedChannelProcessor,+ queuedProcessorChannel, -- * Debugging traceProcessor) where import qualified Control.Category as C import Control.Arrow +import Data.Monoid+ import Simulation.Aivika.Trans.DES import Simulation.Aivika.Trans.Simulation import Simulation.Aivika.Trans.Dynamics import Simulation.Aivika.Trans.Event+import Simulation.Aivika.Trans.Composite import Simulation.Aivika.Trans.Cont import Simulation.Aivika.Trans.Process import Simulation.Aivika.Trans.Stream import Simulation.Aivika.Trans.QueueStrategy import Simulation.Aivika.Trans.Signal+import Simulation.Aivika.Trans.Channel import Simulation.Aivika.Arrival (Arrival(..)) -- | Represents a processor of simulation data.@@ -471,41 +477,95 @@ {-# INLINABLE prefetchProcessor #-} prefetchProcessor = Processor prefetchStream --- | Convert the specified signal transform to a processor.+-- | Convert the specified signal transform, i.e. the channel, to a processor. -- -- The processor may return data with delay as the values are requested by demand. -- Consider using the 'arrivalSignal' function to provide with the information -- about the time points at which the signal was actually triggered. -- -- The point is that the 'Stream' used in the 'Processor' is requested outside, --- while the 'Signal' is triggered inside. They are different by nature. +-- while the 'Signal' used in the 'Channel' is triggered inside. They are different by nature. -- The former is passive, while the latter is active. ----- Cancel the processor's process to unsubscribe from the signals provided.-signalProcessor :: MonadDES m => (Signal m a -> Signal m b) -> Processor m a b-{-# INLINABLE signalProcessor #-}-signalProcessor f =+-- The resulting processor may be a root of space leak as it uses an internal queue to store+-- the values received from the input signal. Consider using 'queuedChannelProcessor' that+-- allows specifying the bounded queue in case of need.+channelProcessor :: MonadDES m => Channel m a b -> Processor m a b+{-# INLINABLE channelProcessor #-}+channelProcessor f = Processor $ \xs -> Cons $- do sa <- streamSignal xs- sb <- signalStream (f sa)- runStream sb+ do let composite =+ do sa <- streamSignal xs+ sb <- runChannel f sa+ signalStream sb+ (ys, h) <- liftEvent $+ runComposite composite mempty+ whenCancellingProcess $+ disposeEvent h+ runStream ys --- | Convert the specified processor to a signal transform. +-- | Convert the specified processor to a signal transform, i.e. the channel. -- -- The processor may return data with delay as the values are requested by demand. -- Consider using the 'arrivalSignal' function to provide with the information -- about the time points at which the signal was actually triggered. -- -- The point is that the 'Stream' used in the 'Processor' is requested outside, --- while the 'Signal' is triggered inside. They are different by nature.+-- while the 'Signal' used in 'Channel' is triggered inside. They are different by nature. -- The former is passive, while the latter is active. ----- Cancel the returned process to unsubscribe from the signal specified.-processorSignaling :: MonadDES m => Processor m a b -> Signal m a -> Process m (Signal m b)-{-# INLINABLE processorSignaling #-}-processorSignaling (Processor f) sa =+-- The resulting channel may be a root of space leak as it uses an internal queue to store+-- the values received from the input stream. Consider using 'queuedProcessorChannel' that+-- allows specifying the bounded queue in case of need.+processorChannel :: MonadDES m => Processor m a b -> Channel m a b+{-# INLINABLE processorChannel #-}+processorChannel (Processor f) =+ Channel $ \sa -> do xs <- signalStream sa+ let ys = f xs+ streamSignal ys++-- | Like 'channelProcessor' but allows specifying an arbitrary queue for storing the signal values,+-- for example, the bounded queue.+queuedChannelProcessor :: MonadDES m+ => (b -> Event m ())+ -- ^ enqueue+ -> Process m b+ -- ^ dequeue+ -> Channel m a b+ -- ^ the channel+ -> Processor m a b+ -- ^ the processor+{-# INLINABLE queuedChannelProcessor #-}+queuedChannelProcessor enqueue dequeue f =+ Processor $ \xs ->+ Cons $+ do let composite =+ do sa <- streamSignal xs+ sb <- runChannel f sa+ queuedSignalStream enqueue dequeue sb+ (ys, h) <- liftEvent $+ runComposite composite mempty+ whenCancellingProcess $+ disposeEvent h+ runStream ys++-- | Like 'processorChannel' but allows specifying an arbitrary queue for storing the signal values,+-- for example, the bounded queue.+queuedProcessorChannel :: MonadDES m =>+ (a -> Event m ())+ -- ^ enqueue+ -> (Process m a)+ -- ^ dequeue+ -> Processor m a b+ -- ^ the processor+ -> Channel m a b+ -- ^ the channel+{-# INLINABLE queuedProcessorChannel #-}+queuedProcessorChannel enqueue dequeue (Processor f) =+ Channel $ \sa ->+ do xs <- queuedSignalStream enqueue dequeue sa let ys = f xs streamSignal ys
+ Simulation/Aivika/Trans/Signal/Random.hs view
@@ -0,0 +1,264 @@++-- |+-- Module : Simulation.Aivika.Trans.Signal.Random+-- Copyright : Copyright (c) 2009-2016, David Sorokin <david.sorokin@gmail.com>+-- License : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability : experimental+-- Tested with: GHC 8.0.1+--+-- This module defines random signals of events, which are useful+-- for describing the input of the model.+--++module Simulation.Aivika.Trans.Signal.Random+ (-- * Signal of Random Events+ newRandomSignal,+ newRandomUniformSignal,+ newRandomUniformIntSignal,+ newRandomTriangularSignal,+ newRandomNormalSignal,+ newRandomLogNormalSignal,+ newRandomExponentialSignal,+ newRandomErlangSignal,+ newRandomPoissonSignal,+ newRandomBinomialSignal,+ newRandomGammaSignal,+ newRandomBetaSignal,+ newRandomWeibullSignal,+ newRandomDiscreteSignal) where++import Control.Monad+import Control.Monad.Trans++import Simulation.Aivika.Trans.DES+import Simulation.Aivika.Trans.Generator+import Simulation.Aivika.Trans.Parameter+import Simulation.Aivika.Trans.Parameter.Random+import Simulation.Aivika.Trans.Simulation+import Simulation.Aivika.Trans.Dynamics+import Simulation.Aivika.Trans.Event+import Simulation.Aivika.Trans.Composite+import Simulation.Aivika.Trans.Process+import Simulation.Aivika.Trans.Signal+import Simulation.Aivika.Trans.Statistics+import Simulation.Aivika.Trans.Arrival++-- | Return a signal of random events that arrive with the specified delay.+newRandomSignal :: MonadDES m+ => Parameter m (Double, a)+ -- ^ compute a pair of the delay and event of type @a@+ -> Composite m (Signal m (Arrival a))+ -- ^ the computation that returns a signal emitting the delayed events+{-# INLINABLE newRandomSignal #-}+newRandomSignal delay =+ do source <- liftSimulation newSignalSource+ let loop t0 =+ do (delay, a) <- liftParameter delay+ when (delay > 0) $+ holdProcess delay+ t2 <- liftDynamics time+ let arrival = Arrival { arrivalValue = a,+ arrivalTime = t2,+ arrivalDelay =+ case t0 of+ Nothing -> Nothing+ Just t0 -> Just delay }+ liftEvent $+ triggerSignal source arrival+ loop (Just t2)+ pid <- liftSimulation newProcessId+ liftEvent $+ runProcessUsingId pid $+ loop Nothing+ disposableComposite $+ DisposableEvent $+ cancelProcessWithId pid+ return $ publishSignal source++-- | Create a new signal with random delays distributed uniformly.+newRandomUniformSignal :: MonadDES m+ => Double+ -- ^ the minimum delay+ -> Double+ -- ^ the maximum delay+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomUniformSignal #-}+newRandomUniformSignal min max =+ newRandomSignal $+ randomUniform min max >>= \x ->+ return (x, x)++-- | Create a new signal with integer random delays distributed uniformly.+newRandomUniformIntSignal :: MonadDES m+ => Int+ -- ^ the minimum delay+ -> Int+ -- ^ the maximum delay+ -> Composite m (Signal m (Arrival Int))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomUniformIntSignal #-}+newRandomUniformIntSignal min max =+ newRandomSignal $+ randomUniformInt min max >>= \x ->+ return (fromIntegral x, x)++-- | Create a new signal with random delays having the triangular distribution.+newRandomTriangularSignal :: MonadDES m+ => Double+ -- ^ the minimum delay+ -> Double+ -- ^ the median of the delay+ -> Double+ -- ^ the maximum delay+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomTriangularSignal #-}+newRandomTriangularSignal min median max =+ newRandomSignal $+ randomTriangular min median max >>= \x ->+ return (x, x)++-- | Create a new signal with random delays distributed normally.+newRandomNormalSignal :: MonadDES m+ => Double+ -- ^ the mean delay+ -> Double+ -- ^ the delay deviation+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomNormalSignal #-}+newRandomNormalSignal mu nu =+ newRandomSignal $+ randomNormal mu nu >>= \x ->+ return (x, x)++-- | Create a new signal with random delays having the lognormal distribution.+newRandomLogNormalSignal :: MonadDES m+ => Double+ -- ^ the mean of a normal distribution which+ -- this distribution is derived from+ -> Double+ -- ^ the deviation of a normal distribution which+ -- this distribution is derived from+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomLogNormalSignal #-}+newRandomLogNormalSignal mu nu =+ newRandomSignal $+ randomLogNormal mu nu >>= \x ->+ return (x, x)++-- | Return a new signal with random delays distibuted exponentially with the specified mean+-- (the reciprocal of the rate).+newRandomExponentialSignal :: MonadDES m+ => Double+ -- ^ the mean delay (the reciprocal of the rate)+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomExponentialSignal #-}+newRandomExponentialSignal mu =+ newRandomSignal $+ randomExponential mu >>= \x ->+ return (x, x)+ +-- | Return a new signal with random delays having the Erlang distribution with the specified+-- scale (the reciprocal of the rate) and shape parameters.+newRandomErlangSignal :: MonadDES m+ => Double+ -- ^ the scale (the reciprocal of the rate)+ -> Int+ -- ^ the shape+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomErlangSignal #-}+newRandomErlangSignal beta m =+ newRandomSignal $+ randomErlang beta m >>= \x ->+ return (x, x)++-- | Return a new signal with random delays having the Poisson distribution with+-- the specified mean.+newRandomPoissonSignal :: MonadDES m+ => Double+ -- ^ the mean delay+ -> Composite m (Signal m (Arrival Int))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomPoissonSignal #-}+newRandomPoissonSignal mu =+ newRandomSignal $+ randomPoisson mu >>= \x ->+ return (fromIntegral x, x)++-- | Return a new signal with random delays having the binomial distribution with the specified+-- probability and trials.+newRandomBinomialSignal :: MonadDES m+ => Double+ -- ^ the probability+ -> Int+ -- ^ the number of trials+ -> Composite m (Signal m (Arrival Int))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomBinomialSignal #-}+newRandomBinomialSignal prob trials =+ newRandomSignal $+ randomBinomial prob trials >>= \x ->+ return (fromIntegral x, x)++-- | Return a new signal with random delays having the Gamma distribution by the specified+-- shape and scale.+newRandomGammaSignal :: MonadDES m+ => Double+ -- ^ the shape+ -> Double+ -- ^ the scale (a reciprocal of the rate)+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomGammaSignal #-}+newRandomGammaSignal kappa theta =+ newRandomSignal $+ randomGamma kappa theta >>= \x ->+ return (x, x)++-- | Return a new signal with random delays having the Beta distribution by the specified+-- shape parameters (alpha and beta).+newRandomBetaSignal :: MonadDES m+ => Double+ -- ^ the shape (alpha)+ -> Double+ -- ^ the shape (beta)+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomBetaSignal #-}+newRandomBetaSignal alpha beta =+ newRandomSignal $+ randomBeta alpha beta >>= \x ->+ return (x, x)++-- | Return a new signal with random delays having the Weibull distribution by the specified+-- shape and scale.+newRandomWeibullSignal :: MonadDES m+ => Double+ -- ^ shape+ -> Double+ -- ^ scale+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomWeibullSignal #-}+newRandomWeibullSignal alpha beta =+ newRandomSignal $+ randomWeibull alpha beta >>= \x ->+ return (x, x)++-- | Return a new signal with random delays having the specified discrete distribution.+newRandomDiscreteSignal :: MonadDES m+ => DiscretePDF Double+ -- ^ the discrete probability density function+ -> Composite m (Signal m (Arrival Double))+ -- ^ the computation of signal emitting random events with the delays generated+{-# INLINABLE newRandomDiscreteSignal #-}+newRandomDiscreteSignal dpdf =+ newRandomSignal $+ randomDiscrete dpdf >>= \x ->+ return (x, x)
Simulation/Aivika/Trans/Stream.hs view
@@ -68,6 +68,7 @@ -- * Integrating with Signals signalStream, streamSignal,+ queuedSignalStream, -- * Utilities leftStream, rightStream,@@ -95,12 +96,13 @@ import Simulation.Aivika.Trans.Simulation import Simulation.Aivika.Trans.Dynamics import Simulation.Aivika.Trans.Event+import Simulation.Aivika.Trans.Composite import Simulation.Aivika.Trans.Cont import Simulation.Aivika.Trans.Process import Simulation.Aivika.Trans.Signal import Simulation.Aivika.Trans.Resource.Base import Simulation.Aivika.Trans.QueueStrategy-import Simulation.Aivika.Trans.Queue.Infinite.Base+import qualified Simulation.Aivika.Trans.Queue.Infinite.Base as IQ import Simulation.Aivika.Arrival (Arrival(..)) -- | Represents an infinite stream of data in time,@@ -600,6 +602,23 @@ spawnProcess $ writer s runStream $ repeatProcess reader +-- | Like 'signalStream' but allows specifying an arbitrary queue instead of the unbounded queue.+queuedSignalStream :: MonadDES m+ => (a -> Event m ())+ -- ^ enqueue+ -> Process m a+ -- ^ dequeue+ -> Signal m a+ -- ^ the input signal+ -> Composite m (Stream m a)+ -- ^ the output stream+{-# INLINABLE queuedSignalStream #-}+queuedSignalStream enqueue dequeue s =+ do h <- liftEvent $+ handleSignal s enqueue+ disposableComposite h+ return $ repeatProcess dequeue+ -- | Return a stream of values triggered by the specified signal. -- -- Since the time at which the values of the stream are requested for may differ from@@ -610,32 +629,30 @@ -- The point is that the 'Stream' is requested outside, while the 'Signal' is triggered -- inside. They are different by nature. The former is passive, while the latter is active. ----- The resulting stream may be a root of space leak as it uses an internal queue to store+-- The resulting stream may be a root of space leak as it uses an internal unbounded queue to store -- the values received from the signal. The oldest value is dequeued each time we request--- the stream and it is returned within the computation.------ Cancel the stream's process to unsubscribe from the specified signal.-signalStream :: MonadDES m => Signal m a -> Process m (Stream m a)+-- the stream and it is returned within the computation. Consider using 'queuedSignalStream' that+-- allows specifying the bounded queue in case of need.+signalStream :: MonadDES m => Signal m a -> Composite m (Stream m a) {-# INLINABLE signalStream #-} signalStream s =- do q <- liftSimulation newFCFSQueue- h <- liftEvent $- handleSignal s $ - enqueue q- whenCancellingProcess $ disposeEvent h- return $ repeatProcess $ dequeue q+ do q <- liftSimulation IQ.newFCFSQueue+ queuedSignalStream (IQ.enqueue q) (IQ.dequeue q) s -- | Return a computation of the signal that triggers values from the specified stream, -- each time the next value of the stream is received within the underlying 'Process' -- computation.------ Cancel the returned process to stop reading from the specified stream. -streamSignal :: MonadDES m => Stream m a -> Process m (Signal m a)+streamSignal :: MonadDES m => Stream m a -> Composite m (Signal m a) {-# INLINABLE streamSignal #-} streamSignal z = do s <- liftSimulation newSignalSource- spawnProcess $+ pid <- liftSimulation newProcessId+ liftEvent $+ runProcessUsingId pid $ consumeStream (liftEvent . triggerSignal s) z+ disposableComposite $+ DisposableEvent $+ cancelProcessWithId pid return $ publishSignal s -- | Transform a stream so that the resulting stream returns a sequence of arrivals@@ -779,16 +796,16 @@ cloneStream :: MonadDES m => Int -> Stream m a -> Simulation m [Stream m a] {-# INLINABLE cloneStream #-} cloneStream n s =- do qs <- forM [1..n] $ \i -> newFCFSQueue+ do qs <- forM [1..n] $ \i -> IQ.newFCFSQueue rs <- newFCFSResource 1 ref <- newRef s let reader m q =- do a <- liftEvent $ tryDequeue q+ do a <- liftEvent $ IQ.tryDequeue q case a of Just a -> return a Nothing -> usingResource rs $- do a <- liftEvent $ tryDequeue q+ do a <- liftEvent $ IQ.tryDequeue q case a of Just a -> return a Nothing ->@@ -797,7 +814,7 @@ liftEvent $ writeRef ref xs forM_ (zip [1..] qs) $ \(i, q) -> unless (i == m) $- liftEvent $ enqueue q a+ liftEvent $ IQ.enqueue q a return a forM (zip [1..] qs) $ \(i, q) -> return $ repeatProcess $ reader i q
Simulation/Aivika/Trans/Stream/Random.hs view
@@ -66,7 +66,8 @@ "At least, they can be lost, for example, when trying to enqueue them, but " ++ "the random stream itself must always execute: randomStream." (delay, a) <- liftParameter delay- holdProcess delay+ when (delay > 0) $+ holdProcess delay t2 <- liftDynamics time let arrival = Arrival { arrivalValue = a, arrivalTime = t2,
aivika-transformers.cabal view
@@ -1,5 +1,5 @@ name: aivika-transformers-version: 4.6.1+version: 5.0.1 synopsis: Transformers for the Aivika simulation library description: This package is a generalization of the aivika [1] simulation library@@ -53,8 +53,10 @@ Simulation.Aivika.Trans.Agent Simulation.Aivika.Trans.Array Simulation.Aivika.Trans.Arrival+ Simulation.Aivika.Trans.Channel Simulation.Aivika.Trans.Circuit Simulation.Aivika.Trans.Comp+ Simulation.Aivika.Trans.Composite Simulation.Aivika.Trans.Cont Simulation.Aivika.Trans.DoubleLinkedList Simulation.Aivika.Trans.DES@@ -99,6 +101,7 @@ Simulation.Aivika.Trans.Server Simulation.Aivika.Trans.Server.Random Simulation.Aivika.Trans.Signal+ Simulation.Aivika.Trans.Signal.Random Simulation.Aivika.Trans.Simulation Simulation.Aivika.Trans.Specs Simulation.Aivika.Trans.Statistics@@ -145,7 +148,7 @@ containers >= 0.4.0.0, random >= 1.0.0.3, vector >= 0.10.0.1,- aivika >= 4.5+ aivika >= 5.0 other-extensions: FlexibleContexts, FlexibleInstances,