packages feed

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 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,