packages feed

aivika 3.1 → 4.0

raw patch · 27 files changed

+2201/−395 lines, 27 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Simulation.Aivika.Activity: ActivityInterruption :: a -> Double -> Double -> ActivityInterruption a
- Simulation.Aivika.Activity: activityInterrupted :: Activity s a b -> Signal (ActivityInterruption a)
- Simulation.Aivika.Activity: activityInterruptedInput :: ActivityInterruption a -> a
- Simulation.Aivika.Activity: activityInterruptionTime :: ActivityInterruption a -> Double
- Simulation.Aivika.Activity: activityStartProcessingTime :: ActivityInterruption a -> Double
- Simulation.Aivika.Activity: data ActivityInterruption a
- Simulation.Aivika.Activity: newInterruptibleActivity :: Bool -> (a -> Process b) -> Simulation (Activity () a b)
- Simulation.Aivika.Activity: newInterruptibleStateActivity :: Bool -> (s -> a -> Process (s, b)) -> s -> Simulation (Activity s a b)
- Simulation.Aivika.Server: ServerInterruption :: a -> Double -> Double -> ServerInterruption a
- Simulation.Aivika.Server: data ServerInterruption a
- Simulation.Aivika.Server: newInterruptibleServer :: Bool -> (a -> Process b) -> Simulation (Server () a b)
- Simulation.Aivika.Server: newInterruptibleStateServer :: Bool -> (s -> a -> Process (s, b)) -> s -> Simulation (Server s a b)
- Simulation.Aivika.Server: serverInterruptedInput :: ServerInterruption a -> a
- Simulation.Aivika.Server: serverInterruptionTime :: ServerInterruption a -> Double
- Simulation.Aivika.Server: serverStartProcessingTime :: ServerInterruption a -> Double
- Simulation.Aivika.Server: serverTaskInterrupted :: Server s a b -> Signal (ServerInterruption a)
+ Simulation.Aivika.Activity: activityPreempting :: Activity s a b -> Signal a
+ Simulation.Aivika.Activity: activityPreemptionFactor :: Activity s a b -> Event Double
+ Simulation.Aivika.Activity: activityPreemptionFactorChanged :: Activity s a b -> Signal Double
+ Simulation.Aivika.Activity: activityPreemptionFactorChanged_ :: Activity s a b -> Signal ()
+ Simulation.Aivika.Activity: activityPreemptionTime :: Activity s a b -> Event (SamplingStats Double)
+ Simulation.Aivika.Activity: activityPreemptionTimeChanged :: Activity s a b -> Signal (SamplingStats Double)
+ Simulation.Aivika.Activity: activityPreemptionTimeChanged_ :: Activity s a b -> Signal ()
+ Simulation.Aivika.Activity: activityReentering :: Activity s a b -> Signal a
+ Simulation.Aivika.Activity: activityTotalPreemptionTime :: Activity s a b -> Event Double
+ Simulation.Aivika.Activity: activityTotalPreemptionTimeChanged :: Activity s a b -> Signal Double
+ Simulation.Aivika.Activity: activityTotalPreemptionTimeChanged_ :: Activity s a b -> Signal ()
+ Simulation.Aivika.Activity: newPreemptibleActivity :: Bool -> (a -> Process b) -> Simulation (Activity () a b)
+ Simulation.Aivika.Activity: newPreemptibleStateActivity :: Bool -> (s -> a -> Process (s, b)) -> s -> Simulation (Activity s a b)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomBinomialActivity :: Bool -> Double -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomErlangActivity :: Bool -> Double -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomExponentialActivity :: Bool -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomNormalActivity :: Bool -> Double -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomPoissonActivity :: Bool -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomUniformActivity :: Bool -> Double -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newPreemptibleRandomUniformIntActivity :: Bool -> Int -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomBinomialActivity :: Double -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomErlangActivity :: Double -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomExponentialActivity :: Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomNormalActivity :: Double -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomPoissonActivity :: Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomUniformActivity :: Double -> Double -> Simulation (Activity () a a)
+ Simulation.Aivika.Activity.Random: newRandomUniformIntActivity :: Int -> Int -> Simulation (Activity () a a)
+ Simulation.Aivika.Net: withinNet :: Process () -> Net a a
+ Simulation.Aivika.Net.Random: randomBinomialNet :: Double -> Int -> Net a a
+ Simulation.Aivika.Net.Random: randomErlangNet :: Double -> Int -> Net a a
+ Simulation.Aivika.Net.Random: randomExponentialNet :: Double -> Net a a
+ Simulation.Aivika.Net.Random: randomNormalNet :: Double -> Double -> Net a a
+ Simulation.Aivika.Net.Random: randomPoissonNet :: Double -> Net a a
+ Simulation.Aivika.Net.Random: randomUniformIntNet :: Int -> Int -> Net a a
+ Simulation.Aivika.Net.Random: randomUniformNet :: Double -> Double -> Net a a
+ Simulation.Aivika.PriorityQueue: remove :: Eq a => PriorityQueue a -> a -> IO Bool
+ Simulation.Aivika.PriorityQueue: removeBy :: PriorityQueue a -> (a -> Bool) -> IO Bool
+ Simulation.Aivika.Process: processPreemptionBeginning :: ProcessId -> Signal ()
+ Simulation.Aivika.Process: processPreemptionEnding :: ProcessId -> Signal ()
+ Simulation.Aivika.Process.Random: randomBinomialProcess :: Double -> Int -> Process Int
+ Simulation.Aivika.Process.Random: randomBinomialProcess_ :: Double -> Int -> Process ()
+ Simulation.Aivika.Process.Random: randomErlangProcess :: Double -> Int -> Process Double
+ Simulation.Aivika.Process.Random: randomErlangProcess_ :: Double -> Int -> Process ()
+ Simulation.Aivika.Process.Random: randomExponentialProcess :: Double -> Process Double
+ Simulation.Aivika.Process.Random: randomExponentialProcess_ :: Double -> Process ()
+ Simulation.Aivika.Process.Random: randomNormalProcess :: Double -> Double -> Process Double
+ Simulation.Aivika.Process.Random: randomNormalProcess_ :: Double -> Double -> Process ()
+ Simulation.Aivika.Process.Random: randomPoissonProcess :: Double -> Process Int
+ Simulation.Aivika.Process.Random: randomPoissonProcess_ :: Double -> Process ()
+ Simulation.Aivika.Process.Random: randomUniformIntProcess :: Int -> Int -> Process Int
+ Simulation.Aivika.Process.Random: randomUniformIntProcess_ :: Int -> Int -> Process ()
+ Simulation.Aivika.Process.Random: randomUniformProcess :: Double -> Double -> Process Double
+ Simulation.Aivika.Process.Random: randomUniformProcess_ :: Double -> Double -> Process ()
+ Simulation.Aivika.Processor: withinProcessor :: Process () -> Processor a a
+ Simulation.Aivika.Processor.Random: randomBinomialProcessor :: Double -> Int -> Processor a a
+ Simulation.Aivika.Processor.Random: randomErlangProcessor :: Double -> Int -> Processor a a
+ Simulation.Aivika.Processor.Random: randomExponentialProcessor :: Double -> Processor a a
+ Simulation.Aivika.Processor.Random: randomNormalProcessor :: Double -> Double -> Processor a a
+ Simulation.Aivika.Processor.Random: randomPoissonProcessor :: Double -> Processor a a
+ Simulation.Aivika.Processor.Random: randomUniformIntProcessor :: Int -> Int -> Processor a a
+ Simulation.Aivika.Processor.Random: randomUniformProcessor :: Double -> Double -> Processor a a
+ Simulation.Aivika.Resource: incResourceCount :: DequeueStrategy s => Resource s -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption: alterResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption: data Resource
+ Simulation.Aivika.Resource.Preemption: decResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption: incResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption: instance Eq Resource
+ Simulation.Aivika.Resource.Preemption: instance Eq ResourceActingItem
+ Simulation.Aivika.Resource.Preemption: newResource :: Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption: newResourceWithMaxCount :: Int -> Maybe Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption: releaseResource :: Resource -> Process ()
+ Simulation.Aivika.Resource.Preemption: requestResourceWithPriority :: Resource -> Double -> Process ()
+ Simulation.Aivika.Resource.Preemption: resourceCount :: Resource -> Event Int
+ Simulation.Aivika.Resource.Preemption: resourceMaxCount :: Resource -> Maybe Int
+ Simulation.Aivika.Resource.Preemption: usingResourceWithPriority :: Resource -> Double -> Process a -> Process a
+ Simulation.Aivika.Results.Locale: ActivityPreemptionFactorId :: ResultId
+ Simulation.Aivika.Results.Locale: ActivityPreemptionTimeId :: ResultId
+ Simulation.Aivika.Results.Locale: ActivityTotalPreemptionTimeId :: ResultId
+ Simulation.Aivika.Results.Locale: ServerPreemptionFactorId :: ResultId
+ Simulation.Aivika.Results.Locale: ServerPreemptionTimeId :: ResultId
+ Simulation.Aivika.Results.Locale: ServerTotalPreemptionTimeId :: ResultId
+ Simulation.Aivika.Server: newPreemptibleServer :: Bool -> (a -> Process b) -> Simulation (Server () a b)
+ Simulation.Aivika.Server: newPreemptibleStateServer :: Bool -> (s -> a -> Process (s, b)) -> s -> Simulation (Server s a b)
+ Simulation.Aivika.Server: serverPreemptionFactor :: Server s a b -> Event Double
+ Simulation.Aivika.Server: serverPreemptionFactorChanged :: Server s a b -> Signal Double
+ Simulation.Aivika.Server: serverPreemptionFactorChanged_ :: Server s a b -> Signal ()
+ Simulation.Aivika.Server: serverPreemptionTime :: Server s a b -> Event (SamplingStats Double)
+ Simulation.Aivika.Server: serverPreemptionTimeChanged :: Server s a b -> Signal (SamplingStats Double)
+ Simulation.Aivika.Server: serverPreemptionTimeChanged_ :: Server s a b -> Signal ()
+ Simulation.Aivika.Server: serverTaskPreempting :: Server s a b -> Signal a
+ Simulation.Aivika.Server: serverTaskReentering :: Server s a b -> Signal a
+ Simulation.Aivika.Server: serverTotalPreemptionTime :: Server s a b -> Event Double
+ Simulation.Aivika.Server: serverTotalPreemptionTimeChanged :: Server s a b -> Signal Double
+ Simulation.Aivika.Server: serverTotalPreemptionTimeChanged_ :: Server s a b -> Signal ()
+ Simulation.Aivika.Server.Random: newPreemptibleRandomBinomialServer :: Bool -> Double -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomErlangServer :: Bool -> Double -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomExponentialServer :: Bool -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomNormalServer :: Bool -> Double -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomPoissonServer :: Bool -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomUniformIntServer :: Bool -> Int -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newPreemptibleRandomUniformServer :: Bool -> Double -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomBinomialServer :: Double -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomErlangServer :: Double -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomExponentialServer :: Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomNormalServer :: Double -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomPoissonServer :: Double -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomUniformIntServer :: Int -> Int -> Simulation (Server () a a)
+ Simulation.Aivika.Server.Random: newRandomUniformServer :: Double -> Double -> Simulation (Server () a a)
+ Simulation.Aivika.Signal: filterSignalM_ :: (a -> Event Bool) -> Signal a -> Signal ()
+ Simulation.Aivika.Signal: filterSignal_ :: (a -> Bool) -> Signal a -> Signal ()
+ Simulation.Aivika.Stream: dropStream :: Int -> Stream a -> Stream a
+ Simulation.Aivika.Stream: dropStreamWhile :: (a -> Bool) -> Stream a -> Stream a
+ Simulation.Aivika.Stream: dropStreamWhileM :: (a -> Process Bool) -> Stream a -> Stream a
+ Simulation.Aivika.Stream: takeStream :: Int -> Stream a -> Stream a
+ Simulation.Aivika.Stream: takeStreamWhile :: (a -> Bool) -> Stream a -> Stream a
+ Simulation.Aivika.Stream: takeStreamWhileM :: (a -> Process Bool) -> Stream a -> Stream a

Files

Simulation/Aivika.hs view
@@ -13,6 +13,7 @@ module Simulation.Aivika        (-- * Modules         module Simulation.Aivika.Activity,+        module Simulation.Aivika.Activity.Random,         module Simulation.Aivika.Agent,         module Simulation.Aivika.Arrival,         module Simulation.Aivika.Circuit,@@ -24,10 +25,13 @@         module Simulation.Aivika.Event,         module Simulation.Aivika.Generator,         module Simulation.Aivika.Net,+        module Simulation.Aivika.Net.Random,         module Simulation.Aivika.Parameter,         module Simulation.Aivika.Parameter.Random,         module Simulation.Aivika.Process,+        module Simulation.Aivika.Process.Random,         module Simulation.Aivika.Processor,+        module Simulation.Aivika.Processor.Random,         module Simulation.Aivika.Processor.RoundRobbin,         module Simulation.Aivika.QueueStrategy,         module Simulation.Aivika.Ref,@@ -36,6 +40,7 @@         module Simulation.Aivika.Results.Locale,         module Simulation.Aivika.Results.IO,         module Simulation.Aivika.Server,+        module Simulation.Aivika.Server.Random,         module Simulation.Aivika.Signal,         module Simulation.Aivika.Simulation,         module Simulation.Aivika.Specs,@@ -50,6 +55,7 @@         module Simulation.Aivika.Var.Unboxed) where  import Simulation.Aivika.Activity+import Simulation.Aivika.Activity.Random import Simulation.Aivika.Agent import Simulation.Aivika.Arrival import Simulation.Aivika.Circuit@@ -61,10 +67,13 @@ import Simulation.Aivika.Event import Simulation.Aivika.Generator import Simulation.Aivika.Net+import Simulation.Aivika.Net.Random import Simulation.Aivika.Parameter import Simulation.Aivika.Parameter.Random import Simulation.Aivika.Process+import Simulation.Aivika.Process.Random import Simulation.Aivika.Processor+import Simulation.Aivika.Processor.Random import Simulation.Aivika.Processor.RoundRobbin import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Ref@@ -73,6 +82,7 @@ import Simulation.Aivika.Results.Locale import Simulation.Aivika.Results.IO import Simulation.Aivika.Server+import Simulation.Aivika.Server.Random import Simulation.Aivika.Signal import Simulation.Aivika.Simulation import Simulation.Aivika.Specs
Simulation/Aivika/Activity.hs view
@@ -12,11 +12,10 @@ module Simulation.Aivika.Activity        (-- * Activity         Activity,-        ActivityInterruption(..),         newActivity,         newStateActivity,-        newInterruptibleActivity,-        newInterruptibleStateActivity,+        newPreemptibleActivity,+        newPreemptibleStateActivity,         -- * Processing         activityNet,         -- * Activity Properties@@ -24,10 +23,13 @@         activityState,         activityTotalUtilisationTime,         activityTotalIdleTime,+        activityTotalPreemptionTime,         activityUtilisationTime,         activityIdleTime,+        activityPreemptionTime,         activityUtilisationFactor,         activityIdleFactor,+        activityPreemptionFactor,         -- * Summary         activitySummary,         -- * Derived Signals for Properties@@ -37,18 +39,25 @@         activityTotalUtilisationTimeChanged_,         activityTotalIdleTimeChanged,         activityTotalIdleTimeChanged_,+        activityTotalPreemptionTimeChanged,+        activityTotalPreemptionTimeChanged_,         activityUtilisationTimeChanged,         activityUtilisationTimeChanged_,         activityIdleTimeChanged,         activityIdleTimeChanged_,+        activityPreemptionTimeChanged,+        activityPreemptionTimeChanged_,         activityUtilisationFactorChanged,         activityUtilisationFactorChanged_,         activityIdleFactorChanged,         activityIdleFactorChanged_,+        activityPreemptionFactorChanged,+        activityPreemptionFactorChanged_,         -- * Basic Signals         activityUtilising,         activityUtilised,-        activityInterrupted,+        activityPreempting,+        activityReentering,         -- * Overall Signal         activityChanged_) where @@ -79,49 +88,45 @@              -- ^ The current state of the activity.              activityProcess :: s -> a -> Process (s, b),              -- ^ Provide @b@ by specified @a@.-             activityProcessInterruptible :: Bool,-             -- ^ Whether the process is interruptible.+             activityProcessPreemptible :: Bool,+             -- ^ Whether the process is preemptible.              activityTotalUtilisationTimeRef :: IORef Double,              -- ^ The counted total time of utilising the activity.              activityTotalIdleTimeRef :: IORef Double,-             -- ^ The counted total time, when the activity was idle.+             -- ^ The counted total time when the activity was idle.+             activityTotalPreemptionTimeRef :: IORef Double,+             -- ^ The counted total time when the activity was preempted.               activityUtilisationTimeRef :: IORef (SamplingStats Double),              -- ^ The statistics for the utilisation time.              activityIdleTimeRef :: IORef (SamplingStats Double),-             -- ^ The statistics for the time, when the activity was idle.+             -- ^ The statistics for the time when the activity was idle.+             activityPreemptionTimeRef :: IORef (SamplingStats Double),+             -- ^ The statistics for the time when the activity was preempted.              activityUtilisingSource :: SignalSource a,              -- ^ A signal raised when starting to utilise the activity.              activityUtilisedSource :: SignalSource (a, b),              -- ^ A signal raised when the activity has been utilised.-             activityInterruptedSource :: SignalSource (ActivityInterruption a)-             -- ^ A signal raised when the utilisation was interrupted.+             activityPreemptingSource :: SignalSource a,+             -- ^ A signal raised when the utilisation was preempted.+             activityReenteringSource :: SignalSource a+             -- ^ A signal raised when the utilisation was proceeded after it had been preempted earlier.            } --- | Contains data about the interrupted task.-data ActivityInterruption a =-  ActivityInterruption { activityInterruptedInput :: a,-                         -- ^ The input task that was interrupted.-                         activityStartProcessingTime :: Double,-                         -- ^ The start time of processing the task.-                         activityInterruptionTime :: Double-                         -- ^ The time of interrupting the task.-                       }- -- | Create a new activity that can provide output @b@ by input @a@. ----- By default, it is assumed that the activity utilisation cannot be interrupted,--- because the handling of possible task interruption is rather costly+-- By default, it is assumed that the activity utilisation cannot be preempted,+-- because the handling of possible task preemption is rather costly -- operation. newActivity :: (a -> Process b)                -- ^ provide an output by the specified input                -> Simulation (Activity () a b)-newActivity = newInterruptibleActivity False+newActivity = newPreemptibleActivity False  -- | Create a new activity that can provide output @b@ by input @a@ -- starting from state @s@. ----- By default, it is assumed that the activity utilisation cannot be interrupted,--- because the handling of possible task interruption is rather costly+-- By default, it is assumed that the activity utilisation cannot be preempted,+-- because the handling of possible task preemption is rather costly -- operation. newStateActivity :: (s -> a -> Process (s, b))                     -- ^ provide a new state and output by the specified @@ -129,49 +134,55 @@                     -> s                     -- ^ the initial state                     -> Simulation (Activity s a b)-newStateActivity = newInterruptibleStateActivity False+newStateActivity = newPreemptibleStateActivity False --- | Create a new interruptible activity that can provide output @b@ by input @a@.-newInterruptibleActivity :: Bool-                            -- ^ whether the activity can be interrupted-                            -> (a -> Process b)-                            -- ^ provide an output by the specified input-                            -> Simulation (Activity () a b)-newInterruptibleActivity interruptible provide =-  flip (newInterruptibleStateActivity interruptible) () $ \s a ->+-- | Create a new preemptible activity that can provide output @b@ by input @a@.+newPreemptibleActivity :: Bool+                          -- ^ whether the activity can be preempted+                          -> (a -> Process b)+                          -- ^ provide an output by the specified input+                          -> Simulation (Activity () a b)+newPreemptibleActivity preemptible provide =+  flip (newPreemptibleStateActivity preemptible) () $ \s a ->   do b <- provide a      return (s, b)  -- | Create a new activity that can provide output @b@ by input @a@ -- starting from state @s@.-newInterruptibleStateActivity :: Bool-                                 -- ^ whether the activity can be interrupted-                                 -> (s -> a -> Process (s, b))-                                 -- ^ provide a new state and output by the specified -                                 -- old state and input-                                 -> s-                                 -- ^ the initial state+newPreemptibleStateActivity :: Bool+                               -- ^ whether the activity can be preempted+                               -> (s -> a -> Process (s, b))+                               -- ^ provide a new state and output by the specified +                               -- old state and input+                               -> s+                               -- ^ the initial state                               -> Simulation (Activity s a b)-newInterruptibleStateActivity interruptible provide state =+newPreemptibleStateActivity preemptible provide state =   do r0 <- liftIO $ newIORef state      r1 <- liftIO $ newIORef 0      r2 <- liftIO $ newIORef 0-     r3 <- liftIO $ newIORef emptySamplingStats+     r3 <- liftIO $ newIORef 0      r4 <- liftIO $ newIORef emptySamplingStats+     r5 <- liftIO $ newIORef emptySamplingStats+     r6 <- liftIO $ newIORef emptySamplingStats      s1 <- newSignalSource      s2 <- newSignalSource      s3 <- newSignalSource+     s4 <- newSignalSource      return Activity { activityInitState = state,                        activityStateRef = r0,                        activityProcess = provide,-                       activityProcessInterruptible = interruptible,+                       activityProcessPreemptible = preemptible,                        activityTotalUtilisationTimeRef = r1,                        activityTotalIdleTimeRef = r2,-                       activityUtilisationTimeRef = r3,-                       activityIdleTimeRef = r4,+                       activityTotalPreemptionTimeRef = r3,+                       activityUtilisationTimeRef = r4,+                       activityIdleTimeRef = r5,+                       activityPreemptionTimeRef = r6,                        activityUtilisingSource = s1,                        activityUtilisedSource = s2,-                       activityInterruptedSource = s3 }+                       activityPreemptingSource = s3,+                       activityReenteringSource = s4 }  -- | Return a network computation for the specified activity. --@@ -201,37 +212,52 @@                        addSamplingStats (t0 - t')               triggerSignal (activityUtilisingSource act) a          -- utilise the activity-         (s', b) <- activityProcess act s a-         (s', b) <- if activityProcessInterruptible act-                    then activityProcessInterrupting act s a-                    else activityProcess act s a+         (s', b, dt) <- if activityProcessPreemptible act+                        then activityProcessPreempting act s a+                        else do (s', b) <- activityProcess act s a+                                return (s', b, 0)          t1 <- liftDynamics time          liftEvent $            do liftIO $                 do writeIORef (activityStateRef act) $! s'-                   modifyIORef' (activityTotalUtilisationTimeRef act) (+ (t1 - t0))+                   modifyIORef' (activityTotalUtilisationTimeRef act) (+ (t1 - t0 - dt))                    modifyIORef' (activityUtilisationTimeRef act) $-                     addSamplingStats (t1 - t0)+                     addSamplingStats (t1 - t0 - dt)               triggerSignal (activityUtilisedSource act) (a, b)          return (b, Net $ loop s' (Just t1)) --- | Process the input with ability to handle a possible interruption.-activityProcessInterrupting :: Activity s a b -> s -> a -> Process (s, b)-activityProcessInterrupting act s a =+-- | Process the input with ability to handle a possible preemption.+activityProcessPreempting :: Activity s a b -> s -> a -> Process (s, b, Double)+activityProcessPreempting act s a =   do pid <- processId      t0  <- liftDynamics time-     finallyProcess-       (activityProcess act s a)-       (liftEvent $-        do cancelled <- processCancelled pid-           when cancelled $-             do t1 <- liftDynamics time-                liftIO $-                  do modifyIORef' (activityTotalUtilisationTimeRef act) (+ (t1 - t0))-                     modifyIORef' (activityUtilisationTimeRef act) $-                       addSamplingStats (t1 - t0)-                let x = ActivityInterruption a t0 t1-                triggerSignal (activityInterruptedSource act) x)+     rs  <- liftIO $ newIORef 0+     r0  <- liftIO $ newIORef t0+     h1  <- liftEvent $+            handleSignal (processPreemptionBeginning pid) $ \() ->+            do t0 <- liftDynamics time+               liftIO $ writeIORef r0 t0+               triggerSignal (activityPreemptingSource act) a+     h2  <- liftEvent $+            handleSignal (processPreemptionEnding pid) $ \() ->+            do t0 <- liftIO $ readIORef r0+               t1 <- liftDynamics time+               let dt = t1 - t0+               liftIO $+                 do modifyIORef' rs (+ dt)+                    modifyIORef' (activityTotalPreemptionTimeRef act) (+ dt)+                    modifyIORef' (activityPreemptionTimeRef act) $+                      addSamplingStats dt+               triggerSignal (activityReenteringSource act) a +     let m1 =+           do (s', b) <- activityProcess act s a+              dt <- liftIO $ readIORef rs+              return (s', b, dt)+         m2 =+           liftEvent $+           do disposeEvent h1+              disposeEvent h2+     finallyProcess m1 m2  -- | Return the current state of the activity. --@@ -290,6 +316,27 @@ activityTotalIdleTimeChanged_ act =   mapSignal (const ()) (activityUtilising act) +-- | Return the counted total time when the activity was preemted waiting for+-- the further proceeding.+--+-- The value returned changes discretely and it is usually delayed relative+-- to the current simulation time.+--+-- See also 'activityTotalPreemptionTimeChanged' and 'activityTotalPreemptionTimeChanged_'.+activityTotalPreemptionTime :: Activity s a b -> Event Double+activityTotalPreemptionTime act =+  Event $ \p -> readIORef (activityTotalPreemptionTimeRef act)+  +-- | Signal when the 'activityTotalPreemptionTime' property value has changed.+activityTotalPreemptionTimeChanged :: Activity s a b -> Signal Double+activityTotalPreemptionTimeChanged act =+  mapSignalM (const $ activityTotalPreemptionTime act) (activityTotalPreemptionTimeChanged_ act)+  +-- | Signal when the 'activityTotalPreemptionTime' property value has changed.+activityTotalPreemptionTimeChanged_ :: Activity s a b -> Signal ()+activityTotalPreemptionTimeChanged_ act =+  mapSignal (const ()) (activityReentering act)+ -- | Return the statistics for the time when the activity was utilised. -- -- The value returned changes discretely and it is usually delayed relative@@ -329,14 +376,35 @@ activityIdleTimeChanged_ :: Activity s a b -> Signal () activityIdleTimeChanged_ act =   mapSignal (const ()) (activityUtilising act)++-- | Return the statistics for the time when the activity was preempted+-- waiting for the further proceeding.+--+-- The value returned changes discretely and it is usually delayed relative+-- to the current simulation time.+--+-- See also 'activityPreemptionTimeChanged' and 'activityPreemptionTimeChanged_'.+activityPreemptionTime :: Activity s a b -> Event (SamplingStats Double)+activityPreemptionTime act =+  Event $ \p -> readIORef (activityPreemptionTimeRef act)   +-- | Signal when the 'activityPreemptionTime' property value has changed.+activityPreemptionTimeChanged :: Activity s a b -> Signal (SamplingStats Double)+activityPreemptionTimeChanged act =+  mapSignalM (const $ activityPreemptionTime act) (activityPreemptionTimeChanged_ act)+  +-- | Signal when the 'activityPreemptionTime' property value has changed.+activityPreemptionTimeChanged_ :: Activity s a b -> Signal ()+activityPreemptionTimeChanged_ act =+  mapSignal (const ()) (activityReentering act)+   -- | It returns the factor changing from 0 to 1, which estimates how often -- the activity was utilised. -- -- This factor is calculated as -- -- @---   totalUtilisationTime \/ (totalUtilisationTime + totalIdleTime)+--   totalUtilisationTime \/ (totalUtilisationTime + totalIdleTime + totalPreemptionTime) -- @ -- -- As before in this module, the value returned changes discretely and@@ -348,7 +416,8 @@   Event $ \p ->   do x1 <- readIORef (activityTotalUtilisationTimeRef act)      x2 <- readIORef (activityTotalIdleTimeRef act)-     return (x1 / (x1 + x2))+     x3 <- readIORef (activityTotalPreemptionTimeRef act)+     return (x1 / (x1 + x2 + x3))    -- | Signal when the 'activityUtilisationFactor' property value has changed. activityUtilisationFactorChanged :: Activity s a b -> Signal Double@@ -359,7 +428,8 @@ activityUtilisationFactorChanged_ :: Activity s a b -> Signal () activityUtilisationFactorChanged_ act =   mapSignal (const ()) (activityUtilising act) <>-  mapSignal (const ()) (activityUtilised act)+  mapSignal (const ()) (activityUtilised act) <>+  mapSignal (const ()) (activityReentering act)    -- | It returns the factor changing from 0 to 1, which estimates how often -- the activity was idle.@@ -367,7 +437,7 @@ -- This factor is calculated as -- -- @---   totalIdleTime \/ (totalUtilisationTime + totalIdleTime)+--   totalIdleTime \/ (totalUtilisationTime + totalIdleTime + totalPreemptionTime) -- @ -- -- As before in this module, the value returned changes discretely and@@ -379,7 +449,8 @@   Event $ \p ->   do x1 <- readIORef (activityTotalUtilisationTimeRef act)      x2 <- readIORef (activityTotalIdleTimeRef act)-     return (x2 / (x1 + x2))+     x3 <- readIORef (activityTotalPreemptionTimeRef act)+     return (x2 / (x1 + x2 + x3))    -- | Signal when the 'activityIdleFactor' property value has changed. activityIdleFactorChanged :: Activity s a b -> Signal Double@@ -390,8 +461,42 @@ activityIdleFactorChanged_ :: Activity s a b -> Signal () activityIdleFactorChanged_ act =   mapSignal (const ()) (activityUtilising act) <>-  mapSignal (const ()) (activityUtilised act)+  mapSignal (const ()) (activityUtilised act) <>+  mapSignal (const ()) (activityReentering act) +-- | It returns the factor changing from 0 to 1, which estimates how often+-- the activity was preempted waiting for the further proceeding.+--+-- This factor is calculated as+--+-- @+--   totalUtilisationTime \/ (totalUtilisationTime + totalIdleTime + totalPreemptionTime)+-- @+--+-- As before in this module, the value returned changes discretely and+-- it is usually delayed relative to the current simulation time.+--+-- See also 'activityPreemptionFactorChanged' and 'activityPreemptionFactorChanged_'.+activityPreemptionFactor :: Activity s a b -> Event Double+activityPreemptionFactor act =+  Event $ \p ->+  do x1 <- readIORef (activityTotalUtilisationTimeRef act)+     x2 <- readIORef (activityTotalIdleTimeRef act)+     x3 <- readIORef (activityTotalPreemptionTimeRef act)+     return (x3 / (x1 + x2 + x3))+  +-- | Signal when the 'activityPreemptionFactor' property value has changed.+activityPreemptionFactorChanged :: Activity s a b -> Signal Double+activityPreemptionFactorChanged act =+  mapSignalM (const $ activityPreemptionFactor act) (activityPreemptionFactorChanged_ act)+  +-- | Signal when the 'activityPreemptionFactor' property value has changed.+activityPreemptionFactorChanged_ :: Activity s a b -> Signal ()+activityPreemptionFactorChanged_ act =+  mapSignal (const ()) (activityUtilising act) <>+  mapSignal (const ()) (activityUtilised act) <>+  mapSignal (const ()) (activityReentering act)+   -- | Raised when starting to utilise the activity after a new input task is received. activityUtilising :: Activity s a b -> Signal a activityUtilising = publishSignal . activityUtilisingSource@@ -400,16 +505,20 @@ activityUtilised :: Activity s a b -> Signal (a, b) activityUtilised = publishSignal . activityUtilisedSource --- | Raised when the task utilisation by the activity was interrupted.-activityInterrupted :: Activity s a b -> Signal (ActivityInterruption a)-activityInterrupted = publishSignal . activityInterruptedSource+-- | Raised when the task utilisation by the activity was preempted.+activityPreempting :: Activity s a b -> Signal a+activityPreempting = publishSignal . activityPreemptingSource +-- | Raised when the task utilisation by the activity was proceeded after it had been preempted earlier.+activityReentering :: Activity s a b -> Signal a+activityReentering = publishSignal . activityReenteringSource+ -- | Signal whenever any property of the activity changes. activityChanged_ :: Activity s a b -> Signal () activityChanged_ act =   mapSignal (const ()) (activityUtilising act) <>   mapSignal (const ()) (activityUtilised act) <>-  mapSignal (const ()) (activityInterrupted act)+  mapSignal (const ()) (activityReentering act)  -- | Return the summary for the activity with desciption of its -- properties using the specified indent.@@ -418,10 +527,13 @@   Event $ \p ->   do tx1 <- readIORef (activityTotalUtilisationTimeRef act)      tx2 <- readIORef (activityTotalIdleTimeRef act)-     let xf1 = tx1 / (tx1 + tx2)-         xf2 = tx2 / (tx1 + tx2)+     tx3 <- readIORef (activityTotalPreemptionTimeRef act)+     let xf1 = tx1 / (tx1 + tx2 + tx3)+         xf2 = tx2 / (tx1 + tx2 + tx3)+         xf3 = tx3 / (tx1 + tx2 + tx3)      xs1 <- readIORef (activityUtilisationTimeRef act)      xs2 <- readIORef (activityIdleTimeRef act)+     xs3 <- readIORef (activityPreemptionTimeRef act)      let tab = replicate indent ' '      return $        showString tab .@@ -431,15 +543,24 @@        showString "total idle time = " . shows tx2 .        showString "\n" .        showString tab .+       showString "total preemption time = " . shows tx3 .+       showString "\n" .+       showString tab .        showString "utilisation factor (from 0 to 1) = " . shows xf1 .        showString "\n" .        showString tab .        showString "idle factor (from 0 to 1) = " . shows xf2 .        showString "\n" .        showString tab .+       showString "preemption factor (from 0 to 1) = " . shows xf3 .+       showString "\n" .+       showString tab .        showString "utilisation time (locked while awaiting the input):\n\n" .        samplingStatsSummary xs1 (2 + indent) .        showString "\n\n" .        showString tab .        showString "idle time:\n\n" .-       samplingStatsSummary xs2 (2 + indent)+       samplingStatsSummary xs2 (2 + indent) .+       showString tab .+       showString "preemption time:\n\n" .+       samplingStatsSummary xs3 (2 + indent)
+ Simulation/Aivika/Activity/Random.hs view
@@ -0,0 +1,230 @@++-- |+-- Module     : Simulation.Aivika.Activity.Random+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines some useful predefined activities that+-- hold the current process for the corresponding random time+-- interval, when processing every input element.+--++module Simulation.Aivika.Activity.Random+       (newRandomUniformActivity,+        newRandomUniformIntActivity,+        newRandomNormalActivity,+        newRandomExponentialActivity,+        newRandomErlangActivity,+        newRandomPoissonActivity,+        newRandomBinomialActivity,+        newPreemptibleRandomUniformActivity,+        newPreemptibleRandomUniformIntActivity,+        newPreemptibleRandomNormalActivity,+        newPreemptibleRandomExponentialActivity,+        newPreemptibleRandomErlangActivity,+        newPreemptibleRandomPoissonActivity,+        newPreemptibleRandomBinomialActivity) where++import Simulation.Aivika.Simulation+import Simulation.Aivika.Process+import Simulation.Aivika.Process.Random+import Simulation.Aivika.Activity++-- | Create a new activity that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomUniformActivity :: Double+                            -- ^ the minimum time interval+                            -> Double+                            -- ^ the maximum time interval+                            -> Simulation (Activity () a a)+newRandomUniformActivity =+  newPreemptibleRandomUniformActivity False++-- | Create a new activity that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomUniformIntActivity :: Int+                               -- ^ the minimum time interval+                               -> Int+                               -- ^ the maximum time interval+                               -> Simulation (Activity () a a)+newRandomUniformIntActivity =+  newPreemptibleRandomUniformIntActivity False++-- | Create a new activity that holds the process for a random time interval+-- distributed normally, when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomNormalActivity :: Double+                           -- ^ the mean time interval+                           -> Double+                           -- ^ the time interval deviation+                           -> Simulation (Activity () a a)+newRandomNormalActivity =+  newPreemptibleRandomNormalActivity False+         +-- | Create a new activity that holds the process for a random time interval+-- distributed exponentially with the specified mean (the reciprocal of the rate),+-- when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomExponentialActivity :: Double+                                -- ^ the mean time interval (the reciprocal of the rate)+                                -> Simulation (Activity () a a)+newRandomExponentialActivity =+  newPreemptibleRandomExponentialActivity False+         +-- | Create a new activity that holds the process for a random time interval+-- having the Erlang distribution with the specified scale (the reciprocal of the rate)+-- and shape parameters, when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomErlangActivity :: Double+                           -- ^ the scale (the reciprocal of the rate)+                           -> Int+                           -- ^ the shape+                           -> Simulation (Activity () a a)+newRandomErlangActivity =+  newPreemptibleRandomErlangActivity False++-- | Create a new activity that holds the process for a random time interval+-- having the Poisson distribution with the specified mean, when processing+-- every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomPoissonActivity :: Double+                            -- ^ the mean time interval+                            -> Simulation (Activity () a a)+newRandomPoissonActivity =+  newPreemptibleRandomPoissonActivity False++-- | Create a new activity that holds the process for a random time interval+-- having the binomial distribution with the specified probability and trials,+-- when processing every input element.+--+-- By default, it is assumed that the activity process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomBinomialActivity :: Double+                             -- ^ the probability+                             -> Int+                             -- ^ the number of trials+                             -> Simulation (Activity () a a)+newRandomBinomialActivity =+  newPreemptibleRandomBinomialActivity False++-- | Create a new activity that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+newPreemptibleRandomUniformActivity :: Bool+                                       -- ^ whether the activity process can be preempted+                                       -> Double+                                       -- ^ the minimum time interval+                                       -> Double+                                       -- ^ the maximum time interval+                                       -> Simulation (Activity () a a)+newPreemptibleRandomUniformActivity preemptible min max =+  newPreemptibleActivity preemptible $ \a ->+  do randomUniformProcess_ min max+     return a++-- | Create a new activity that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+newPreemptibleRandomUniformIntActivity :: Bool+                                          -- ^ whether the activity process can be preempted+                                          -> Int+                                          -- ^ the minimum time interval+                                          -> Int+                                          -- ^ the maximum time interval+                                          -> Simulation (Activity () a a)+newPreemptibleRandomUniformIntActivity preemptible min max =+  newPreemptibleActivity preemptible $ \a ->+  do randomUniformIntProcess_ min max+     return a++-- | Create a new activity that holds the process for a random time interval+-- distributed normally, when processing every input element.+newPreemptibleRandomNormalActivity :: Bool+                                      -- ^ whether the activity process can be preempted+                                      -> Double+                                      -- ^ the mean time interval+                                      -> Double+                                      -- ^ the time interval deviation+                                      -> Simulation (Activity () a a)+newPreemptibleRandomNormalActivity preemptible mu nu =+  newPreemptibleActivity preemptible $ \a ->+  do randomNormalProcess_ mu nu+     return a+         +-- | Create a new activity that holds the process for a random time interval+-- distributed exponentially with the specified mean (the reciprocal of the rate),+-- when processing every input element.+newPreemptibleRandomExponentialActivity :: Bool+                                           -- ^ whether the activity process can be preempted+                                           -> Double+                                           -- ^ the mean time interval (the reciprocal of the rate)+                                           -> Simulation (Activity () a a)+newPreemptibleRandomExponentialActivity preemptible mu =+  newPreemptibleActivity preemptible $ \a ->+  do randomExponentialProcess_ mu+     return a+         +-- | Create a new activity that holds the process for a random time interval+-- having the Erlang distribution with the specified scale (the reciprocal of the rate)+-- and shape parameters, when processing every input element.+newPreemptibleRandomErlangActivity :: Bool+                                      -- ^ whether the activity process can be preempted+                                      -> Double+                                      -- ^ the scale (the reciprocal of the rate)+                                      -> Int+                                      -- ^ the shape+                                      -> Simulation (Activity () a a)+newPreemptibleRandomErlangActivity preemptible beta m =+  newPreemptibleActivity preemptible $ \a ->+  do randomErlangProcess_ beta m+     return a++-- | Create a new activity that holds the process for a random time interval+-- having the Poisson distribution with the specified mean, when processing+-- every input element.+newPreemptibleRandomPoissonActivity :: Bool+                                       -- ^ whether the activity process can be preempted+                                       -> Double+                                       -- ^ the mean time interval+                                       -> Simulation (Activity () a a)+newPreemptibleRandomPoissonActivity preemptible mu =+  newPreemptibleActivity preemptible $ \a ->+  do randomPoissonProcess_ mu+     return a++-- | Create a new activity that holds the process for a random time interval+-- having the binomial distribution with the specified probability and trials,+-- when processing every input element.+newPreemptibleRandomBinomialActivity :: Bool+                                        -- ^ whether the activity process can be preempted+                                        -> Double+                                        -- ^ the probability+                                        -> Int+                                        -- ^ the number of trials+                                        -> Simulation (Activity () a a)+newPreemptibleRandomBinomialActivity preemptible prob trials =+  newPreemptibleActivity preemptible $ \a ->+  do randomBinomialProcess_ prob trials+     return a
Simulation/Aivika/Internal/Cont.hs view
@@ -15,15 +15,24 @@ -- module Simulation.Aivika.Internal.Cont        (ContCancellation(..),-        ContCancellationSource,+        ContId,+        ContEvent(..),         Cont(..),         ContParams,-        newContCancellationSource,+        FrozenCont,+        newContId,+        contSignal,         contCancellationInitiated,         contCancellationInitiate,         contCancellationInitiating,+        contCancellationActivated,         contCancellationBind,         contCancellationConnect,+        contPreemptionBegun,+        contPreemptionBegin,+        contPreemptionBeginning,+        contPreemptionEnd,+        contPreemptionEnding,         invokeCont,         runCont,         rerunCont,@@ -35,8 +44,12 @@         throwCont,         resumeCont,         resumeECont,+        reenterCont,+        freezeCont,+        freezeContReentering,+        unfreezeCont,+        substituteCont,         contCanceled,-        contFreeze,         contAwait,         traceCont) where @@ -69,47 +82,66 @@                       | CancelInIsolation                         -- ^ Cancel the computations in isolation. --- | It manages the cancellation process.-data ContCancellationSource =-  ContCancellationSource { contCancellationInitiatedRef :: IORef Bool,-                           contCancellationActivatedRef :: IORef Bool,-                           contCancellationInitiatingSource :: SignalSource ()-                         }+-- | It identifies the 'Cont' computation.+data ContId =+  ContId { contCancellationInitiatedRef :: IORef Bool,+           contCancellationActivatedRef :: IORef Bool,+           contPreemptionCountRef :: IORef Int,+           contSignalSource :: SignalSource ContEvent+         } --- | Create the cancellation source.-newContCancellationSource :: Simulation ContCancellationSource-newContCancellationSource =+instance Eq ContId where+  x == y = contCancellationInitiatedRef x == contCancellationInitiatedRef y  -- unique references++-- | The event that occurs within the 'Cont' computation.+data ContEvent = ContCancellationInitiating+                 -- ^ Cancel the computation.+               | ContPreemptionBeginning+                 -- ^ Preempt the computation.+               | ContPreemptionEnding+                 -- ^ Proceed with the computation after if was preempted.+               deriving (Eq, Ord, Show)++-- | Create a computation identifier.+newContId :: Simulation ContId+newContId =   Simulation $ \r ->   do r1 <- newIORef False      r2 <- newIORef False+     r3 <- newIORef 0      s  <- invokeSimulation r newSignalSource-     return ContCancellationSource { contCancellationInitiatedRef = r1,-                                     contCancellationActivatedRef = r2,-                                     contCancellationInitiatingSource = s-                                   }+     return ContId { contCancellationInitiatedRef = r1,+                     contCancellationActivatedRef = r2,+                     contPreemptionCountRef = r3,+                     contSignalSource = s+                   } +-- | Signal when the computation state changes.+contSignal :: ContId -> Signal ContEvent+contSignal = publishSignal . contSignalSource+ -- | Signal when the cancellation is intiating.-contCancellationInitiating :: ContCancellationSource -> Signal ()+contCancellationInitiating :: ContId -> Signal () contCancellationInitiating =-  publishSignal . contCancellationInitiatingSource+  filterSignal_ (ContCancellationInitiating ==) . contSignal  -- | Whether the cancellation was initiated.-contCancellationInitiated :: ContCancellationSource -> Event Bool+contCancellationInitiated :: ContId -> Event Bool contCancellationInitiated x =   Event $ \p -> readIORef (contCancellationInitiatedRef x)  -- | Whether the cancellation was activated.-contCancellationActivated :: ContCancellationSource -> IO Bool+contCancellationActivated :: ContId -> IO Bool contCancellationActivated =   readIORef . contCancellationActivatedRef  -- | Deactivate the cancellation.-contCancellationDeactivate :: ContCancellationSource -> IO ()+contCancellationDeactivate :: ContId -> IO () contCancellationDeactivate x =   writeIORef (contCancellationActivatedRef x) False  -- | If the main computation is cancelled then all the nested ones will be cancelled too.-contCancellationBind :: ContCancellationSource -> [ContCancellationSource] -> Event DisposableEvent+contCancellationBind :: ContId -> [ContId] -> Event DisposableEvent contCancellationBind x ys =   Event $ \p ->   do hs1 <- forM ys $ \y ->@@ -123,11 +155,11 @@      return $ mconcat hs1 <> mconcat hs2  -- | Connect the parent computation to the child one.-contCancellationConnect :: ContCancellationSource+contCancellationConnect :: ContId                            -- ^ the parent                            -> ContCancellation                            -- ^ how to connect-                           -> ContCancellationSource+                           -> ContId                            -- ^ the child                            -> Event DisposableEvent                            -- ^ computation of the disposable handler@@ -154,15 +186,59 @@      return $ h1 <> h2  -- | Initiate the cancellation.-contCancellationInitiate :: ContCancellationSource -> Event ()+contCancellationInitiate :: ContId -> Event () contCancellationInitiate x =   Event $ \p ->   do f <- readIORef (contCancellationInitiatedRef x)      unless f $        do writeIORef (contCancellationInitiatedRef x) True           writeIORef (contCancellationActivatedRef x) True-          invokeEvent p $ triggerSignal (contCancellationInitiatingSource x) ()+          invokeEvent p $+            triggerSignal (contSignalSource x) ContCancellationInitiating +-- | Preempt the computation.+contPreemptionBegin :: ContId -> Event ()+contPreemptionBegin x =+  Event $ \p ->+  do f <- readIORef (contCancellationInitiatedRef x)+     unless f $+       do n <- readIORef (contPreemptionCountRef x)+          let n' = n + 1+          n' `seq` writeIORef (contPreemptionCountRef x) n'+          when (n == 0) $+            invokeEvent p $+            triggerSignal (contSignalSource x) ContPreemptionBeginning++-- | Proceed with the computation after it was preempted earlier.+contPreemptionEnd :: ContId -> Event ()+contPreemptionEnd x =+  Event $ \p ->+  do f <- readIORef (contCancellationInitiatedRef x)+     unless f $+       do n <- readIORef (contPreemptionCountRef x)+          let n' = n - 1+          n' `seq` writeIORef (contPreemptionCountRef x) n'+          when (n' == 0) $+            invokeEvent p $+            triggerSignal (contSignalSource x) ContPreemptionEnding++-- | Signal when the computation is preempted.+contPreemptionBeginning :: ContId -> Signal ()+contPreemptionBeginning =+  filterSignal_ (ContPreemptionBeginning ==) . contSignal++-- | Signal when the computation is proceeded after it was preempted before.+contPreemptionEnding :: ContId -> Signal ()+contPreemptionEnding =+  filterSignal_ (ContPreemptionEnding ==) . contSignal++-- | Whether the computation was preemtped.+contPreemptionBegun :: ContId -> Event Bool+contPreemptionBegun x =+  Event $ \p ->+  do n <- readIORef (contPreemptionCountRef x)+     return (n > 0)+ -- | The 'Cont' type is similar to the standard @Cont@ monad  -- and F# async workflow but only the result of applying -- the continuations return the 'Event' computation.@@ -177,7 +253,7 @@ data ContParamsAux =   ContParamsAux { contECont :: SomeException -> Event (),                   contCCont :: () -> Event (),-                  contCancelSource :: ContCancellationSource,+                  contId :: ContId,                   contCancelFlag :: IO Bool,                   contCatchFlag  :: Bool } @@ -216,7 +292,7 @@ cancelCont :: Point -> ContParams a -> IO () {-# NOINLINE cancelCont #-} cancelCont p c =-  do contCancellationDeactivate (contCancelSource $ contAux c)+  do contCancellationDeactivate (contId $ contAux c)      invokeEvent p $ (contCCont $ contAux c) ()  returnC :: a -> Cont a@@ -317,18 +393,18 @@            -- ^ the branch for handing exceptions            -> (() -> Event ())            -- ^ the branch for cancellation-           -> ContCancellationSource-           -- ^ the cancellation source+           -> ContId+           -- ^ the computation identifier            -> Bool            -- ^ whether to support the exception handling from the beginning            -> Event ()-runCont (Cont m) cont econt ccont cancelSource catchFlag = +runCont (Cont m) cont econt ccont cid catchFlag =    m ContParams { contCont = cont,                  contAux  =                     ContParamsAux { contECont = econt,                                    contCCont = ccont,-                                   contCancelSource = cancelSource,-                                   contCancelFlag = contCancellationActivated cancelSource, +                                   contId = cid,+                                   contCancelFlag = contCancellationActivated cid,                                     contCatchFlag  = catchFlag } }  -- | Lift the 'Parameter' computation.@@ -440,10 +516,10 @@ -- Here word @parallel@ literally means that the computations are -- actually executed on a single operating system thread but -- they are processed simultaneously by the event queue.-contParallel :: [(Cont a, ContCancellationSource)]+contParallel :: [(Cont a, ContId)]                 -- ^ the list of:                 -- the nested computation,-                -- the cancellation source+                -- the computation identifier                 -> Cont [a] contParallel xs =   Cont $ \c ->@@ -454,7 +530,7 @@               counter   <- newIORef 0               catchRef  <- newIORef Nothing               hs <- invokeEvent p $-                    contCancellationBind (contCancelSource $ contAux c) $+                    contCancellationBind (contId $ contAux c) $                     map snd xs               let propagate =                     Event $ \p ->@@ -489,9 +565,9 @@                     do modifyIORef counter (+ 1)                        -- the main computation was automatically canceled                        invokeEvent p propagate-              forM_ (zip [1..n] xs) $ \(i, (x, cancelSource)) ->+              forM_ (zip [1..n] xs) $ \(i, (x, cid)) ->                 invokeEvent p $-                runCont x (cont i) econt ccont cancelSource (contCatchFlag $ contAux c)+                runCont x (cont i) econt ccont cid (contCatchFlag $ contAux c)      z <- contCanceled c      if z        then cancelCont p c@@ -502,10 +578,10 @@ -- | A partial case of 'contParallel' when we are not interested in -- the results but we are interested in the actions to be peformed by -- the nested computations.-contParallel_ :: [(Cont a, ContCancellationSource)]+contParallel_ :: [(Cont a, ContId)]                  -- ^ the list of:                  -- the nested computation,-                 -- the cancellation source+                 -- the computation identifier                  -> Cont () contParallel_ xs =   Cont $ \c ->@@ -515,7 +591,7 @@            do counter   <- newIORef 0               catchRef  <- newIORef Nothing               hs <- invokeEvent p $-                    contCancellationBind (contCancelSource $ contAux c) $+                    contCancellationBind (contId $ contAux c) $                     map snd xs               let propagate =                     Event $ \p ->@@ -549,9 +625,9 @@                     do modifyIORef counter (+ 1)                        -- the main computation was automatically canceled                        invokeEvent p propagate-              forM_ (zip [1..n] xs) $ \(i, (x, cancelSource)) ->+              forM_ (zip [1..n] xs) $ \(i, (x, cid)) ->                 invokeEvent p $-                runCont x (cont i) econt ccont cancelSource (contCatchFlag $ contAux c)+                runCont x (cont i) econt ccont cid (contCatchFlag $ contAux c)      z <- contCanceled c      if z        then cancelCont p c@@ -559,14 +635,14 @@             then invokeEvent p $ contCont c ()             else worker --- | Rerun the 'Cont' computation with the specified cancellation source.-rerunCont :: Cont a -> ContCancellationSource -> Cont a-rerunCont x cancelSource =+-- | Rerun the 'Cont' computation with the specified identifier.+rerunCont :: Cont a -> ContId -> Cont a+rerunCont x cid =   Cont $ \c ->   Event $ \p ->   do let worker =            do hs <- invokeEvent p $-                    contCancellationBind (contCancelSource $ contAux c) [cancelSource]+                    contCancellationBind (contId $ contAux c) [cid]               let cont a  =                     Event $ \p ->                     do invokeEvent p $ disposeEvent hs  -- unbind the cancellation source@@ -580,21 +656,21 @@                     do invokeEvent p $ disposeEvent hs  -- unbind the cancellation source                        cancelCont p c               invokeEvent p $-                runCont x cont econt ccont cancelSource (contCatchFlag $ contAux c)+                runCont x cont econt ccont cid (contCatchFlag $ contAux c)      z <- contCanceled c      if z        then cancelCont p c        else worker --- | Run the 'Cont' computation in parallel but connect the cancellation sources.-spawnCont :: ContCancellation -> Cont () -> ContCancellationSource -> Cont ()-spawnCont cancellation x cancelSource =+-- | Run the 'Cont' computation in parallel but connect the computations.+spawnCont :: ContCancellation -> Cont () -> ContId -> Cont ()+spawnCont cancellation x cid =   Cont $ \c ->   Event $ \p ->   do let worker =            do hs <- invokeEvent p $                     contCancellationConnect-                    (contCancelSource $ contAux c) cancellation cancelSource+                    (contId $ contAux c) cancellation cid               let cont a  =                     Event $ \p ->                     do invokeEvent p $ disposeEvent hs  -- unbind the cancellation source@@ -609,7 +685,7 @@                        -- do nothing and it will finish the computation               invokeEvent p $                 enqueueEvent (pointTime p) $-                runCont x cont econt ccont cancelSource False+                runCont x cont econt ccont cid False               invokeEvent p $                 resumeCont c ()      z <- contCanceled c@@ -617,21 +693,26 @@        then cancelCont p c        else worker +-- | Represents a temporarily frozen computation.+newtype FrozenCont a =+  FrozenCont { unfreezeCont :: Event (Maybe (ContParams a))+               -- ^ Unfreeze the computation.+             }+ -- | Freeze the computation parameters temporarily.-contFreeze :: ContParams a -> Event (Event (Maybe (ContParams a)))-contFreeze c =+freezeCont :: ContParams a -> Event (FrozenCont a)+freezeCont c =   Event $ \p ->   do rh <- newIORef Nothing      rc <- newIORef $ Just c      h <- invokeEvent p $           handleSignal (contCancellationInitiating $-                        contCancelSource $-                        contAux c) $ \a ->+                        contId $ contAux c) $ \e ->           Event $ \p ->           do h <- readIORef rh              case h of                Nothing ->-                 error "The handler was lost: contFreeze."+                 error "The handler was lost: freezeCont."                Just h ->                  do invokeEvent p $ disposeEvent h                     c <- readIORef rc@@ -646,18 +727,115 @@                                 when z $ cancelCont p c      writeIORef rh (Just h)      return $+       FrozenCont $        Event $ \p ->        do invokeEvent p $ disposeEvent h           c <- readIORef rc           writeIORef rc Nothing           return c-     ++-- | Freeze the computation parameters specifying what should be done when reentering the computation.+freezeContReentering :: ContParams a -> a -> Event () -> Event (FrozenCont a)+freezeContReentering c a m =+  Event $ \p ->+  do rh <- newIORef Nothing+     rc <- newIORef $ Just c+     h <- invokeEvent p $+          handleSignal (contCancellationInitiating $+                        contId $ contAux c) $ \e ->+          Event $ \p ->+          do h <- readIORef rh+             case h of+               Nothing ->+                 error "The handler was lost: freezeContReentering."+               Just h ->+                 do invokeEvent p $ disposeEvent h+                    c <- readIORef rc+                    case c of+                      Nothing -> return ()+                      Just c  ->+                        do writeIORef rc Nothing+                           invokeEvent p $+                             enqueueEvent (pointTime p) $+                             Event $ \p ->+                             do z <- contCanceled c+                                when z $ cancelCont p c+     writeIORef rh (Just h)+     return $+       FrozenCont $+       Event $ \p ->+       do invokeEvent p $ disposeEvent h+          c <- readIORef rc+          writeIORef rc Nothing+          case c of+            Nothing -> return Nothing+            z @ (Just c) ->+              do f <- invokeEvent p $+                      contPreemptionBegun $+                      contId $ contAux c+                 if not f+                   then return z+                   else do let c = c { contCont = \a -> m }+                           invokeEvent p $ sleepCont c a+                           return Nothing++-- | Reenter the computation parameters when needed.+reenterCont :: ContParams a -> a -> Event ()+{-# INLINE reenterCont #-}+reenterCont c a =+  Event $ \p ->+  do f <- invokeEvent p $+          contPreemptionBegun $+          contId $ contAux c+     if not f+       then invokeEvent p $+            enqueueEvent (pointTime p) $+            resumeCont c a+       else invokeEvent p $+            sleepCont c a++-- | Sleep until the preempted computation will be reentered.+sleepCont :: ContParams a -> a -> Event ()+{-# NOINLINE sleepCont #-}+sleepCont c a =+  Event $ \p ->+  do rh <- newIORef Nothing+     h  <- invokeEvent p $+           handleSignal (contSignal $+                         contId $ contAux c) $ \e ->+           Event $ \p ->+           do h <- readIORef rh+              case h of+                Nothing ->+                  error "The handler was lost: sleepCont."+                Just h ->+                  do invokeEvent p $ disposeEvent h+                     case e of+                       ContCancellationInitiating ->+                         invokeEvent p $+                         enqueueEvent (pointTime p) $+                         Event $ \p ->+                         do z <- contCanceled c+                            when z $ cancelCont p c+                       ContPreemptionEnding ->+                         invokeEvent p $+                         enqueueEvent (pointTime p) $+                         resumeCont c a+                       ContPreemptionBeginning ->+                         error "The computation was already preempted: sleepCont."+     writeIORef rh (Just h)++-- | Substitute the continuation.+substituteCont :: ContParams a -> (a -> Event ()) -> ContParams a+{-# INLINE substituteCont #-}+substituteCont c m = c { contCont = m }+ -- | Await the signal. contAwait :: Signal a -> Cont a contAwait signal =   Cont $ \c ->   Event $ \p ->-  do c <- invokeEvent p $ contFreeze c+  do c <- invokeEvent p $ freezeCont c      r <- newIORef Nothing      h <- invokeEvent p $           handleSignal signal $ @@ -668,11 +846,11 @@                              error "The signal was lost: contAwait."                            Just x ->                              do invokeEvent p $ disposeEvent x-                                c <- invokeEvent p c+                                c <- invokeEvent p $ unfreezeCont c                                 case c of                                   Nothing -> return ()                                   Just c  ->-                                    invokeEvent p $ resumeCont c a+                                    invokeEvent p $ reenterCont c a      writeIORef r $ Just h            -- | Show the debug message with the current simulation time.
Simulation/Aivika/Internal/Process.hs view
@@ -61,6 +61,11 @@         whenCancellingProcess,         -- * Awaiting Signal         processAwait,+        -- * Preemption+        processPreemptionBegin,+        processPreemptionEnd,+        processPreemptionBeginning,+        processPreemptionEnding,         -- * Yield of Process         processYield,         -- * Process Timeout@@ -106,9 +111,10 @@ data ProcessId =    ProcessId { processStarted :: IORef Bool,               processReactCont     :: IORef (Maybe (ContParams ())), -              processCancelSource  :: ContCancellationSource,+              processContId  :: ContId,               processInterruptRef  :: IORef Bool, -              processInterruptCont :: IORef (Maybe (ContParams ())), +              processInterruptCont :: IORef (Maybe (ContParams ())),+              processInterruptTime :: IORef Double,               processInterruptVersion :: IORef Int }  -- | Specifies a discontinuous process that can suspend at any time@@ -138,11 +144,13 @@   do when (dt < 0) $        error "Time period dt < 0: holdProcess"      let x = processInterruptCont pid+         t = pointTime p + dt      writeIORef x $ Just c      writeIORef (processInterruptRef pid) False+     writeIORef (processInterruptTime pid) t      v <- readIORef (processInterruptVersion pid)      invokeEvent p $-       enqueueEvent (pointTime p + dt) $+       enqueueEvent t $        Event $ \p ->        do v' <- readIORef (processInterruptVersion pid)           when (v == v') $ @@ -170,6 +178,37 @@   Event $ \p ->   readIORef (processInterruptRef pid) +-- | Define a reaction when the process with the specified identifier is preempted.+processPreempted :: ProcessId -> Event ()+processPreempted pid =+  Event $ \p ->+  do let x = processInterruptCont pid+     a <- readIORef x+     case a of+       Just c ->+         do writeIORef x Nothing+            writeIORef (processInterruptRef pid) True+            modifyIORef (processInterruptVersion pid) $ (+) 1+            t <- readIORef (processInterruptTime pid)+            let dt = t - pointTime p+                c' = substituteCont c $ \a ->+                  Event $ \p ->+                  invokeEvent p $+                  invokeCont c $+                  invokeProcess pid $+                  holdProcess dt+            invokeEvent p $+              reenterCont c' ()+       Nothing ->+         do let x = processReactCont pid+            a <- readIORef x+            case a of+              Nothing ->+                return ()+              Just c ->+                do let c' = substituteCont c $ reenterCont c+                   writeIORef x $ Just c'+ -- | Passivate the process. passivateProcess :: Process () passivateProcess =@@ -213,11 +252,20 @@             "Another process with the specified identifier " ++             "has been started already: processIdPrepare"        else writeIORef (processStarted pid) True-     let signal = processCancelling pid+     let signal = contSignal $ processContId pid      invokeEvent p $-       handleSignal_ signal $ \_ ->-       do interruptProcess pid-          reactivateProcess pid+       handleSignal_ signal $ \e ->+       Event $ \p ->+       case e of+         ContCancellationInitiating ->+           do z <- contCancellationActivated $ processContId pid+              when z $+                do invokeEvent p $ interruptProcess pid+                   invokeEvent p $ reactivateProcess pid+         ContPreemptionBeginning ->+           invokeEvent p $ processPreempted pid+         ContPreemptionEnding ->+           return ()  -- | Run immediately the process. A new 'ProcessId' identifier will be -- assigned to the process.@@ -238,7 +286,7 @@ runProcessUsingId :: ProcessId -> Process () -> Event () runProcessUsingId pid p =   do processIdPrepare pid-     runCont m cont econt ccont (processCancelSource pid) False+     runCont m cont econt ccont (processContId pid) False        where cont  = return              econt = throwEvent              ccont = return@@ -288,20 +336,22 @@ newProcessId =   do x <- liftIO $ newIORef Nothing      y <- liftIO $ newIORef False-     c <- newContCancellationSource+     c <- newContId      i <- liftIO $ newIORef False      z <- liftIO $ newIORef Nothing+     t <- liftIO $ newIORef 0      v <- liftIO $ newIORef 0      return ProcessId { processStarted = y,                         processReactCont     = x, -                        processCancelSource  = c, +                        processContId  = c,                          processInterruptRef  = i,-                        processInterruptCont = z, +                        processInterruptCont = z,+                        processInterruptTime = t,                         processInterruptVersion = v }  -- | Cancel a process with the specified identifier, interrupting it if needed. cancelProcessWithId :: ProcessId -> Event ()-cancelProcessWithId pid = contCancellationInitiate (processCancelSource pid)+cancelProcessWithId pid = contCancellationInitiate (processContId pid)  -- | The process cancels itself. cancelProcess :: Process a@@ -313,12 +363,12 @@  -- | Test whether the process with the specified identifier was cancelled. processCancelled :: ProcessId -> Event Bool-processCancelled pid = contCancellationInitiated (processCancelSource pid)+processCancelled pid = contCancellationInitiated (processContId pid)  -- | Return a signal that notifies about cancelling the process with  -- the specified identifier. processCancelling :: ProcessId -> Signal ()-processCancelling pid = contCancellationInitiating (processCancelSource pid)+processCancelling pid = contCancellationInitiating (processContId pid)  -- | Register a handler that will be invoked in case of cancelling the current process. whenCancellingProcess :: Event () -> Process ()@@ -327,6 +377,22 @@   liftEvent $   handleSignal_ (processCancelling pid) $ \() -> h +-- | Preempt a process with the specified identifier.+processPreemptionBegin :: ProcessId -> Event ()+processPreemptionBegin pid = contPreemptionBegin (processContId pid)++-- | Proceed with the process with the specified identifier after it was preempted with help of 'preemptProcessBegin'.+processPreemptionEnd :: ProcessId -> Event ()+processPreemptionEnd pid = contPreemptionEnd (processContId pid)++-- | Return a signal when the process is preempted.+processPreemptionBeginning :: ProcessId -> Signal ()+processPreemptionBeginning pid = contPreemptionBeginning (processContId pid)++-- | Return a signal when the process is proceeded after it was preempted earlier.+processPreemptionEnding :: ProcessId -> Signal ()+processPreemptionEnding pid = contPreemptionEnding (processContId pid)+ instance Eq ProcessId where   x == y = processReactCont x == processReactCont y    -- for the references are unique @@ -435,7 +501,7 @@   do liftEvent $ processParallelPrepare xs      contParallel $        flip map xs $ \(pid, m) ->-       (invokeProcess pid m, processCancelSource pid)+       (invokeProcess pid m, processContId pid)  -- | Like 'processParallel' but ignores the result. processParallel_ :: [Process a] -> Process ()@@ -449,7 +515,7 @@   do liftEvent $ processParallelPrepare xs      contParallel_ $        flip map xs $ \(pid, m) ->-       (invokeProcess pid m, processCancelSource pid)+       (invokeProcess pid m, processContId pid)  -- | Create the new process identifiers. processParallelCreateIds :: [Process a] -> Simulation [(ProcessId, Process a)]@@ -475,7 +541,7 @@ processUsingId pid x =   Process $ \pid' ->   do liftEvent $ processIdPrepare pid-     rerunCont (invokeProcess pid x) (processCancelSource pid)+     rerunCont (invokeProcess pid x) (processContId pid)  -- | Spawn the child process. In case of cancelling one of the processes, -- other process will be cancelled too.@@ -501,7 +567,7 @@ spawnProcessUsingIdWith cancellation pid x =   Process $ \pid' ->   do liftEvent $ processIdPrepare pid-     spawnCont cancellation (invokeProcess pid x) (processCancelSource pid)+     spawnCont cancellation (invokeProcess pid x) (processContId pid)  -- | Await the signal. processAwait :: Signal a -> Process a
Simulation/Aivika/Net.hs view
@@ -34,6 +34,7 @@         emptyNet,         arrNet,         accumNet,+        withinNet,         -- * Specifying Identifier         netUsingId,         -- * Arrival Net@@ -168,7 +169,13 @@ accumNet f acc =   Net $ \a ->   do (acc', b) <- f acc a-     return (b, accumNet f acc') +     return (b, accumNet f acc')++-- | Involve the computation with side effect when processing the input.+withinNet :: Process () -> Net a a+withinNet m =+  Net $ \a ->+  do { m; return (a, withinNet m) }  -- | Create a net that will use the specified process identifier. -- It can be useful to refer to the underlying 'Process' computation which
+ Simulation/Aivika/Net/Random.hs view
@@ -0,0 +1,103 @@++-- |+-- Module     : Simulation.Aivika.Net.Random+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines some useful random network computations that+-- hold the current process for the corresponding time interval,+-- when processing every input element.+--++module Simulation.Aivika.Net.Random+       (randomUniformNet,+        randomUniformIntNet,+        randomNormalNet,+        randomExponentialNet,+        randomErlangNet,+        randomPoissonNet,+        randomBinomialNet) where++import Simulation.Aivika.Process+import Simulation.Aivika.Process.Random+import Simulation.Aivika.Net++-- | When processing every input element, hold the process+-- for a random time interval distributed uniformly.+randomUniformNet :: Double+                    -- ^ the minimum time interval+                    -> Double+                    -- ^ the maximum time interval+                    -> Net a a+randomUniformNet min max =+  withinNet $+  randomUniformProcess_ min max++-- | When processing every input element, hold the process+-- for a random time interval distributed uniformly.+randomUniformIntNet :: Int+                       -- ^ the minimum time interval+                       -> Int+                       -- ^ the maximum time interval+                       -> Net a a+randomUniformIntNet min max =+  withinNet $+  randomUniformIntProcess_ min max++-- | When processing every input element, hold the process+-- for a random time interval distributed normally.+randomNormalNet :: Double+                   -- ^ the mean time interval+                   -> Double+                   -- ^ the time interval deviation+                   -> Net a a+randomNormalNet mu nu =+  withinNet $+  randomNormalProcess_ mu nu+         +-- | When processing every input element, hold the process+-- for a random time interval distributed exponentially+-- with the specified mean (the reciprocal of the rate).+randomExponentialNet :: Double+                        -- ^ the mean time interval (the reciprocal of the rate)+                        -> Net a a+randomExponentialNet mu =+  withinNet $+  randomExponentialProcess_ mu+         +-- | When processing every input element, hold the process+-- for a random time interval having the Erlang distribution with+-- the specified scale (the reciprocal of the rate) and shape parameters.+randomErlangNet :: Double+                   -- ^ the scale (the reciprocal of the rate)+                   -> Int+                   -- ^ the shape+                   -> Net a a+randomErlangNet beta m =+  withinNet $+  randomErlangProcess_ beta m++-- | When processing every input element, hold the process+-- for a random time interval having the Poisson distribution+-- with the specified mean.+randomPoissonNet :: Double+                    -- ^ the mean time interval+                    -> Net a a+randomPoissonNet mu =+  withinNet $+  randomPoissonProcess_ mu++-- | When processing every input element, hold the process+-- for a random time interval having the binomial distribution+-- with the specified probability and trials.+randomBinomialNet :: Double+                     -- ^ the probability+                     -> Int+                     -- ^ the number of trials+                     -> Net a a+randomBinomialNet prob trials =+  withinNet $+  randomBinomialProcess_ prob trials
Simulation/Aivika/PriorityQueue.hs view
@@ -16,7 +16,9 @@         newQueue,          enqueue,          dequeue, -        queueFront) where +        queueFront,+        remove,+        removeBy) where   import Data.Array import Data.Array.MArray.Safe@@ -149,7 +151,8 @@      -- v0 <- readArray vals size      writeArray keys i k0      writeArray vals i v0-     siftDown keys vals i 0 k v+     when (i > 0) $+       siftDown keys vals i 0 k v  -- | Return the element with the minimal priority. queueFront :: PriorityQueue a -> IO (Double, a)@@ -161,3 +164,50 @@      k <- readArray keys 0      v <- readArray vals 0      return (k, v)++-- | Remove the specified element from the queue and return a computation of the flag+-- indicating whether the element was actually removed.+--+-- Note that unlike other functions it has complexity O(n).+remove :: Eq a => PriorityQueue a -> a -> IO Bool+remove pq a = removeBy pq (== a)++-- | Remove an element satisfying the predicate and return a computation of the flag+-- indicating whether the element was actually removed.+--+-- Note that unlike other functions it has complexity O(n).+removeBy :: PriorityQueue a -> (a -> Bool) -> IO Bool+removeBy pq pred =+  do index <- indexBy pq pred+     if index < 0+       then return False+       else do size <- readIORef (pqSize pq)+               when (size == 0) $+                 error "Internal error in the priority queue implementation: removeBy"+               let i = size - 1+               writeIORef (pqSize pq) i+               keys <- readIORef (pqKeys pq)+               vals <- readIORef (pqVals pq)+               k <- readArray keys i+               v <- readArray vals i+               let k0 = 0.0+                   v0 = undefined+               writeArray keys i k0+               writeArray vals i v0+               when (i > 0) $+                 siftDown keys vals i index k v+               return True+     +-- | Return the index of the item satisfying the predicate or -1.     +indexBy :: PriorityQueue a -> (a -> Bool) -> IO Int+indexBy pq pred =+  do size <- readIORef (pqSize pq)+     vals <- readIORef (pqVals pq)+     let loop index =+           if index >= size+           then return (-1)+           else do x <- readArray vals index+                   if pred x+                     then return index+                     else loop $ index + 1+     loop 0
Simulation/Aivika/Process.hs view
@@ -58,6 +58,9 @@         whenCancellingProcess,         -- * Awaiting Signal         processAwait,+        -- * Preemption+        processPreemptionBeginning,+        processPreemptionEnding,         -- * Yield of Process         processYield,         -- * Process Timeout
+ Simulation/Aivika/Process/Random.hs view
@@ -0,0 +1,199 @@++-- |+-- Module     : Simulation.Aivika.Process.Random+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines helper functions, which are useful to hold +-- the 'Process' computation for a time interval according to some+-- random distribution.+--++module Simulation.Aivika.Process.Random+       (randomUniformProcess,+        randomUniformProcess_,+        randomUniformIntProcess,+        randomUniformIntProcess_,+        randomNormalProcess,+        randomNormalProcess_,+        randomExponentialProcess,+        randomExponentialProcess_,+        randomErlangProcess,+        randomErlangProcess_,+        randomPoissonProcess,+        randomPoissonProcess_,+        randomBinomialProcess,+        randomBinomialProcess_) where++import Control.Monad+import Control.Monad.Trans++import Simulation.Aivika.Parameter+import Simulation.Aivika.Parameter.Random+import Simulation.Aivika.Process++-- | Hold the process for a random time interval distributed uniformly.+randomUniformProcess :: Double+                        -- ^ the minimum time interval+                        -> Double+                        -- ^ the maximum time interval+                        -> Process Double+                        -- ^ a computation of the time interval+                        -- for which the process was actually held+randomUniformProcess min max =+  do t <- liftParameter $ randomUniform min max+     holdProcess t+     return t++-- | Hold the process for a random time interval distributed uniformly.+randomUniformProcess_ :: Double+                         -- ^ the minimum time interval+                         -> Double+                         -- ^ the maximum time interval+                         -> Process ()+randomUniformProcess_ min max =+  do t <- liftParameter $ randomUniform min max+     holdProcess t++-- | Hold the process for a random time interval distributed uniformly.+randomUniformIntProcess :: Int+                           -- ^ the minimum time interval+                           -> Int+                           -- ^ the maximum time interval+                           -> Process Int+                           -- ^ a computation of the time interval+                           -- for which the process was actually held+randomUniformIntProcess min max =+  do t <- liftParameter $ randomUniformInt min max+     holdProcess $ fromIntegral t+     return t++-- | Hold the process for a random time interval distributed uniformly.+randomUniformIntProcess_ :: Int+                            -- ^ the minimum time interval+                            -> Int+                            -- ^ the maximum time interval+                            -> Process ()+randomUniformIntProcess_ min max =+  do t <- liftParameter $ randomUniformInt min max+     holdProcess $ fromIntegral t++-- | Hold the process for a random time interval distributed normally.+randomNormalProcess :: Double+                       -- ^ the mean time interval+                       -> Double+                       -- ^ the time interval deviation+                       -> Process Double+                       -- ^ a computation of the time interval+                       -- for which the process was actually held+randomNormalProcess mu nu =+  do t <- liftParameter $ randomNormal mu nu+     when (t > 0) $+       holdProcess t+     return t+         +-- | Hold the process for a random time interval distributed normally.+randomNormalProcess_ :: Double+                        -- ^ the mean time interval+                        -> Double+                        -- ^ the time interval deviation+                        -> Process ()+randomNormalProcess_ mu nu =+  do t <- liftParameter $ randomNormal mu nu+     when (t > 0) $+       holdProcess t+         +-- | Hold the process for a random time interval distributed exponentially+-- with the specified mean (the reciprocal of the rate).+randomExponentialProcess :: Double+                            -- ^ the mean time interval (the reciprocal of the rate)+                            -> Process Double+                            -- ^ a computation of the time interval+                            -- for which the process was actually held+randomExponentialProcess mu =+  do t <- liftParameter $ randomExponential mu+     holdProcess t+     return t+         +-- | Hold the process for a random time interval distributed exponentially+-- with the specified mean (the reciprocal of the rate).+randomExponentialProcess_ :: Double+                             -- ^ the mean time interval (the reciprocal of the rate)+                             -> Process ()+randomExponentialProcess_ mu =+  do t <- liftParameter $ randomExponential mu+     holdProcess t+         +-- | Hold the process for a random time interval having the Erlang distribution with+-- the specified scale (the reciprocal of the rate) and shape parameters.+randomErlangProcess :: Double+                       -- ^ the scale (the reciprocal of the rate)+                       -> Int+                       -- ^ the shape+                       -> Process Double+                       -- ^ a computation of the time interval+                       -- for which the process was actually held+randomErlangProcess beta m =+  do t <- liftParameter $ randomErlang beta m+     holdProcess t+     return t++-- | Hold the process for a random time interval having the Erlang distribution with+-- the specified scale (the reciprocal of the rate) and shape parameters.+randomErlangProcess_ :: Double+                        -- ^ the scale (the reciprocal of the rate)+                        -> Int+                        -- ^ the shape+                        -> Process ()+randomErlangProcess_ beta m =+  do t <- liftParameter $ randomErlang beta m+     holdProcess t++-- | Hold the process for a random time interval having the Poisson distribution with+-- the specified mean.+randomPoissonProcess :: Double+                        -- ^ the mean time interval+                        -> Process Int+                        -- ^ a computation of the time interval+                        -- for which the process was actually held+randomPoissonProcess mu =+  do t <- liftParameter $ randomPoisson mu+     holdProcess $ fromIntegral t+     return t++-- | Hold the process for a random time interval having the Poisson distribution with+-- the specified mean.+randomPoissonProcess_ :: Double+                         -- ^ the mean time interval+                         -> Process ()+randomPoissonProcess_ mu =+  do t <- liftParameter $ randomPoisson mu+     holdProcess $ fromIntegral t++-- | Hold the process for a random time interval having the binomial distribution+-- with the specified probability and trials.+randomBinomialProcess :: Double+                         -- ^ the probability+                         -> Int+                         -- ^ the number of trials+                         -> Process Int+                         -- ^ a computation of the time interval+                         -- for which the process was actually held+randomBinomialProcess prob trials =+  do t <- liftParameter $ randomBinomial prob trials+     holdProcess $ fromIntegral t+     return t++-- | Hold the process for a random time interval having the binomial distribution+-- with the specified probability and trials.+randomBinomialProcess_ :: Double+                         -- ^ the probability+                         -> Int+                         -- ^ the number of trials+                         -> Process ()+randomBinomialProcess_ prob trials =+  do t <- liftParameter $ randomBinomial prob trials+     holdProcess $ fromIntegral t
Simulation/Aivika/Processor.hs view
@@ -16,6 +16,7 @@         emptyProcessor,         arrProcessor,         accumProcessor,+        withinProcessor,         -- * Specifying Identifier         processorUsingId,         -- * Prefetch and Delay Processors@@ -146,6 +147,13 @@       do (a, xs') <- runStream xs          (acc', b) <- f acc a          return (b, Cons $ loop xs' acc') ++-- | Involve the computation with side effect when processing a stream of data.+withinProcessor :: Process () -> Processor a a+withinProcessor m =+  Processor $+  mapStreamM $ \a ->+  do { m; return a }  -- | Create a processor that will use the specified process identifier. -- It can be useful to refer to the underlying 'Process' computation which
+ Simulation/Aivika/Processor/Random.hs view
@@ -0,0 +1,103 @@++-- |+-- Module     : Simulation.Aivika.Processor.Random+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines some useful random processors that+-- hold the current process for the corresponding time interval,+-- when processing every input element.+--++module Simulation.Aivika.Processor.Random+       (randomUniformProcessor,+        randomUniformIntProcessor,+        randomNormalProcessor,+        randomExponentialProcessor,+        randomErlangProcessor,+        randomPoissonProcessor,+        randomBinomialProcessor) where++import Simulation.Aivika.Process+import Simulation.Aivika.Process.Random+import Simulation.Aivika.Processor++-- | When processing every input element, hold the process+-- for a random time interval distributed uniformly.+randomUniformProcessor :: Double+                          -- ^ the minimum time interval+                          -> Double+                          -- ^ the maximum time interval+                          -> Processor a a+randomUniformProcessor min max =+  withinProcessor $+  randomUniformProcess_ min max++-- | When processing every input element, hold the process+-- for a random time interval distributed uniformly.+randomUniformIntProcessor :: Int+                             -- ^ the minimum time interval+                             -> Int+                             -- ^ the maximum time interval+                             -> Processor a a+randomUniformIntProcessor min max =+  withinProcessor $+  randomUniformIntProcess_ min max++-- | When processing every input element, hold the process+-- for a random time interval distributed normally.+randomNormalProcessor :: Double+                         -- ^ the mean time interval+                         -> Double+                         -- ^ the time interval deviation+                         -> Processor a a+randomNormalProcessor mu nu =+  withinProcessor $+  randomNormalProcess_ mu nu+         +-- | When processing every input element, hold the process+-- for a random time interval distributed exponentially+-- with the specified mean (the reciprocal of the rate).+randomExponentialProcessor :: Double+                              -- ^ the mean time interval (the reciprocal of the rate)+                              -> Processor a a+randomExponentialProcessor mu =+  withinProcessor $+  randomExponentialProcess_ mu+         +-- | When processing every input element, hold the process+-- for a random time interval having the Erlang distribution with+-- the specified scale (the reciprocal of the rate) and shape parameters.+randomErlangProcessor :: Double+                         -- ^ the scale (the reciprocal of the rate)+                         -> Int+                         -- ^ the shape+                         -> Processor a a+randomErlangProcessor beta m =+  withinProcessor $+  randomErlangProcess_ beta m++-- | When processing every input element, hold the process+-- for a random time interval having the Poisson distribution+-- with the specified mean.+randomPoissonProcessor :: Double+                          -- ^ the mean time interval+                          -> Processor a a+randomPoissonProcessor mu =+  withinProcessor $+  randomPoissonProcess_ mu++-- | When processing every input element, hold the process+-- for a random time interval having the binomial distribution+-- with the specified probability and trials.+randomBinomialProcessor :: Double+                           -- ^ the probability+                           -> Int+                           -- ^ the number of trials+                           -> Processor a a+randomBinomialProcessor prob trials =+  withinProcessor $+  randomBinomialProcess_ prob trials
Simulation/Aivika/Resource.hs view
@@ -42,7 +42,9 @@         releaseResource,         releaseResourceWithinEvent,         usingResource,-        usingResourceWithPriority) where+        usingResourceWithPriority,+        -- * Altering Resource+        incResourceCount) where  import Data.IORef import Control.Monad@@ -80,7 +82,7 @@              -- ^ Return the maximum count of the resource, where 'Nothing'              -- means that the resource has no upper bound.              resourceCountRef :: IORef Int, -             resourceWaitList :: StrategyQueue s (Event (Maybe (ContParams ()))) }+             resourceWaitList :: StrategyQueue s (FrozenCont ()) }  instance Eq (Resource s) where   x == y = resourceCountRef x == resourceCountRef y  -- unique references@@ -218,7 +220,11 @@   Event $ \p ->   do a <- readIORef (resourceCountRef r)      if a == 0 -       then do c <- invokeEvent p $ contFreeze c+       then do c <- invokeEvent p $+                    freezeContReentering c () $+                    invokeCont c $+                    invokeProcess pid $+                    requestResource r                invokeEvent p $                  strategyEnqueue (resourceWaitList r) c        else do let a' = a - 1@@ -240,7 +246,11 @@   Event $ \p ->   do a <- readIORef (resourceCountRef r)      if a == 0 -       then do c <- invokeEvent p $ contFreeze c+       then do c <- invokeEvent p $+                    freezeContReentering c () $+                    invokeCont c $+                    invokeProcess pid $+                    requestResourceWithPriority r priority                invokeEvent p $                  strategyEnqueueWithPriority (resourceWaitList r) priority c        else do let a' = a - 1@@ -283,7 +293,7 @@        then a' `seq` writeIORef (resourceCountRef r) a'        else do c <- invokeEvent p $                     strategyDequeue (resourceWaitList r)-               c <- invokeEvent p c+               c <- invokeEvent p $ unfreezeCont c                case c of                  Nothing ->                    invokeEvent p $ releaseResourceWithinEvent r@@ -333,3 +343,19 @@ usingResourceWithPriority r priority m =   do requestResourceWithPriority r priority      finallyProcess m $ releaseResource r++-- | Increase the count of available resource by the specified number,+-- invoking the awaiting processes as needed.+incResourceCount :: DequeueStrategy s+                    => Resource s+                    -- ^ the resource+                    -> Int+                    -- ^ the increment for the resource count+                    -> Event ()+incResourceCount r n+  | n < 0     = error "The increment cannot be negative: incResourceCount"+  | n == 0    = return ()+  | otherwise =+    do releaseResourceWithinEvent r+       incResourceCount r (n - 1)+
+ Simulation/Aivika/Resource/Preemption.hs view
@@ -0,0 +1,308 @@++-- |+-- Module     : Simulation.Aivika.Resource.Preemption+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines the preemptible resource.+--+module Simulation.Aivika.Resource.Preemption+       (-- * Resource Type+        Resource,+        -- * Creating Resource+        newResource,+        newResourceWithMaxCount,+        -- * Resource Properties+        resourceMaxCount,+        resourceCount,+        -- * Requesting for and Releasing Resource+        requestResourceWithPriority,+        releaseResource,+        usingResourceWithPriority,+        -- * Altering Resource +        incResourceCount,+        decResourceCount,+        alterResourceCount) where++import Data.IORef++import Control.Monad+import Control.Monad.Trans+import Control.Exception++import Simulation.Aivika.Internal.Specs+import Simulation.Aivika.Internal.Simulation+import Simulation.Aivika.Internal.Event+import Simulation.Aivika.Internal.Cont+import Simulation.Aivika.Internal.Process+import Simulation.Aivika.QueueStrategy++import qualified Simulation.Aivika.PriorityQueue as PQ++-- | Represents a preemptible resource.+data Resource = +  Resource { resourceMaxCount :: Maybe Int,+             -- ^ Return the maximum count of the resource, where 'Nothing'+             -- means that the resource has no upper bound.+             resourceCountRef :: IORef Int,+             resourceActingQueue :: PQ.PriorityQueue ResourceActingItem,+             resourceWaitQueue :: PQ.PriorityQueue ResourceAwaitingItem }++-- | Identifies an acting item that acquired the resource.+data ResourceActingItem =+  ResourceActingItem { actingItemPriority :: Double,+                       actingItemId :: ProcessId }++-- | Idenitifies an awaiting item that waits for releasing of the resource to take it.+type ResourceAwaitingItem = Either ResourceRequestingItem ResourcePreemptedItem++-- | Idenitifies an item that requests for the resource.+data ResourceRequestingItem =+  ResourceRequestingItem { requestingItemPriority :: Double,+                           requestingItemId :: ProcessId,+                           requestingItemCont :: FrozenCont () }++-- | Idenitifies an item that was preempted.+data ResourcePreemptedItem =+  ResourcePreemptedItem { preemptedItemPriority :: Double,+                          preemptedItemId :: ProcessId }++instance Eq Resource where+  x == y = resourceCountRef x == resourceCountRef y  -- unique references++instance Eq ResourceActingItem where+  x == y = actingItemId x == actingItemId y++-- | Create a new resource with the specified initial count that becomes the upper bound as well.+newResource :: Int+               -- ^ the initial count (and maximal count too) of the resource+               -> Simulation Resource+newResource count =+  Simulation $ \r ->+  do when (count < 0) $+       error $+       "The resource count cannot be negative: " +++       "newResource."+     countRef <- newIORef count+     actingQueue <- PQ.newQueue+     waitQueue <- PQ.newQueue+     return Resource { resourceMaxCount = Just count,+                       resourceCountRef = countRef,+                       resourceActingQueue = actingQueue,+                       resourceWaitQueue = waitQueue }++-- | Create a new resource with the specified initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newResourceWithMaxCount :: Int+                           -- ^ the initial count of the resource+                           -> Maybe Int+                           -- ^ the maximum count of the resource, which can be indefinite+                           -> Simulation Resource+newResourceWithMaxCount count maxCount =+  Simulation $ \r ->+  do when (count < 0) $+       error $+       "The resource count cannot be negative: " +++       "newResourceWithMaxCount."+     case maxCount of+       Just maxCount | count > maxCount ->+         error $+         "The resource count cannot be greater than " +++         "its maximum value: newResourceWithMaxCount."+       _ ->+         return ()+     countRef <- newIORef count+     actingQueue <- PQ.newQueue+     waitQueue <- PQ.newQueue+     return Resource { resourceMaxCount = maxCount,+                       resourceCountRef = countRef,+                       resourceActingQueue = actingQueue,+                       resourceWaitQueue = waitQueue }++-- | Return the current count of the resource.+resourceCount :: Resource -> Event Int+resourceCount r =+  Event $ \p -> readIORef (resourceCountRef r)++-- | Request with the priority for the resource decreasing its count+-- in case of success, otherwise suspending the discontinuous process+-- until some other process releases the resource.+--+-- It may preempt another process if the latter aquired the resource before+-- but had a lower priority. Then the current process takes an ownership of+-- the resource.+requestResourceWithPriority :: Resource+                               -- ^ the requested resource+                               -> Double+                               -- ^ the priority (the less value has a higher priority)+                               -> Process ()+requestResourceWithPriority r priority =+  Process $ \pid ->+  Cont $ \c ->+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     if a == 0+       then do f <- PQ.queueNull (resourceActingQueue r)+               if f+                 then do c <- invokeEvent p $+                              freezeContReentering c () $+                              invokeCont c $+                              invokeProcess pid $+                              requestResourceWithPriority r priority+                         PQ.enqueue (resourceWaitQueue r) priority (Left $ ResourceRequestingItem priority pid c)+                 else do (p0', item0) <- PQ.queueFront (resourceActingQueue r)+                         let p0 = - p0'+                             pid0 = actingItemId item0+                         if priority < p0+                           then do PQ.dequeue (resourceActingQueue r)+                                   PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+                                   PQ.enqueue (resourceWaitQueue r) p0 (Right $ ResourcePreemptedItem p0 pid0)+                                   invokeEvent p $ processPreemptionBegin pid0+                                   invokeEvent p $ resumeCont c ()+                           else do c <- invokeEvent p $+                                        freezeContReentering c () $+                                        invokeCont c $+                                        invokeProcess pid $+                                        requestResourceWithPriority r priority+                                   PQ.enqueue (resourceWaitQueue r) priority (Left $ ResourceRequestingItem priority pid c)+       else do let a' = a - 1+               a' `seq` writeIORef (resourceCountRef r) a'+               PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+               invokeEvent p $ resumeCont c ()++-- | Release the resource increasing its count and resuming one of the+-- previously suspended or preempted processes as possible.+releaseResource :: Resource+                   -- ^ the resource to release+                   -> Process ()+releaseResource r = +  Process $ \pid ->+  Cont $ \c ->+  Event $ \p ->+  do f <- PQ.removeBy (resourceActingQueue r) (\item -> actingItemId item == pid)+     if f+       then do invokeEvent p $ releaseResource' r+               invokeEvent p $ resumeCont c ()+       else error $+            "The resource was not acquired by this process: releaseResource"++-- | Release the resource increasing its count and resuming one of the+-- previously suspended or preempted processes as possible.+releaseResource' :: Resource+                    -- ^ the resource to release+                    -> Event ()+releaseResource' r =+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     let a' = a + 1+     case resourceMaxCount r of+       Just maxCount | a' > maxCount ->+         error $+         "The resource count cannot be greater than " +++         "its maximum value: releaseResourceWithinEvent."+       _ ->+         return ()+     f <- PQ.queueNull (resourceWaitQueue r)+     if f +       then a' `seq` writeIORef (resourceCountRef r) a'+       else do (priority', item) <- PQ.queueFront (resourceWaitQueue r)+               PQ.dequeue (resourceWaitQueue r)+               case item of+                 Left (ResourceRequestingItem priority pid c) ->+                   do c <- invokeEvent p $ unfreezeCont c+                      case c of+                        Nothing ->+                          invokeEvent p $ releaseResource' r+                        Just c ->+                          do PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+                             invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()+                 Right (ResourcePreemptedItem priority pid) ->+                   do f <- invokeEvent p $ processCancelled pid+                      case f of+                        True ->+                          invokeEvent p $ releaseResource' r+                        False ->+                          do PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+                             invokeEvent p $ processPreemptionEnd pid+               +-- | Acquire the resource with the specified priority, perform some action and+-- safely release the resource in the end, even if the 'IOException' was raised+-- within the action.+usingResourceWithPriority :: Resource+                             -- ^ the resource we are going to request for and then+                             -- release in the end+                             -> Double+                             -- ^ the priority (the less value has a higher priority)+                             -> Process a+                             -- ^ the action we are going to apply having the resource+                             -> Process a+                             -- ^ the result of the action+usingResourceWithPriority r priority m =+  do requestResourceWithPriority r priority+     finallyProcess m $ releaseResource r++-- | Preempt a process with the lowest priority that acquires yet the resource+-- and decrease the count of available resource by 1. +decResourceCount' :: Resource -> Event ()+decResourceCount' r =+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     when (a == 0) $+       error $+       "The resource exceeded and its count is zero: decResourceCount'"+     f <- PQ.queueNull (resourceActingQueue r)+     when f $+       error $+       "The resource acting queue is null: decResourceCount'"+     (p0', item0) <- PQ.queueFront (resourceActingQueue r)+     let p0 = - p0'+         pid0 = actingItemId item0+     PQ.dequeue (resourceActingQueue r)+     PQ.enqueue (resourceWaitQueue r) p0 (Right $ ResourcePreemptedItem p0 pid0)+     invokeEvent p $ processPreemptionEnd pid0+     let a' = a - 1+     a' `seq` writeIORef (resourceCountRef r) a'++-- | Increase the count of available resource by the specified number,+-- invoking the awaiting and preempted processes according to their priorities+-- as needed.+incResourceCount :: Resource+                    -- ^ the resource+                    -> Int+                    -- ^ the increment for the resource count+                    -> Event ()+incResourceCount r n+  | n < 0     = error "The increment cannot be negative: incResourceCount"+  | n == 0    = return ()+  | otherwise =+    do releaseResource' r+       incResourceCount r (n - 1)++-- | Decrease the count of available resource by the specified number,+-- preempting the processes according to their priorities as needed.+decResourceCount :: Resource+                    -- ^ the resource+                    -> Int+                    -- ^ the decrement for the resource count+                    -> Event ()+decResourceCount r n+  | n < 0     = error "The decrement cannot be negative: decResourceCount"+  | n == 0    = return ()+  | otherwise =+    do decResourceCount' r+       decResourceCount r (n - 1)++-- | Alter the resource count either increasing or decreasing it by calling+-- 'incResourceCount' or 'decResourceCount' respectively. +alterResourceCount :: Resource+                      -- ^ the resource+                      -> Int+                      -- ^ a change of the resource count+                      -> Event ()+alterResourceCount r n+  | n < 0  = decResourceCount r (- n)+  | n > 0  = incResourceCount r n+  | n == 0 = return ()
Simulation/Aivika/Results.hs view
@@ -1651,12 +1651,15 @@       resultContainerProperty c "totalInputWaitTime" ServerTotalInputWaitTimeId serverTotalInputWaitTime serverTotalInputWaitTimeChanged_,       resultContainerProperty c "totalProcessingTime" ServerTotalProcessingTimeId serverTotalProcessingTime serverTotalProcessingTimeChanged_,       resultContainerProperty c "totalOutputWaitTime" ServerTotalOutputWaitTimeId serverTotalOutputWaitTime serverTotalOutputWaitTimeChanged_,+      resultContainerProperty c "totalPreemptionTime" ServerTotalPreemptionTimeId serverTotalPreemptionTime serverTotalPreemptionTimeChanged_,       resultContainerProperty c "inputWaitTime" ServerInputWaitTimeId serverInputWaitTime serverInputWaitTimeChanged_,       resultContainerProperty c "processingTime" ServerProcessingTimeId serverProcessingTime serverProcessingTimeChanged_,       resultContainerProperty c "outputWaitTime" ServerOutputWaitTimeId serverOutputWaitTime serverOutputWaitTimeChanged_,+      resultContainerProperty c "preemptionTime" ServerPreemptionTimeId serverPreemptionTime serverPreemptionTimeChanged_,       resultContainerProperty c "inputWaitFactor" ServerInputWaitFactorId serverInputWaitFactor serverInputWaitFactorChanged_,       resultContainerProperty c "processingFactor" ServerProcessingFactorId serverProcessingFactor serverProcessingFactorChanged_,-      resultContainerProperty c "outputWaitFactor" ServerOutputWaitFactorId serverOutputWaitFactor serverOutputWaitFactorChanged_ ] }+      resultContainerProperty c "outputWaitFactor" ServerOutputWaitFactorId serverOutputWaitFactor serverOutputWaitFactorChanged_,+      resultContainerProperty c "preemptionFactor" ServerPreemptionFactorId serverPreemptionFactor serverPreemptionFactorChanged_ ] }  -- | Return the summary by the specified server. serverResultSummary :: ResultContainer (Server s a b)@@ -1674,9 +1677,11 @@       resultContainerProperty c "inputWaitTime" ServerInputWaitTimeId serverInputWaitTime serverInputWaitTimeChanged_,       resultContainerProperty c "processingTime" ServerProcessingTimeId serverProcessingTime serverProcessingTimeChanged_,       resultContainerProperty c "outputWaitTime" ServerOutputWaitTimeId serverOutputWaitTime serverOutputWaitTimeChanged_,+      resultContainerProperty c "preemptionTime" ServerPreemptionTimeId serverPreemptionTime serverPreemptionTimeChanged_,       resultContainerProperty c "inputWaitFactor" ServerInputWaitFactorId serverInputWaitFactor serverInputWaitFactorChanged_,       resultContainerProperty c "processingFactor" ServerProcessingFactorId serverProcessingFactor serverProcessingFactorChanged_,-      resultContainerProperty c "outputWaitFactor" ServerOutputWaitFactorId serverOutputWaitFactor serverOutputWaitFactorChanged_ ] }+      resultContainerProperty c "outputWaitFactor" ServerOutputWaitFactorId serverOutputWaitFactor serverOutputWaitFactorChanged_,+      resultContainerProperty c "preemptionFactor" ServerPreemptionFactorId serverPreemptionFactor serverPreemptionFactorChanged_ ] }  -- | Return a source by the specified activity. activityResultSource :: (Show s, ResultItemable (ResultValue s))@@ -1696,10 +1701,13 @@       resultContainerProperty c "state" ActivityStateId activityState activityStateChanged_,       resultContainerProperty c "totalUtilisationTime" ActivityTotalUtilisationTimeId activityTotalUtilisationTime activityTotalUtilisationTimeChanged_,       resultContainerProperty c "totalIdleTime" ActivityTotalIdleTimeId activityTotalIdleTime activityTotalIdleTimeChanged_,+      resultContainerProperty c "totalPreemptionTime" ActivityTotalPreemptionTimeId activityTotalPreemptionTime activityTotalPreemptionTimeChanged_,       resultContainerProperty c "utilisationTime" ActivityUtilisationTimeId activityUtilisationTime activityUtilisationTimeChanged_,       resultContainerProperty c "idleTime" ActivityIdleTimeId activityIdleTime activityIdleTimeChanged_,+      resultContainerProperty c "preemptionTime" ActivityPreemptionTimeId activityPreemptionTime activityPreemptionTimeChanged_,       resultContainerProperty c "utilisationFactor" ActivityUtilisationFactorId activityUtilisationFactor activityUtilisationFactorChanged_,-      resultContainerProperty c "idleFactor" ActivityIdleFactorId activityIdleFactor activityIdleFactorChanged_ ] }+      resultContainerProperty c "idleFactor" ActivityIdleFactorId activityIdleFactor activityIdleFactorChanged_,+      resultContainerProperty c "preemptionFactor" ActivityPreemptionFactorId activityPreemptionFactor activityPreemptionFactorChanged_ ] }  -- | Return a summary by the specified activity. activityResultSummary :: ResultContainer (Activity s a b)@@ -1716,8 +1724,10 @@     resultObjectProperties = [       resultContainerProperty c "utilisationTime" ActivityUtilisationTimeId activityUtilisationTime activityUtilisationTimeChanged_,       resultContainerProperty c "idleTime" ActivityIdleTimeId activityIdleTime activityIdleTimeChanged_,+      resultContainerProperty c "preemptionTime" ActivityPreemptionTimeId activityPreemptionTime activityPreemptionTimeChanged_,       resultContainerProperty c "utilisationFactor" ActivityUtilisationFactorId activityUtilisationFactor activityUtilisationFactorChanged_,-      resultContainerProperty c "idleFactor" ActivityIdleFactorId activityIdleFactor activityIdleFactorChanged_ ] }+      resultContainerProperty c "idleFactor" ActivityIdleFactorId activityIdleFactor activityIdleFactorChanged_,+      resultContainerProperty c "preemptionFactor" ActivityPreemptionFactorId activityPreemptionFactor activityPreemptionFactorChanged_ ] }  -- | Return an arbitrary text as a separator source. textResultSource :: String -> ResultSource
Simulation/Aivika/Results/Locale.hs view
@@ -173,18 +173,24 @@                 -- ^ Property 'serverTotalProcessingTime'.               | ServerTotalOutputWaitTimeId                 -- ^ Property 'serverTotalOutputWaitTime'.+              | ServerTotalPreemptionTimeId+                -- ^ Property 'serverTotalPreemptionTime'.               | ServerInputWaitTimeId                 -- ^ Property 'serverInputWaitTime'.               | ServerProcessingTimeId                 -- ^ Property 'serverProcessingTime'.               | ServerOutputWaitTimeId                 -- ^ Property 'serverOutputWaitTime'.+              | ServerPreemptionTimeId+                -- ^ Property 'serverPreemptionTime'.               | ServerInputWaitFactorId                 -- ^ Property 'serverInputWaitFactor'.               | ServerProcessingFactorId                 -- ^ Property 'serverProcessingFactor'.               | ServerOutputWaitFactorId                 -- ^ Property 'serverOutputWaitFactor'.+              | ServerPreemptionFactorId+                -- ^ Property 'serverPreemptionFactor'.               | ActivityId                 -- ^ Represents an 'Activity'.               | ActivityInitStateId@@ -195,14 +201,20 @@                 -- ^ Property 'activityTotalUtilisationTime'.               | ActivityTotalIdleTimeId                 -- ^ Property 'activityTotalIdleTime'.+              | ActivityTotalPreemptionTimeId+                -- ^ Property 'activityTotalPreemptionTime'.               | ActivityUtilisationTimeId                 -- ^ Property 'activityUtilisationTime'.               | ActivityIdleTimeId                 -- ^ Property 'activityIdleTime'.+              | ActivityPreemptionTimeId+                -- ^ Property 'activityPreemptionTime'.               | ActivityUtilisationFactorId                 -- ^ Property 'activityUtilisationFactor'.               | ActivityIdleFactorId                 -- ^ Property 'activityIdleFactor'.+              | ActivityPreemptionFactorId+                -- ^ Property 'activityPreemptionFactor'.               | UserDefinedResultId ResultDescription                 -- ^ An user defined description.               | LocalisedResultId (M.Map ResultLocale ResultDescription)@@ -282,21 +294,27 @@ russianResultLocalisation ServerTotalInputWaitTimeId = "общее время блокировки в ожидании ввода" russianResultLocalisation ServerTotalProcessingTimeId = "общее время, потраченное на саму обработку заданий" russianResultLocalisation ServerTotalOutputWaitTimeId = "общее время блокировки при попытке доставить вывод"+russianResultLocalisation ServerTotalPreemptionTimeId = "общее время вытеснения" russianResultLocalisation ServerInputWaitTimeId = "время блокировки в ожидании ввода" russianResultLocalisation ServerProcessingTimeId = "время, потраченное на саму обработку заданий" russianResultLocalisation ServerOutputWaitTimeId = "время блокировки при попытке доставить вывод"+russianResultLocalisation ServerPreemptionTimeId = "время вытеснения" russianResultLocalisation ServerInputWaitFactorId = "относительное время блокировки в ожидании ввода (от 0 до 1)" russianResultLocalisation ServerProcessingFactorId = "относительное время, потраченное на саму обработку заданий (от 0 до 1)" russianResultLocalisation ServerOutputWaitFactorId = "относительное время блокировки при попытке доставить вывод (от 0 до 1)"+russianResultLocalisation ServerPreemptionFactorId = "относительное время вытеснения (от 0 до 1)" russianResultLocalisation ActivityId = "активность" russianResultLocalisation ActivityInitStateId = "начальное состояние" russianResultLocalisation ActivityStateId = "текущее состояние" russianResultLocalisation ActivityTotalUtilisationTimeId = "общее время использования" russianResultLocalisation ActivityTotalIdleTimeId = "общее время простоя"+russianResultLocalisation ActivityTotalPreemptionTimeId = "общее время вытеснения" russianResultLocalisation ActivityUtilisationTimeId = "статистика времени использования" russianResultLocalisation ActivityIdleTimeId = "статистика времени простоя"+russianResultLocalisation ActivityPreemptionTimeId = "статистика времени вытеснения" russianResultLocalisation ActivityUtilisationFactorId = "относительное время использования (от 0 до 1)" russianResultLocalisation ActivityIdleFactorId = "относительное время простоя (от 0 до 1)"+russianResultLocalisation ActivityPreemptionFactorId = "относительное время вытеснения (от 0 до 1)" russianResultLocalisation (UserDefinedResultId m) = m russianResultLocalisation x@(LocalisedResultId m) =   lookupResultLocalisation russianResultLocale x@@ -366,21 +384,27 @@ englishResultLocalisation ServerTotalInputWaitTimeId = "the total time spent while waiting for input" englishResultLocalisation ServerTotalProcessingTimeId = "the total time spent on actual processing the tasks" englishResultLocalisation ServerTotalOutputWaitTimeId = "the total time spent on delivering the output"+englishResultLocalisation ServerTotalPreemptionTimeId = "the total time spent being preempted" englishResultLocalisation ServerInputWaitTimeId = "the time spent while waiting for input" englishResultLocalisation ServerProcessingTimeId = "the time spent on processing the tasks" englishResultLocalisation ServerOutputWaitTimeId = "the time spent on delivering the output"+englishResultLocalisation ServerPreemptionTimeId = "the time spent being preempted" englishResultLocalisation ServerInputWaitFactorId = "the relative time spent while waiting for input (from 0 to 1)" englishResultLocalisation ServerProcessingFactorId = "the relative time spent on processing the tasks (from 0 to 1)" englishResultLocalisation ServerOutputWaitFactorId = "the relative time spent on delivering the output (from 0 to 1)"+englishResultLocalisation ServerPreemptionFactorId = "the relative time spent being preempted (from 0 to 1)" englishResultLocalisation ActivityId = "the activity" englishResultLocalisation ActivityInitStateId = "the initial state" englishResultLocalisation ActivityStateId = "the current state" englishResultLocalisation ActivityTotalUtilisationTimeId = "the total time of utilisation" englishResultLocalisation ActivityTotalIdleTimeId = "the total idle time"+englishResultLocalisation ActivityTotalPreemptionTimeId = "the total time of preemption" englishResultLocalisation ActivityUtilisationTimeId = "the utilisation time" englishResultLocalisation ActivityIdleTimeId = "the idle time"+englishResultLocalisation ActivityPreemptionTimeId = "the preemption time" englishResultLocalisation ActivityUtilisationFactorId = "the relative utilisation time (от 0 до 1)" englishResultLocalisation ActivityIdleFactorId = "the relative idle time (от 0 до 1)"+englishResultLocalisation ActivityPreemptionFactorId = "the relative preemption time (от 0 до 1)" englishResultLocalisation (UserDefinedResultId m) = m englishResultLocalisation x@(LocalisedResultId m) =   lookupResultLocalisation englishResultLocale x
Simulation/Aivika/Server.hs view
@@ -11,11 +11,10 @@ module Simulation.Aivika.Server        (-- * Server         Server,-        ServerInterruption(..),         newServer,         newStateServer,-        newInterruptibleServer,-        newInterruptibleStateServer,+        newPreemptibleServer,+        newPreemptibleStateServer,         -- * Processing         serverProcessor,         -- * Server Properties and Activities@@ -24,12 +23,15 @@         serverTotalInputWaitTime,         serverTotalProcessingTime,         serverTotalOutputWaitTime,+        serverTotalPreemptionTime,         serverInputWaitTime,         serverProcessingTime,         serverOutputWaitTime,+        serverPreemptionTime,         serverInputWaitFactor,         serverProcessingFactor,         serverOutputWaitFactor,+        serverPreemptionFactor,         -- * Summary         serverSummary,         -- * Derived Signals for Properties@@ -41,21 +43,28 @@         serverTotalProcessingTimeChanged_,         serverTotalOutputWaitTimeChanged,         serverTotalOutputWaitTimeChanged_,+        serverTotalPreemptionTimeChanged,+        serverTotalPreemptionTimeChanged_,         serverInputWaitTimeChanged,         serverInputWaitTimeChanged_,         serverProcessingTimeChanged,         serverProcessingTimeChanged_,         serverOutputWaitTimeChanged,         serverOutputWaitTimeChanged_,+        serverPreemptionTimeChanged,+        serverPreemptionTimeChanged_,         serverInputWaitFactorChanged,         serverInputWaitFactorChanged_,         serverProcessingFactorChanged,         serverProcessingFactorChanged_,         serverOutputWaitFactorChanged,         serverOutputWaitFactorChanged_,+        serverPreemptionFactorChanged,+        serverPreemptionFactorChanged_,         -- * Basic Signals         serverInputReceived,-        serverTaskInterrupted,+        serverTaskPreempting,+        serverTaskReentering,         serverTaskProcessed,         serverOutputProvided,         -- * Overall Signal@@ -87,24 +96,30 @@            -- ^ The current state of the server.            serverProcess :: s -> a -> Process (s, b),            -- ^ Provide @b@ by specified @a@.-           serverProcessInterruptible :: Bool,-           -- ^ Whether the process is interruptible.+           serverProcessPreemptible :: Bool,+           -- ^ Whether the process can be preempted.            serverTotalInputWaitTimeRef :: IORef Double,            -- ^ The counted total time spent in awating the input.            serverTotalProcessingTimeRef :: IORef Double,            -- ^ The counted total time spent to process the input and prepare the output.            serverTotalOutputWaitTimeRef :: IORef Double,            -- ^ The counted total time spent for delivering the output.+           serverTotalPreemptionTimeRef :: IORef Double,+           -- ^ The counted total time spent being preempted and waiting for the proceeding.             serverInputWaitTimeRef :: IORef (SamplingStats Double),            -- ^ The statistics for the time spent in awaiting the input.            serverProcessingTimeRef :: IORef (SamplingStats Double),            -- ^ The statistics for the time spent to process the input and prepare the output.            serverOutputWaitTimeRef :: IORef (SamplingStats Double),            -- ^ The statistics for the time spent for delivering the output.+           serverPreemptionTimeRef :: IORef (SamplingStats Double),+           -- ^ The statistics for the time spent being preempted.            serverInputReceivedSource :: SignalSource a,            -- ^ A signal raised when the server recieves a new input to process.-           serverTaskInterruptedSource :: SignalSource (ServerInterruption a),-           -- ^ A signal raised when the task was interrupted.+           serverTaskPreemptingSource :: SignalSource a,+           -- ^ A signal raised when the task was preempted.+           serverTaskReenteringSource :: SignalSource a,+           -- ^ A signal raised when the task was proceeded after it had been preempted earlier.            serverTaskProcessedSource :: SignalSource (a, b),            -- ^ A signal raised when the input is processed and            -- the output is prepared for deliverying.@@ -112,31 +127,21 @@            -- ^ A signal raised when the server has supplied the output.          } --- | Contains data about the interrupted task.-data ServerInterruption a =-  ServerInterruption { serverInterruptedInput :: a,-                       -- ^ The input task that was interrupted.-                       serverStartProcessingTime :: Double,-                       -- ^ The start time of processing the task.-                       serverInterruptionTime :: Double-                       -- ^ The time of interrupting the task.-                     }- -- | Create a new server that can provide output @b@ by input @a@. ----- By default, it is assumed that the server cannot be interrupted,--- because the handling of possible task interruption is rather costly+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly -- operation. newServer :: (a -> Process b)              -- ^ provide an output by the specified input              -> Simulation (Server () a b)-newServer = newInterruptibleServer False+newServer = newPreemptibleServer False  -- | Create a new server that can provide output @b@ by input @a@ -- starting from state @s@. ----- By default, it is assumed that the server cannot be interrupted,--- because the handling of possible task interruption is rather costly+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly -- operation. newStateServer :: (s -> a -> Process (s, b))                   -- ^ provide a new state and output by the specified @@ -144,55 +149,61 @@                   -> s                   -- ^ the initial state                   -> Simulation (Server s a b)-newStateServer = newInterruptibleStateServer False+newStateServer = newPreemptibleStateServer False --- | Create a new interruptible server that can provide output @b@ by input @a@.-newInterruptibleServer :: Bool-                          -- ^ whether the server can be interrupted-                          -> (a -> Process b)-                          -- ^ provide an output by the specified input-                          -> Simulation (Server () a b)-newInterruptibleServer interruptible provide =-  flip (newInterruptibleStateServer interruptible) () $ \s a ->+-- | Create a new preemptible server that can provide output @b@ by input @a@.+newPreemptibleServer :: Bool+                        -- ^ whether the server process can be preempted+                        -> (a -> Process b)+                        -- ^ provide an output by the specified input+                        -> Simulation (Server () a b)+newPreemptibleServer preemptible provide =+  flip (newPreemptibleStateServer preemptible) () $ \s a ->   do b <- provide a      return (s, b) --- | Create a new interruptible server that can provide output @b@ by input @a@+-- | Create a new preemptible server that can provide output @b@ by input @a@ -- starting from state @s@.-newInterruptibleStateServer :: Bool-                               -- ^ whether the server can be interrupted-                               -> (s -> a -> Process (s, b))-                               -- ^ provide a new state and output by the specified -                               -- old state and input-                               -> s-                               -- ^ the initial state-                               -> Simulation (Server s a b)-newInterruptibleStateServer interruptible provide state =+newPreemptibleStateServer :: Bool+                             -- ^ whether the server process can be preempted+                             -> (s -> a -> Process (s, b))+                             -- ^ provide a new state and output by the specified +                             -- old state and input+                             -> s+                             -- ^ the initial state+                             -> Simulation (Server s a b)+newPreemptibleStateServer preemptible provide state =   do r0 <- liftIO $ newIORef state      r1 <- liftIO $ newIORef 0      r2 <- liftIO $ newIORef 0      r3 <- liftIO $ newIORef 0-     r4 <- liftIO $ newIORef emptySamplingStats+     r4 <- liftIO $ newIORef 0      r5 <- liftIO $ newIORef emptySamplingStats      r6 <- liftIO $ newIORef emptySamplingStats+     r7 <- liftIO $ newIORef emptySamplingStats+     r8 <- liftIO $ newIORef emptySamplingStats      s1 <- newSignalSource      s2 <- newSignalSource      s3 <- newSignalSource      s4 <- newSignalSource+     s5 <- newSignalSource      let server = Server { serverInitState = state,                            serverStateRef = r0,                            serverProcess = provide,-                           serverProcessInterruptible = interruptible,+                           serverProcessPreemptible = preemptible,                            serverTotalInputWaitTimeRef = r1,                            serverTotalProcessingTimeRef = r2,                            serverTotalOutputWaitTimeRef = r3,-                           serverInputWaitTimeRef = r4,-                           serverProcessingTimeRef = r5,-                           serverOutputWaitTimeRef = r6,+                           serverTotalPreemptionTimeRef = r4,+                           serverInputWaitTimeRef = r5,+                           serverProcessingTimeRef = r6,+                           serverOutputWaitTimeRef = r7,+                           serverPreemptionTimeRef = r8,                            serverInputReceivedSource = s1,-                           serverTaskInterruptedSource = s2,-                           serverTaskProcessedSource = s3,-                           serverOutputProvidedSource = s4 }+                           serverTaskPreemptingSource = s2,+                           serverTaskReenteringSource = s3,+                           serverTaskProcessedSource = s4,+                           serverOutputProvidedSource = s5 }      return server  -- | Return a processor for the specified server.@@ -242,37 +253,53 @@                      addSamplingStats (t1 - t0)               triggerSignal (serverInputReceivedSource server) a          -- provide the service-         (s', b) <--           if serverProcessInterruptible server-           then serverProcessInterrupting server s a-           else serverProcess server s a+         (s', b, dt) <-+           if serverProcessPreemptible server+           then serverProcessPreempting server s a+           else do (s', b) <- serverProcess server s a+                   return (s', b, 0)          t2 <- liftDynamics time          liftEvent $            do liftIO $                 do writeIORef (serverStateRef server) $! s'-                   modifyIORef' (serverTotalProcessingTimeRef server) (+ (t2 - t1))+                   modifyIORef' (serverTotalProcessingTimeRef server) (+ (t2 - t1 - dt))                    modifyIORef' (serverProcessingTimeRef server) $-                     addSamplingStats (t2 - t1)+                     addSamplingStats (t2 - t1 - dt)               triggerSignal (serverTaskProcessedSource server) (a, b)          return (b, loop s' (Just (t2, a, b)) xs') --- | Process the input with ability to handle a possible interruption.-serverProcessInterrupting :: Server s a b -> s -> a -> Process (s, b)-serverProcessInterrupting server s a =+-- | Process the input with ability to handle a possible preemption.+serverProcessPreempting :: Server s a b -> s -> a -> Process (s, b, Double)+serverProcessPreempting server s a =   do pid <- processId      t1  <- liftDynamics time-     finallyProcess-       (serverProcess server s a)-       (liftEvent $-        do cancelled <- processCancelled pid-           when cancelled $-             do t2 <- liftDynamics time-                liftIO $-                  do modifyIORef' (serverTotalProcessingTimeRef server) (+ (t2 - t1))-                     modifyIORef' (serverProcessingTimeRef server) $-                       addSamplingStats (t2 - t1)-                let x = ServerInterruption a t1 t2-                triggerSignal (serverTaskInterruptedSource server) x)+     rs  <- liftIO $ newIORef 0+     r1  <- liftIO $ newIORef t1+     h1  <- liftEvent $+            handleSignal (processPreemptionBeginning pid) $ \() ->+            do t1 <- liftDynamics time+               liftIO $ writeIORef r1 t1+               triggerSignal (serverTaskPreemptingSource server) a+     h2  <- liftEvent $+            handleSignal (processPreemptionEnding pid) $ \() ->+            do t1 <- liftIO $ readIORef r1+               t2 <- liftDynamics time+               let dt = t2 - t1+               liftIO $+                 do modifyIORef' rs (+ dt)+                    modifyIORef' (serverTotalPreemptionTimeRef server) (+ dt)+                    modifyIORef' (serverPreemptionTimeRef server) $+                      addSamplingStats dt+               triggerSignal (serverTaskReenteringSource server) a +     let m1 =+           do (s', b) <- serverProcess server s a+              dt <- liftIO $ readIORef rs+              return (s', b, dt)+         m2 =+           liftEvent $+           do disposeEvent h1+              disposeEvent h2+     finallyProcess m1 m2  -- | Return the current state of the server. --@@ -352,6 +379,27 @@ serverTotalOutputWaitTimeChanged_ server =   mapSignal (const ()) (serverOutputProvided server) +-- | Return the counted total time spent by the server while it was preempted+-- waiting for the further proceeding.+--+-- The value returned changes discretely and it is usually delayed relative+-- to the current simulation time.+--+-- See also 'serverTotalPreemptionTimeChanged' and 'serverTotalPreemptionTimeChanged_'.+serverTotalPreemptionTime :: Server s a b -> Event Double+serverTotalPreemptionTime server =+  Event $ \p -> readIORef (serverTotalPreemptionTimeRef server)+  +-- | Signal when the 'serverTotalPreemptionTime' property value has changed.+serverTotalPreemptionTimeChanged :: Server s a b -> Signal Double+serverTotalPreemptionTimeChanged server =+  mapSignalM (const $ serverTotalPreemptionTime server) (serverTotalPreemptionTimeChanged_ server)+  +-- | Signal when the 'serverTotalPreemptionTime' property value has changed.+serverTotalPreemptionTimeChanged_ :: Server s a b -> Signal ()+serverTotalPreemptionTimeChanged_ server =+  mapSignal (const ()) (serverTaskReentering server)+ -- | Return the statistics of the time when the server was locked while awaiting the input. -- -- The value returned changes discretely and it is usually delayed relative@@ -413,13 +461,34 @@ serverOutputWaitTimeChanged_ server =   mapSignal (const ()) (serverOutputProvided server) +-- | Return the statistics of the time spent by the server while it was preempted+-- waiting for the further proceeding.+--+-- The value returned changes discretely and it is usually delayed relative+-- to the current simulation time.+--+-- See also 'serverPreemptionTimeChanged' and 'serverPreemptionTimeChanged_'.+serverPreemptionTime :: Server s a b -> Event (SamplingStats Double)+serverPreemptionTime server =+  Event $ \p -> readIORef (serverPreemptionTimeRef server)+  +-- | Signal when the 'serverPreemptionTime' property value has changed.+serverPreemptionTimeChanged :: Server s a b -> Signal (SamplingStats Double)+serverPreemptionTimeChanged server =+  mapSignalM (const $ serverPreemptionTime server) (serverPreemptionTimeChanged_ server)+  +-- | Signal when the 'serverPreemptionTime' property value has changed.+serverPreemptionTimeChanged_ :: Server s a b -> Signal ()+serverPreemptionTimeChanged_ server =+  mapSignal (const ()) (serverTaskReentering server)+ -- | It returns the factor changing from 0 to 1, which estimates how often -- the server was awaiting for the next input task. -- -- This factor is calculated as -- -- @---   totalInputWaitTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime)+--   totalInputWaitTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime + totalPreemptionTime) -- @ -- -- As before in this module, the value returned changes discretely and@@ -432,7 +501,8 @@   do x1 <- readIORef (serverTotalInputWaitTimeRef server)      x2 <- readIORef (serverTotalProcessingTimeRef server)      x3 <- readIORef (serverTotalOutputWaitTimeRef server)-     return (x1 / (x1 + x2 + x3))+     x4 <- readIORef (serverTotalPreemptionTimeRef server)+     return (x1 / (x1 + x2 + x3 + x4))    -- | Signal when the 'serverInputWaitFactor' property value has changed. serverInputWaitFactorChanged :: Server s a b -> Signal Double@@ -444,7 +514,8 @@ serverInputWaitFactorChanged_ server =   mapSignal (const ()) (serverInputReceived server) <>   mapSignal (const ()) (serverTaskProcessed server) <>-  mapSignal (const ()) (serverOutputProvided server)+  mapSignal (const ()) (serverOutputProvided server) <>+  mapSignal (const ()) (serverTaskReentering server)  -- | It returns the factor changing from 0 to 1, which estimates how often -- the server was busy with direct processing its tasks.@@ -452,7 +523,7 @@ -- This factor is calculated as -- -- @---   totalProcessingTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime)+--   totalProcessingTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime + totalPreemptionTime) -- @ -- -- As before in this module, the value returned changes discretely and@@ -465,7 +536,8 @@   do x1 <- readIORef (serverTotalInputWaitTimeRef server)      x2 <- readIORef (serverTotalProcessingTimeRef server)      x3 <- readIORef (serverTotalOutputWaitTimeRef server)-     return (x2 / (x1 + x2 + x3))+     x4 <- readIORef (serverTotalPreemptionTimeRef server)+     return (x2 / (x1 + x2 + x3 + x4))    -- | Signal when the 'serverProcessingFactor' property value has changed. serverProcessingFactorChanged :: Server s a b -> Signal Double@@ -477,7 +549,8 @@ serverProcessingFactorChanged_ server =   mapSignal (const ()) (serverInputReceived server) <>   mapSignal (const ()) (serverTaskProcessed server) <>-  mapSignal (const ()) (serverOutputProvided server)+  mapSignal (const ()) (serverOutputProvided server) <>+  mapSignal (const ()) (serverTaskReentering server)  -- | It returns the factor changing from 0 to 1, which estimates how often -- the server was locked trying to deliver the output after the task is finished.@@ -485,7 +558,7 @@ -- This factor is calculated as -- -- @---   totalOutputWaitTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime)+--   totalOutputWaitTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime + totalPreemptionTime) -- @ -- -- As before in this module, the value returned changes discretely and@@ -498,7 +571,8 @@   do x1 <- readIORef (serverTotalInputWaitTimeRef server)      x2 <- readIORef (serverTotalProcessingTimeRef server)      x3 <- readIORef (serverTotalOutputWaitTimeRef server)-     return (x3 / (x1 + x2 + x3))+     x4 <- readIORef (serverTotalPreemptionTimeRef server)+     return (x3 / (x1 + x2 + x3 + x4))    -- | Signal when the 'serverOutputWaitFactor' property value has changed. serverOutputWaitFactorChanged :: Server s a b -> Signal Double@@ -510,16 +584,56 @@ serverOutputWaitFactorChanged_ server =   mapSignal (const ()) (serverInputReceived server) <>   mapSignal (const ()) (serverTaskProcessed server) <>-  mapSignal (const ()) (serverOutputProvided server)+  mapSignal (const ()) (serverOutputProvided server) <>+  mapSignal (const ()) (serverTaskReentering server) +-- | It returns the factor changing from 0 to 1, which estimates how often+-- the server was preempted waiting for the further proceeding.+--+-- This factor is calculated as+--+-- @+--   totalPreemptionTime \/ (totalInputWaitTime + totalProcessingTime + totalOutputWaitTime + totalPreemptionTime)+-- @+--+-- As before in this module, the value returned changes discretely and+-- it is usually delayed relative to the current simulation time.+--+-- See also 'serverPreemptionFactorChanged' and 'serverPreemptionFactorChanged_'.+serverPreemptionFactor :: Server s a b -> Event Double+serverPreemptionFactor server =+  Event $ \p ->+  do x1 <- readIORef (serverTotalInputWaitTimeRef server)+     x2 <- readIORef (serverTotalProcessingTimeRef server)+     x3 <- readIORef (serverTotalOutputWaitTimeRef server)+     x4 <- readIORef (serverTotalPreemptionTimeRef server)+     return (x4 / (x1 + x2 + x3 + x4))+  +-- | Signal when the 'serverPreemptionFactor' property value has changed.+serverPreemptionFactorChanged :: Server s a b -> Signal Double+serverPreemptionFactorChanged server =+  mapSignalM (const $ serverPreemptionFactor server) (serverPreemptionFactorChanged_ server)+  +-- | Signal when the 'serverPreemptionFactor' property value has changed.+serverPreemptionFactorChanged_ :: Server s a b -> Signal ()+serverPreemptionFactorChanged_ server =+  mapSignal (const ()) (serverInputReceived server) <>+  mapSignal (const ()) (serverTaskProcessed server) <>+  mapSignal (const ()) (serverOutputProvided server) <>+  mapSignal (const ()) (serverTaskReentering server)+ -- | Raised when the server receives a new input task. serverInputReceived :: Server s a b -> Signal a serverInputReceived = publishSignal . serverInputReceivedSource --- | Raised when the task processing by the server was interrupted.-serverTaskInterrupted :: Server s a b -> Signal (ServerInterruption a)-serverTaskInterrupted = publishSignal . serverTaskInterruptedSource+-- | Raised when the task processing by the server was preempted.+serverTaskPreempting :: Server s a b -> Signal a+serverTaskPreempting = publishSignal . serverTaskPreemptingSource +-- | Raised when the task processing by the server was proceeded after it has been preempeted earlier.+serverTaskReentering :: Server s a b -> Signal a+serverTaskReentering = publishSignal . serverTaskReenteringSource+ -- | Raised when the server has just processed the task. serverTaskProcessed :: Server s a b -> Signal (a, b) serverTaskProcessed = publishSignal . serverTaskProcessedSource@@ -532,9 +646,9 @@ serverChanged_ :: Server s a b -> Signal () serverChanged_ server =   mapSignal (const ()) (serverInputReceived server) <>-  mapSignal (const ()) (serverTaskInterrupted server) <>   mapSignal (const ()) (serverTaskProcessed server) <>-  mapSignal (const ()) (serverOutputProvided server)+  mapSignal (const ()) (serverOutputProvided server) <>+  mapSignal (const ()) (serverTaskReentering server)  -- | Return the summary for the server with desciption of its -- properties and activities using the specified indent.@@ -544,12 +658,15 @@   do tx1 <- readIORef (serverTotalInputWaitTimeRef server)      tx2 <- readIORef (serverTotalProcessingTimeRef server)      tx3 <- readIORef (serverTotalOutputWaitTimeRef server)-     let xf1 = tx1 / (tx1 + tx2 + tx3)-         xf2 = tx2 / (tx1 + tx2 + tx3)-         xf3 = tx3 / (tx1 + tx2 + tx3)+     tx4 <- readIORef (serverTotalPreemptionTimeRef server)+     let xf1 = tx1 / (tx1 + tx2 + tx3 + tx4)+         xf2 = tx2 / (tx1 + tx2 + tx3 + tx4)+         xf3 = tx3 / (tx1 + tx2 + tx3 + tx4)+         xf4 = tx4 / (tx1 + tx3 + tx3 + tx4)      xs1 <- readIORef (serverInputWaitTimeRef server)      xs2 <- readIORef (serverProcessingTimeRef server)      xs3 <- readIORef (serverOutputWaitTimeRef server)+     xs4 <- readIORef (serverPreemptionTimeRef server)      let tab = replicate indent ' '      return $        showString tab .@@ -562,6 +679,9 @@        showString "total output wait time (locked while delivering the output) = " . shows tx3 .        showString "\n\n" .        showString tab .+       showString "total preemption time = " . shows tx4 .+       showString "\n" .+       showString tab .        showString "input wait factor (from 0 to 1) = " . shows xf1 .        showString "\n" .        showString tab .@@ -571,6 +691,9 @@        showString "output wait factor (from 0 to 1) = " . shows xf3 .        showString "\n\n" .        showString tab .+       showString "output preemption factor (from 0 to 1) = " . shows xf4 .+       showString "\n\n" .+       showString tab .        showString "input wait time (locked while awaiting the input):\n\n" .        samplingStatsSummary xs1 (2 + indent) .        showString "\n\n" .@@ -580,4 +703,8 @@        showString "\n\n" .        showString tab .        showString "output wait time (locked while delivering the output):\n\n" .-       samplingStatsSummary xs3 (2 + indent)+       samplingStatsSummary xs3 (2 + indent) .+       showString "\n\n" .+       showString tab .+       showString "preemption time (waiting for the proceeding after preemption):\n\n" .+       samplingStatsSummary xs4 (2 + indent)
+ Simulation/Aivika/Server/Random.hs view
@@ -0,0 +1,230 @@++-- |+-- Module     : Simulation.Aivika.Server.Random+-- Copyright  : Copyright (c) 2009-2015, David Sorokin <david.sorokin@gmail.com>+-- License    : BSD3+-- Maintainer : David Sorokin <david.sorokin@gmail.com>+-- Stability  : experimental+-- Tested with: GHC 7.8.3+--+-- This module defines some useful predefined servers that+-- hold the current process for the corresponding random time+-- interval, when processing every input element.+--++module Simulation.Aivika.Server.Random+       (newRandomUniformServer,+        newRandomUniformIntServer,+        newRandomNormalServer,+        newRandomExponentialServer,+        newRandomErlangServer,+        newRandomPoissonServer,+        newRandomBinomialServer,+        newPreemptibleRandomUniformServer,+        newPreemptibleRandomUniformIntServer,+        newPreemptibleRandomNormalServer,+        newPreemptibleRandomExponentialServer,+        newPreemptibleRandomErlangServer,+        newPreemptibleRandomPoissonServer,+        newPreemptibleRandomBinomialServer) where++import Simulation.Aivika.Simulation+import Simulation.Aivika.Process+import Simulation.Aivika.Process.Random+import Simulation.Aivika.Server++-- | Create a new server that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomUniformServer :: Double+                          -- ^ the minimum time interval+                          -> Double+                          -- ^ the maximum time interval+                          -> Simulation (Server () a a)+newRandomUniformServer =+  newPreemptibleRandomUniformServer False++-- | Create a new server that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomUniformIntServer :: Int+                             -- ^ the minimum time interval+                             -> Int+                             -- ^ the maximum time interval+                             -> Simulation (Server () a a)+newRandomUniformIntServer =+  newPreemptibleRandomUniformIntServer False++-- | Create a new server that holds the process for a random time interval+-- distributed normally, when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomNormalServer :: Double+                         -- ^ the mean time interval+                         -> Double+                         -- ^ the time interval deviation+                         -> Simulation (Server () a a)+newRandomNormalServer =+  newPreemptibleRandomNormalServer False+         +-- | Create a new server that holds the process for a random time interval+-- distributed exponentially with the specified mean (the reciprocal of the rate),+-- when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomExponentialServer :: Double+                              -- ^ the mean time interval (the reciprocal of the rate)+                              -> Simulation (Server () a a)+newRandomExponentialServer =+  newPreemptibleRandomExponentialServer False+         +-- | Create a new server that holds the process for a random time interval+-- having the Erlang distribution with the specified scale (the reciprocal of the rate)+-- and shape parameters, when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomErlangServer :: Double+                         -- ^ the scale (the reciprocal of the rate)+                         -> Int+                         -- ^ the shape+                         -> Simulation (Server () a a)+newRandomErlangServer =+  newPreemptibleRandomErlangServer False++-- | Create a new server that holds the process for a random time interval+-- having the Poisson distribution with the specified mean, when processing+-- every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomPoissonServer :: Double+                          -- ^ the mean time interval+                          -> Simulation (Server () a a)+newRandomPoissonServer =+  newPreemptibleRandomPoissonServer False++-- | Create a new server that holds the process for a random time interval+-- having the binomial distribution with the specified probability and trials,+-- when processing every input element.+--+-- By default, it is assumed that the server process cannot be preempted,+-- because the handling of possible task preemption is rather costly+-- operation.+newRandomBinomialServer :: Double+                           -- ^ the probability+                           -> Int+                           -- ^ the number of trials+                           -> Simulation (Server () a a)+newRandomBinomialServer =+  newPreemptibleRandomBinomialServer False++-- | Create a new server that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+newPreemptibleRandomUniformServer :: Bool+                                     -- ^ whether the server process can be preempted+                                     -> Double+                                     -- ^ the minimum time interval+                                     -> Double+                                     -- ^ the maximum time interval+                                     -> Simulation (Server () a a)+newPreemptibleRandomUniformServer preemptible min max =+  newPreemptibleServer preemptible $ \a ->+  do randomUniformProcess_ min max+     return a++-- | Create a new server that holds the process for a random time interval+-- distributed uniformly, when processing every input element.+newPreemptibleRandomUniformIntServer :: Bool+                                        -- ^ whether the server process can be preempted+                                        -> Int+                                        -- ^ the minimum time interval+                                        -> Int+                                        -- ^ the maximum time interval+                                        -> Simulation (Server () a a)+newPreemptibleRandomUniformIntServer preemptible min max =+  newPreemptibleServer preemptible $ \a ->+  do randomUniformIntProcess_ min max+     return a++-- | Create a new server that holds the process for a random time interval+-- distributed normally, when processing every input element.+newPreemptibleRandomNormalServer :: Bool+                                    -- ^ whether the server process can be preempted+                                    -> Double+                                    -- ^ the mean time interval+                                    -> Double+                                    -- ^ the time interval deviation+                                    -> Simulation (Server () a a)+newPreemptibleRandomNormalServer preemptible mu nu =+  newPreemptibleServer preemptible $ \a ->+  do randomNormalProcess_ mu nu+     return a+         +-- | Create a new server that holds the process for a random time interval+-- distributed exponentially with the specified mean (the reciprocal of the rate),+-- when processing every input element.+newPreemptibleRandomExponentialServer :: Bool+                                         -- ^ whether the server process can be preempted+                                         -> Double+                                         -- ^ the mean time interval (the reciprocal of the rate)+                                         -> Simulation (Server () a a)+newPreemptibleRandomExponentialServer preemptible mu =+  newPreemptibleServer preemptible $ \a ->+  do randomExponentialProcess_ mu+     return a+         +-- | Create a new server that holds the process for a random time interval+-- having the Erlang distribution with the specified scale (the reciprocal of the rate)+-- and shape parameters, when processing every input element.+newPreemptibleRandomErlangServer :: Bool+                                    -- ^ whether the server process can be preempted+                                    -> Double+                                    -- ^ the scale (the reciprocal of the rate)+                                    -> Int+                                    -- ^ the shape+                                    -> Simulation (Server () a a)+newPreemptibleRandomErlangServer preemptible beta m =+  newPreemptibleServer preemptible $ \a ->+  do randomErlangProcess_ beta m+     return a++-- | Create a new server that holds the process for a random time interval+-- having the Poisson distribution with the specified mean, when processing+-- every input element.+newPreemptibleRandomPoissonServer :: Bool+                                     -- ^ whether the server process can be preempted+                                     -> Double+                                     -- ^ the mean time interval+                                  -> Simulation (Server () a a)+newPreemptibleRandomPoissonServer preemptible mu =+  newPreemptibleServer preemptible $ \a ->+  do randomPoissonProcess_ mu+     return a++-- | Create a new server that holds the process for a random time interval+-- having the binomial distribution with the specified probability and trials,+-- when processing every input element.+newPreemptibleRandomBinomialServer :: Bool+                                     -- ^ whether the server process can be preempted+                                     -> Double+                                     -- ^ the probability+                                     -> Int+                                     -- ^ the number of trials+                                     -> Simulation (Server () a a)+newPreemptibleRandomBinomialServer preemptible prob trials =+  newPreemptibleServer preemptible $ \a ->+  do randomBinomialProcess_ prob trials+     return a
Simulation/Aivika/Signal.hs view
@@ -25,7 +25,9 @@         mapSignalM,         apSignal,         filterSignal,+        filterSignal_,         filterSignalM,+        filterSignalM_,         emptySignal,         merge2Signals,         merge3Signals,@@ -174,15 +176,23 @@   Signal { handleSignal = \h ->              handleSignal m $ h . f } --- | Filter only those signal values that satisfy to +-- | Filter only those signal values that satisfy  -- the specified predicate. filterSignal :: (a -> Bool) -> Signal a -> Signal a filterSignal p m =   Signal { handleSignal = \h ->             handleSignal m $ \a ->             when (p a) $ h a }++-- | Filter only those signal values that satisfy+-- the specified predicate, but then ignoring the values.+filterSignal_ :: (a -> Bool) -> Signal a -> Signal ()+filterSignal_ p m =+  Signal { handleSignal = \h ->+            handleSignal m $ \a ->+            when (p a) $ h () }   --- | Filter only those signal values that satisfy to +-- | Filter only those signal values that satisfy -- the specified predicate. filterSignalM :: (a -> Event Bool) -> Signal a -> Signal a filterSignalM p m =@@ -190,6 +200,15 @@             handleSignal m $ \a ->             do x <- p a                when x $ h a }+  +-- | Filter only those signal values that satisfy+-- the specified predicate, but then ignoring the values.+filterSignalM_ :: (a -> Event Bool) -> Signal a -> Signal ()+filterSignalM_ p m =+  Signal { handleSignal = \h ->+            handleSignal m $ \a ->+            do x <- p a+               when x $ h () }    -- | Merge two signals. merge2Signals :: Signal a -> Signal a -> Signal a
Simulation/Aivika/Stream.hs view
@@ -50,6 +50,12 @@         apStreamM,         filterStream,         filterStreamM,+        takeStream,+        takeStreamWhile,+        takeStreamWhileM,+        dropStream,+        dropStreamWhile,+        dropStreamWhileM,         singletonStream,         joinStream,         -- * Failover@@ -595,6 +601,62 @@                             runProcess $ loop ps          liftEvent $ runProcess $ loop ps          runStream $ repeatProcess reader++-- | Return the prefix of the stream of the specified length.+takeStream :: Int -> Stream a -> Stream a+takeStream n s+  | n <= 0    = emptyStream+  | otherwise =+    Cons $+    do (a, xs) <- runStream s+       return (a, takeStream (n - 1) xs)++-- | Return the longest prefix of the stream of elements that satisfy the predicate.+takeStreamWhile :: (a -> Bool) -> Stream a -> Stream a+takeStreamWhile p s =+  Cons $+  do (a, xs) <- runStream s+     if p a+       then return (a, takeStreamWhile p xs)+       else neverProcess++-- | Return the longest prefix of the stream of elements that satisfy the computation.+takeStreamWhileM :: (a -> Process Bool) -> Stream a -> Stream a+takeStreamWhileM p s =+  Cons $+  do (a, xs) <- runStream s+     f <- p a+     if f+       then return (a, takeStreamWhileM p xs)+       else neverProcess++-- | Return the suffix of the stream after the specified first elements.+dropStream :: Int -> Stream a -> Stream a+dropStream n s+  | n <= 0    = s+  | otherwise =+    Cons $+    do (a, xs) <- runStream s+       runStream $ dropStream (n - 1) xs++-- | Return the suffix of the stream of elements remaining after 'takeStreamWhile'.+dropStreamWhile :: (a -> Bool) -> Stream a -> Stream a+dropStreamWhile p s =+  Cons $+  do (a, xs) <- runStream s+     if p a+       then runStream $ dropStreamWhile p xs+       else return (a, xs)++-- | Return the suffix of the stream of elements remaining after 'takeStreamWhileM'.+dropStreamWhileM :: (a -> Process Bool) -> Stream a -> Stream a+dropStreamWhileM p s =+  Cons $+  do (a, xs) <- runStream s+     f <- p a+     if f+       then runStream $ dropStreamWhileM p xs+       else return (a, xs)  -- | Show the debug messages with the current simulation time. traceStream :: Maybe String
Simulation/Aivika/Stream/Random.hs view
@@ -22,8 +22,6 @@         randomPoissonStream,         randomBinomialStream) where -import System.Random- import Control.Monad import Control.Monad.Trans 
aivika.cabal view
@@ -1,5 +1,5 @@ name:            aivika-version:         3.1+version:         4.0 synopsis:        A multi-paradigm simulation library description:     Aivika is a multi-paradigm simulation library with a strong emphasis@@ -119,6 +119,7 @@      exposed-modules: Simulation.Aivika                      Simulation.Aivika.Activity+                     Simulation.Aivika.Activity.Random                      Simulation.Aivika.Agent                      Simulation.Aivika.Arrival                      Simulation.Aivika.Circuit@@ -132,11 +133,14 @@                      Simulation.Aivika.Event                      Simulation.Aivika.Generator                      Simulation.Aivika.Net+                     Simulation.Aivika.Net.Random                      Simulation.Aivika.Parameter                      Simulation.Aivika.Parameter.Random                      Simulation.Aivika.PriorityQueue                      Simulation.Aivika.Process+                     Simulation.Aivika.Process.Random                      Simulation.Aivika.Processor+                     Simulation.Aivika.Processor.Random                      Simulation.Aivika.Processor.RoundRobbin                      Simulation.Aivika.Queue                      Simulation.Aivika.Queue.Infinite@@ -144,10 +148,12 @@                      Simulation.Aivika.Ref                      Simulation.Aivika.Ref.Plain                      Simulation.Aivika.Resource+                     Simulation.Aivika.Resource.Preemption                      Simulation.Aivika.Results.Locale                      Simulation.Aivika.Results                      Simulation.Aivika.Results.IO                      Simulation.Aivika.Server+                     Simulation.Aivika.Server.Random                      Simulation.Aivika.Signal                      Simulation.Aivika.Simulation                      Simulation.Aivika.Specs
examples/InspectionAdjustmentStations.hs view
@@ -58,9 +58,8 @@ -- create an inspection station (server) newInspectionStation =   newServer $ \a ->-  do holdProcess =<<-       (liftParameter $-        randomUniform minInspectionTime maxInspectionTime)+  do randomUniformProcess_+       minInspectionTime maxInspectionTime      passed <-         liftParameter $        randomTrue inspectionPassingProb@@ -70,11 +69,7 @@  -- create an adjustment station (server) newAdjustmentStation =-  newServer $ \a ->-  do holdProcess =<<-       (liftParameter $-        randomUniform minAdjustmentTime maxAdjustmentTime)-     return a+  newRandomUniformServer minAdjustmentTime maxAdjustmentTime    model :: Simulation Results model = mdo
examples/MachRep1.hs view
@@ -35,15 +35,11 @@      let machine :: Process ()          machine =            do upTime <--                liftParameter $-                randomExponential meanUpTime-              holdProcess upTime+                randomExponentialProcess meanUpTime               liftEvent $                  modifyRef totalUpTime (+ upTime)               repairTime <--                liftParameter $-                randomExponential meanRepairTime-              holdProcess repairTime+                randomExponentialProcess meanRepairTime               machine       runProcessInStartTime machine
examples/MachRep2.hs view
@@ -48,9 +48,7 @@      let machine :: Process ()          machine =            do upTime <--                liftParameter $-                randomExponential meanUpTime-              holdProcess upTime+                randomExponentialProcess meanUpTime               liftEvent $                 modifyRef totalUpTime (+ upTime)                @@ -63,9 +61,7 @@                                requestResource repairPerson               repairTime <--                liftParameter $-                randomExponential meanRepairTime-              holdProcess repairTime+                randomExponentialProcess meanRepairTime               releaseResource repairPerson                              machine
examples/MachRep3.hs view
@@ -43,9 +43,7 @@      let machine :: ProcessId -> Process ()          machine pid =            do upTime <--                liftParameter $-                randomExponential meanUpTime-              holdProcess upTime+                randomExponentialProcess meanUpTime               liftEvent $                 modifyRef totalUpTime (+ upTime)                @@ -61,9 +59,7 @@                              requestResource repairPerson               repairTime <--                liftParameter $-                randomExponential meanRepairTime-              holdProcess repairTime+                randomExponentialProcess meanRepairTime               liftEvent $                 modifyRef nUp (+ 1)               releaseResource repairPerson
examples/MachineBreakdowns.hs view
@@ -16,6 +16,7 @@  import Simulation.Aivika import qualified Simulation.Aivika.Queue.Infinite as IQ+import qualified Simulation.Aivika.Resource.Preemption as PR  -- | The simulation specs. specs = Specs { spcStartTime = 0.0,@@ -48,123 +49,57 @@ -- | A mean of each of the three repair phases (Erlang). repairMu = 3/4 --- | It defines a job.-data Job = Job { jobProcessingTime :: Double,-                 -- ^ the job processing time defined when arriving.-                 jobRemainingTime :: Double-                 -- ^ the remaining processing time (may differ after return).-               }+-- | A priority of the job (less is higher)+jobPriority = 1 --- | Return the remaining job after interruption.-remainingJobInput :: ServerInterruption (Arrival Job) -> Arrival Job-remainingJobInput x = a'-  where-    t1 = serverStartProcessingTime x-    t2 = serverInterruptionTime x-    dt = t2 - t1-    a  = serverInterruptedInput x-    a' = a { arrivalValue = job' }-    job  = arrivalValue a-    job' = job { jobRemainingTime =-                    max 0 $ jobRemainingTime job - dt }+-- | A priority of the breakdown (less is higher)+breakdownPriority = 0 +-- | The simulation model. model :: Simulation Results model = do   -- create an input queue-  inputQueue <- runEventInStartTime IQ.newPriorityQueue+  inputQueue <- runEventInStartTime IQ.newFCFSQueue   -- a counter of jobs completed   jobsCompleted <- newArrivalTimer-  -- a counter of interrupted jobs but then returned for the further processing+  -- a counter of interrupted jobs   jobsInterrupted <- newRef (0 :: Int)   -- create an input stream   let inputStream =-        traceStream Nothing (Just "taking a job from the queue") $-        repeatProcess $ IQ.dequeue inputQueue-  -- create the setting up phase of processing+        randomExponentialStream jobArrivingMu+  -- create a preemptible resource+  tool <- PR.newResource 1+  -- the machine setting up   machineSettingUp <--    newInterruptibleServer True $ \a ->-    do -- set up the machine-       setUpTime <--         liftParameter $-         randomUniform minSetUpTime maxSetUpTime-       traceProcess "setting up the machine" $-         holdProcess setUpTime-       return a-  -- create the processing phase itself+    newPreemptibleRandomUniformServer True minSetUpTime maxSetUpTime+  -- the machine processing   machineProcessing <--    newInterruptibleServer True $ \a ->-    do -- process the job-       let job = arrivalValue a-       traceProcess "processing the job" $-         holdProcess $ jobRemainingTime job-       -- return the completed job-       return a { arrivalValue = job { jobRemainingTime = 0 } }-  -- enqueue the interrupted jobs again+    newPreemptibleRandomNormalServer True jobProcessingMu jobProcessingSigma+  -- the machine breakdown+  let machineBreakdown =+        do randomNormalProcess_ breakdownMu breakdownSigma+           PR.usingResourceWithPriority tool breakdownPriority $+             randomErlangProcess_ repairMu 3+           machineBreakdown+  -- start the process of breakdowns+  runProcessInStartTime machineBreakdown+  -- update a counter of job interruptions   runEventInStartTime $-    do handleSignal_ (serverTaskInterrupted machineSettingUp) $ \x ->-         traceEvent "returning the job..." $-         do let a = serverInterruptedInput x-                t = arrivalTime a-            IQ.enqueueWithStoringPriority inputQueue t a-       handleSignal_ (serverTaskInterrupted machineProcessing) $ \x ->-         traceEvent "interrupting the job..." $-         do let a = remainingJobInput x-                t = arrivalTime a-            modifyRef jobsInterrupted (+ 1)-            IQ.enqueueWithStoringPriority inputQueue t a-  let -- launch the machine tool again and again-      machineLaunch =-        joinProcessor $-        do spawnProcess $-             do -- breakdown the machine tool in time (a bound child process)-                breakdownTime <--                  liftParameter $-                  randomNormal breakdownMu breakdownSigma-                when (breakdownTime > 0) $-                  holdProcess breakdownTime-                traceProcess "breakdown" $-                  cancelProcess-           return $-             serverProcessor machineSettingUp >>>-             serverProcessor machineProcessing-      -- repair the machine tool-      machineRepair =-        do repairTime <- liftParameter $-                         randomErlang repairMu 3-           holdProcess repairTime-      -- launch after repairing the machine tool-      machineRepairAndLaunch =-        joinProcessor $-        do machineRepair-           traceProcess "repaired" $-             return machineLaunch-      -- machine loop-      machineLoop = machineLaunch : repeat machineRepairAndLaunch-      -- the network-      network = -        traceProcessor Nothing (Just "the job completed") $-        failoverProcessor machineLoop >>>+    handleSignal_ (serverTaskPreempting machineProcessing) $ \a ->+    modifyRef jobsInterrupted (+ 1)+  -- define the queue network+  let network = +        queueProcessor+        (\a -> liftEvent $ IQ.enqueue inputQueue a)+        (IQ.dequeue inputQueue) >>>+        (withinProcessor $ PR.requestResourceWithPriority tool jobPriority) >>>+        serverProcessor machineSettingUp >>>+        serverProcessor machineProcessing >>>+        (withinProcessor $ PR.releaseResource tool) >>>         arrivalTimerProcessor jobsCompleted   -- start the machine tool   runProcessInStartTime $     sinkStream $ runProcessor network inputStream-  -- model a stream of jobs-  let jobs =-        traceStream Nothing (Just "a new job") $-        randomExponentialStream jobArrivingMu-  -- start the processing of jobs by enqueueing them-  runProcessInStartTime $-    flip consumeStream jobs $ \a ->-    liftEvent $ do-      -- define the processing time for the job-      jobProcessingTime <--        liftParameter $-        randomNormal jobProcessingMu jobProcessingSigma-      -- enqueue the job-      let t0 = arrivalTime a-          dt = max 0 jobProcessingTime-      IQ.enqueueWithStoringPriority inputQueue t0 $-        a { arrivalValue = Job dt dt }   -- return the simulation results in start time   return $     results@@ -173,11 +108,11 @@      inputQueue,      --      resultSource-     "machineSettingUp" "the machine tool (the setting up phase)"+     "machineSettingUp" "the machine setting up"      machineSettingUp,      --      resultSource-     "machineProcessing" "the machine tool (the processing phase)"+     "machineProcessing" "the machine processing"      machineProcessing,      --      resultSource