packages feed

aivika 4.0.3 → 4.1

raw patch · 77 files changed

+1561/−220 lines, 77 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Simulation.Aivika.Ref.Plain: data Ref a
- Simulation.Aivika.Ref.Plain: modifyRef :: Ref a -> (a -> a) -> Event ()
- Simulation.Aivika.Ref.Plain: newRef :: a -> Simulation (Ref a)
- Simulation.Aivika.Ref.Plain: readRef :: Ref a -> Event a
- Simulation.Aivika.Ref.Plain: writeRef :: Ref a -> a -> Event ()
+ Simulation.Aivika.Ref.Base: data Ref a
+ Simulation.Aivika.Ref.Base: modifyRef :: Ref a -> (a -> a) -> Event ()
+ Simulation.Aivika.Ref.Base: newRef :: a -> Simulation (Ref a)
+ Simulation.Aivika.Ref.Base: readRef :: Ref a -> Event a
+ Simulation.Aivika.Ref.Base: writeRef :: Ref a -> a -> Event ()
+ Simulation.Aivika.Resource: decResourceCount :: EnqueueStrategy s => Resource s -> Int -> Process ()
+ Simulation.Aivika.Resource: resourceChanged_ :: Resource s -> Signal ()
+ Simulation.Aivika.Resource: resourceCountChanged :: Resource s -> Signal Int
+ Simulation.Aivika.Resource: resourceCountChanged_ :: Resource s -> Signal ()
+ Simulation.Aivika.Resource: resourceCountStats :: Resource s -> Event (TimingStats Int)
+ Simulation.Aivika.Resource: resourceUtilisationCount :: Resource s -> Event Int
+ Simulation.Aivika.Resource: resourceUtilisationCountChanged :: Resource s -> Signal Int
+ Simulation.Aivika.Resource: resourceUtilisationCountChanged_ :: Resource s -> Signal ()
+ Simulation.Aivika.Resource: resourceUtilisationCountStats :: Resource s -> Event (TimingStats Int)
+ Simulation.Aivika.Resource.Base: data Resource s
+ Simulation.Aivika.Resource.Base: decResourceCount :: EnqueueStrategy s => Resource s -> Int -> Process ()
+ Simulation.Aivika.Resource.Base: incResourceCount :: DequeueStrategy s => Resource s -> Int -> Event ()
+ Simulation.Aivika.Resource.Base: instance Eq (Resource s)
+ Simulation.Aivika.Resource.Base: newFCFSResource :: Int -> Simulation FCFSResource
+ Simulation.Aivika.Resource.Base: newFCFSResourceWithMaxCount :: Int -> Maybe Int -> Simulation FCFSResource
+ Simulation.Aivika.Resource.Base: newLCFSResource :: Int -> Simulation LCFSResource
+ Simulation.Aivika.Resource.Base: newLCFSResourceWithMaxCount :: Int -> Maybe Int -> Simulation LCFSResource
+ Simulation.Aivika.Resource.Base: newPriorityResource :: Int -> Simulation PriorityResource
+ Simulation.Aivika.Resource.Base: newPriorityResourceWithMaxCount :: Int -> Maybe Int -> Simulation PriorityResource
+ Simulation.Aivika.Resource.Base: newResource :: QueueStrategy s => s -> Int -> Simulation (Resource s)
+ Simulation.Aivika.Resource.Base: newResourceWithMaxCount :: QueueStrategy s => s -> Int -> Maybe Int -> Simulation (Resource s)
+ Simulation.Aivika.Resource.Base: newSIROResource :: Int -> Simulation SIROResource
+ Simulation.Aivika.Resource.Base: newSIROResourceWithMaxCount :: Int -> Maybe Int -> Simulation SIROResource
+ Simulation.Aivika.Resource.Base: releaseResource :: DequeueStrategy s => Resource s -> Process ()
+ Simulation.Aivika.Resource.Base: releaseResourceWithinEvent :: DequeueStrategy s => Resource s -> Event ()
+ Simulation.Aivika.Resource.Base: requestResource :: EnqueueStrategy s => Resource s -> Process ()
+ Simulation.Aivika.Resource.Base: requestResourceWithPriority :: PriorityQueueStrategy s p => Resource s -> p -> Process ()
+ Simulation.Aivika.Resource.Base: resourceCount :: Resource s -> Event Int
+ Simulation.Aivika.Resource.Base: resourceMaxCount :: Resource s -> Maybe Int
+ Simulation.Aivika.Resource.Base: resourceStrategy :: Resource s -> s
+ Simulation.Aivika.Resource.Base: tryRequestResourceWithinEvent :: Resource s -> Event Bool
+ Simulation.Aivika.Resource.Base: type FCFSResource = Resource FCFS
+ Simulation.Aivika.Resource.Base: type LCFSResource = Resource LCFS
+ Simulation.Aivika.Resource.Base: type PriorityResource = Resource StaticPriorities
+ Simulation.Aivika.Resource.Base: type SIROResource = Resource SIRO
+ Simulation.Aivika.Resource.Base: usingResource :: EnqueueStrategy s => Resource s -> Process a -> Process a
+ Simulation.Aivika.Resource.Base: usingResourceWithPriority :: PriorityQueueStrategy s p => Resource s -> p -> Process a -> Process a
+ Simulation.Aivika.Resource.Preemption: resourceChanged_ :: Resource -> Signal ()
+ Simulation.Aivika.Resource.Preemption: resourceCountChanged :: Resource -> Signal Int
+ Simulation.Aivika.Resource.Preemption: resourceCountChanged_ :: Resource -> Signal ()
+ Simulation.Aivika.Resource.Preemption: resourceCountStats :: Resource -> Event (TimingStats Int)
+ Simulation.Aivika.Resource.Preemption: resourceUtilisationCount :: Resource -> Event Int
+ Simulation.Aivika.Resource.Preemption: resourceUtilisationCountChanged :: Resource -> Signal Int
+ Simulation.Aivika.Resource.Preemption: resourceUtilisationCountChanged_ :: Resource -> Signal ()
+ Simulation.Aivika.Resource.Preemption: resourceUtilisationCountStats :: Resource -> Event (TimingStats Int)
+ Simulation.Aivika.Resource.Preemption.Base: alterResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption.Base: data Resource
+ Simulation.Aivika.Resource.Preemption.Base: decResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption.Base: incResourceCount :: Resource -> Int -> Event ()
+ Simulation.Aivika.Resource.Preemption.Base: instance Eq Resource
+ Simulation.Aivika.Resource.Preemption.Base: instance Eq ResourceActingItem
+ Simulation.Aivika.Resource.Preemption.Base: newResource :: Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption.Base: newResourceWithMaxCount :: Int -> Maybe Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption.Base: releaseResource :: Resource -> Process ()
+ Simulation.Aivika.Resource.Preemption.Base: requestResourceWithPriority :: Resource -> Double -> Process ()
+ Simulation.Aivika.Resource.Preemption.Base: resourceCount :: Resource -> Event Int
+ Simulation.Aivika.Resource.Preemption.Base: resourceMaxCount :: Resource -> Maybe Int
+ Simulation.Aivika.Resource.Preemption.Base: usingResourceWithPriority :: Resource -> Double -> Process a -> Process a
+ Simulation.Aivika.Results: instance (Show s, ResultItemable (ResultValue s)) => ResultProvider (Resource s)
+ Simulation.Aivika.Results: instance ResultProvider Resource
+ Simulation.Aivika.Results.Locale: ResourceCountId :: ResultId
+ Simulation.Aivika.Results.Locale: ResourceCountStatsId :: ResultId
+ Simulation.Aivika.Results.Locale: ResourceId :: ResultId
+ Simulation.Aivika.Results.Locale: ResourceUtilisationCountId :: ResultId
+ Simulation.Aivika.Results.Locale: ResourceUtilisationCountStatsId :: ResultId
- Simulation.Aivika.Resource: newFCFSResource :: Int -> Simulation FCFSResource
+ Simulation.Aivika.Resource: newFCFSResource :: Int -> Event FCFSResource
- Simulation.Aivika.Resource: newFCFSResourceWithMaxCount :: Int -> Maybe Int -> Simulation FCFSResource
+ Simulation.Aivika.Resource: newFCFSResourceWithMaxCount :: Int -> Maybe Int -> Event FCFSResource
- Simulation.Aivika.Resource: newLCFSResource :: Int -> Simulation LCFSResource
+ Simulation.Aivika.Resource: newLCFSResource :: Int -> Event LCFSResource
- Simulation.Aivika.Resource: newLCFSResourceWithMaxCount :: Int -> Maybe Int -> Simulation LCFSResource
+ Simulation.Aivika.Resource: newLCFSResourceWithMaxCount :: Int -> Maybe Int -> Event LCFSResource
- Simulation.Aivika.Resource: newPriorityResource :: Int -> Simulation PriorityResource
+ Simulation.Aivika.Resource: newPriorityResource :: Int -> Event PriorityResource
- Simulation.Aivika.Resource: newPriorityResourceWithMaxCount :: Int -> Maybe Int -> Simulation PriorityResource
+ Simulation.Aivika.Resource: newPriorityResourceWithMaxCount :: Int -> Maybe Int -> Event PriorityResource
- Simulation.Aivika.Resource: newResource :: QueueStrategy s => s -> Int -> Simulation (Resource s)
+ Simulation.Aivika.Resource: newResource :: QueueStrategy s => s -> Int -> Event (Resource s)
- Simulation.Aivika.Resource: newResourceWithMaxCount :: QueueStrategy s => s -> Int -> Maybe Int -> Simulation (Resource s)
+ Simulation.Aivika.Resource: newResourceWithMaxCount :: QueueStrategy s => s -> Int -> Maybe Int -> Event (Resource s)
- Simulation.Aivika.Resource: newSIROResource :: Int -> Simulation SIROResource
+ Simulation.Aivika.Resource: newSIROResource :: Int -> Event SIROResource
- Simulation.Aivika.Resource: newSIROResourceWithMaxCount :: Int -> Maybe Int -> Simulation SIROResource
+ Simulation.Aivika.Resource: newSIROResourceWithMaxCount :: Int -> Maybe Int -> Event SIROResource
- Simulation.Aivika.Resource.Preemption: newResource :: Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption: newResource :: Int -> Event Resource
- Simulation.Aivika.Resource.Preemption: newResourceWithMaxCount :: Int -> Maybe Int -> Simulation Resource
+ Simulation.Aivika.Resource.Preemption: newResourceWithMaxCount :: Int -> Maybe Int -> Event Resource

Files

Simulation/Aivika.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module re-exports the most part of the library functionality. -- But there are modules that must be imported explicitly.@@ -35,7 +35,7 @@         module Simulation.Aivika.Processor.RoundRobbin,         module Simulation.Aivika.QueueStrategy,         module Simulation.Aivika.Ref,-        module Simulation.Aivika.Resource,+        module Simulation.Aivika.Resource.Base,         module Simulation.Aivika.Results,         module Simulation.Aivika.Results.Locale,         module Simulation.Aivika.Results.IO,@@ -77,7 +77,7 @@ import Simulation.Aivika.Processor.RoundRobbin import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Ref-import Simulation.Aivika.Resource+import Simulation.Aivika.Resource.Base import Simulation.Aivika.Results import Simulation.Aivika.Results.Locale import Simulation.Aivika.Results.IO
Simulation/Aivika/Activity.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It models an activity that can be utilised. The activity is similar to a 'Server' -- but destined for simulation within 'Net' computation.@@ -72,7 +72,6 @@ import Simulation.Aivika.Dynamics import Simulation.Aivika.Internal.Event import Simulation.Aivika.Signal-import Simulation.Aivika.Resource import Simulation.Aivika.Cont import Simulation.Aivika.Process import Simulation.Aivika.Net@@ -505,11 +504,11 @@ activityUtilised :: Activity s a b -> Signal (a, b) activityUtilised = publishSignal . activityUtilisedSource --- | Raised when the task utilisation by the activity was preempted.+-- | Raised when the activity utilisation was preempted. activityPreemptionBeginning :: Activity s a b -> Signal a activityPreemptionBeginning = publishSignal . activityPreemptionBeginningSource --- | Raised when the task utilisation by the activity was proceeded after it had been preempted earlier.+-- | Raised when the activity utilisation was proceeded after it had been preempted earlier. activityPreemptionEnding :: Activity s a b -> Signal a activityPreemptionEnding = publishSignal . activityPreemptionEndingSource 
Simulation/Aivika/Activity/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines some useful predefined activities that -- hold the current process for the corresponding random time
Simulation/Aivika/Agent.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module introduces basic entities for the agent-based modeling. --
Simulation/Aivika/Arrival.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the types and functions for working with the events -- that can represent something that arrive from outside the model, or
Simulation/Aivika/Circuit.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It represents a circuit synchronized with the event queue. -- Also it allows creating the recursive links with help of
Simulation/Aivika/Cont.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The 'Cont' monad is a variation of the standard Cont monad  -- and F# async workflow, where the result of applying 
Simulation/Aivika/DoubleLinkedList.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- An imperative double-linked list. --
Simulation/Aivika/Dynamics.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines the 'Dynamics' monad representing a time varying polymorphic function.  --
Simulation/Aivika/Dynamics/Extra.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines auxiliary functions such as interpolation ones -- that complement the memoization, for example. There are scan functions too.
Simulation/Aivika/Dynamics/Memo.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines memo functions. The memoization creates such 'Dynamics' -- computations, which values are cached in the integration time points. Then
Simulation/Aivika/Dynamics/Memo/Unboxed.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the unboxed memo functions. The memoization creates such 'Dynamics' -- computations, which values are cached in the integration time points. Then
Simulation/Aivika/Dynamics/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the random functions that always return the same values -- in the integration time points within a single simulation run. The values
Simulation/Aivika/Event.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines the 'Event' monad which is very similar to the 'Dynamics' -- monad but only now the computation is strongly synchronized with the event queue.
Simulation/Aivika/Generator.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- Below is defined a type class of the random number generator. --
Simulation/Aivika/Internal/Arrival.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the types and functions for working with the events -- that can represent something that arrive from outside the model, or
Simulation/Aivika/Internal/Cont.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Dynamics.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Event.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Parameter.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Process.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Simulation.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This is an internal implementation module that should never be used directly. --
Simulation/Aivika/Internal/Specs.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It defines the simulation specs and related stuff. module Simulation.Aivika.Internal.Specs
Simulation/Aivika/Net.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines a 'Net' arrow that can be applied to modeling the queue networks -- like the 'Processor' arrow from another module. Only the former has a more efficient@@ -60,7 +60,7 @@ import Simulation.Aivika.Process import Simulation.Aivika.Stream import Simulation.Aivika.QueueStrategy-import Simulation.Aivika.Resource+import Simulation.Aivika.Resource.Base import Simulation.Aivika.Processor import Simulation.Aivika.Ref import Simulation.Aivika.Circuit
Simulation/Aivika/Net/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines some useful random network computations that -- hold the current process for the corresponding time interval,
Simulation/Aivika/Parameter.hs view
@@ -4,7 +4,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines the 'Parameter' monad that allows representing the model -- parameters. For example, they can be used when running the Monte-Carlo simulation.
Simulation/Aivika/Parameter/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the random parameters of simulation experiments. --
Simulation/Aivika/PriorityQueue.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- An imperative heap-based priority queue. --
Simulation/Aivika/Process.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- A value in the 'Process' monad represents a discontinuous process that  -- can suspend in any simulation time point and then resume later in the same 
Simulation/Aivika/Process/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines helper functions, which are useful to hold  -- the 'Process' computation for a time interval according to some
Simulation/Aivika/Processor.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The processor of simulation data. --
Simulation/Aivika/Processor/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines some useful random processors that -- hold the current process for the corresponding time interval,
Simulation/Aivika/Processor/RoundRobbin.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines the Round-Robbin processor. --
Simulation/Aivika/Queue.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines a queue that can use the specified strategies. So, having only -- the 'FCFS', 'LCFS', 'SIRO' and 'StaticPriorities' strategies, you can build@@ -117,7 +117,7 @@ import Simulation.Aivika.Internal.Event import Simulation.Aivika.Internal.Process import Simulation.Aivika.Signal-import Simulation.Aivika.Resource+import Simulation.Aivika.Resource.Base import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Statistics 
Simulation/Aivika/Queue/Infinite.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines an infinite queue that can use the specified strategies. --@@ -81,7 +81,7 @@ import Simulation.Aivika.Internal.Event import Simulation.Aivika.Internal.Process import Simulation.Aivika.Signal-import Simulation.Aivika.Resource+import Simulation.Aivika.Resource.Base import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Statistics 
Simulation/Aivika/QueueStrategy.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the queue strategies. --
Simulation/Aivika/Ref.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines an updatable reference that depends on the event queue. --
+ Simulation/Aivika/Ref/Base.hs view
@@ -0,0 +1,53 @@++-- |+-- Module     : Simulation.Aivika.Ref.Base+-- 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.10.1+--+-- This module defines a light-weight and more fast version of an updatable reference+-- that depends on the event queue but that doesn't supply with the signal notification.+--+module Simulation.Aivika.Ref.Base+       (Ref,+        newRef,+        readRef,+        writeRef,+        modifyRef) where++import Data.IORef+import Control.Monad+import Control.Monad.Trans++import Simulation.Aivika.Internal.Simulation+import Simulation.Aivika.Internal.Event++-- | The 'Ref' type represents a mutable variable similar to the 'IORef' variable +-- but only dependent on the event queue, which allows synchronizing the reference+-- with the model explicitly through the 'Event' monad.+newtype Ref a = +  Ref { refValue :: IORef a }++-- | Create a new reference.+newRef :: a -> Simulation (Ref a)+newRef a =+  do x <- liftIO $ newIORef a+     return Ref { refValue = x }+     +-- | Read the value of a reference.+readRef :: Ref a -> Event a+readRef r = Event $ \p -> readIORef (refValue r)++-- | Write a new value into the reference.+writeRef :: Ref a -> a -> Event ()+writeRef r a = Event $ \p -> +  a `seq` writeIORef (refValue r) a++-- | Mutate the contents of the reference.+modifyRef :: Ref a -> (a -> a) -> Event ()+modifyRef r f = Event $ \p -> +  do a <- readIORef (refValue r)+     let b = f a+     b `seq` writeIORef (refValue r) b
− Simulation/Aivika/Ref/Plain.hs
@@ -1,53 +0,0 @@---- |--- Module     : Simulation.Aivika.Ref.Plain--- 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 a light-weight and more fast version of an updatable reference--- that depends on the event queue but that doesn't supply with the signal notification.----module Simulation.Aivika.Ref.Plain-       (Ref,-        newRef,-        readRef,-        writeRef,-        modifyRef) where--import Data.IORef-import Control.Monad-import Control.Monad.Trans--import Simulation.Aivika.Internal.Simulation-import Simulation.Aivika.Internal.Event---- | The 'Ref' type represents a mutable variable similar to the 'IORef' variable --- but only dependent on the event queue, which allows synchronizing the reference--- with the model explicitly through the 'Event' monad.-newtype Ref a = -  Ref { refValue :: IORef a }---- | Create a new reference.-newRef :: a -> Simulation (Ref a)-newRef a =-  do x <- liftIO $ newIORef a-     return Ref { refValue = x }-     --- | Read the value of a reference.-readRef :: Ref a -> Event a-readRef r = Event $ \p -> readIORef (refValue r)---- | Write a new value into the reference.-writeRef :: Ref a -> a -> Event ()-writeRef r a = Event $ \p -> -  a `seq` writeIORef (refValue r) a---- | Mutate the contents of the reference.-modifyRef :: Ref a -> (a -> a) -> Event ()-modifyRef r f = Event $ \p -> -  do a <- readIORef (refValue r)-     let b = f a-     b `seq` writeIORef (refValue r) b
Simulation/Aivika/Resource.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the resource which can be acquired and  -- then released by the discontinuous process 'Process'.@@ -35,6 +35,9 @@         resourceStrategy,         resourceMaxCount,         resourceCount,+        resourceCountStats,+        resourceUtilisationCount,+        resourceUtilisationCountStats,         -- * Requesting for and Releasing Resource         requestResource,         requestResourceWithPriority,@@ -44,9 +47,18 @@         usingResource,         usingResourceWithPriority,         -- * Altering Resource-        incResourceCount) where+        incResourceCount,+        decResourceCount,+        -- * Signals+        resourceCountChanged,+        resourceCountChanged_,+        resourceUtilisationCountChanged,+        resourceUtilisationCountChanged_,+        resourceChanged_) where  import Data.IORef+import Data.Monoid+ import Control.Monad import Control.Monad.Trans import Control.Exception@@ -57,6 +69,8 @@ import Simulation.Aivika.Internal.Cont import Simulation.Aivika.Internal.Process import Simulation.Aivika.QueueStrategy+import Simulation.Aivika.Statistics+import Simulation.Aivika.Signal  import qualified Simulation.Aivika.DoubleLinkedList as DLL  import qualified Simulation.Aivika.Vector as V@@ -81,7 +95,12 @@              resourceMaxCount :: Maybe Int,              -- ^ Return the maximum count of the resource, where 'Nothing'              -- means that the resource has no upper bound.-             resourceCountRef :: IORef Int, +             resourceCountRef :: IORef Int,+             resourceCountStatsRef :: IORef (TimingStats Int),+             resourceCountSource :: SignalSource Int,+             resourceUtilisationCountRef :: IORef Int,+             resourceUtilisationCountStatsRef :: IORef (TimingStats Int),+             resourceUtilisationCountSource :: SignalSource Int,              resourceWaitList :: StrategyQueue s (FrozenCont ()) }  instance Eq (Resource s) where@@ -91,7 +110,7 @@ -- the upper bound as well. newFCFSResource :: Int                    -- ^ the initial count (and maximal count too) of the resource-                   -> Simulation FCFSResource+                   -> Event FCFSResource newFCFSResource = newResource FCFS  -- | Create a new FCFS resource with the specified initial and maximum counts,@@ -100,14 +119,14 @@                                -- ^ the initial count of the resource                                -> Maybe Int                                -- ^ the maximum count of the resource, which can be indefinite-                               -> Simulation FCFSResource+                               -> Event FCFSResource newFCFSResourceWithMaxCount = newResourceWithMaxCount FCFS  -- | Create a new LCFS resource with the specified initial count which value becomes -- the upper bound as well. newLCFSResource :: Int                    -- ^ the initial count (and maximal count too) of the resource-                   -> Simulation LCFSResource+                   -> Event LCFSResource newLCFSResource = newResource LCFS  -- | Create a new LCFS resource with the specified initial and maximum counts,@@ -116,14 +135,14 @@                                -- ^ the initial count of the resource                                -> Maybe Int                                -- ^ the maximum count of the resource, which can be indefinite-                               -> Simulation LCFSResource+                               -> Event LCFSResource newLCFSResourceWithMaxCount = newResourceWithMaxCount LCFS  -- | Create a new SIRO resource with the specified initial count which value becomes -- the upper bound as well. newSIROResource :: Int                    -- ^ the initial count (and maximal count too) of the resource-                   -> Simulation SIROResource+                   -> Event SIROResource newSIROResource = newResource SIRO  -- | Create a new SIRO resource with the specified initial and maximum counts,@@ -132,14 +151,14 @@                                -- ^ the initial count of the resource                                -> Maybe Int                                -- ^ the maximum count of the resource, which can be indefinite-                               -> Simulation SIROResource+                               -> Event SIROResource newSIROResourceWithMaxCount = newResourceWithMaxCount SIRO  -- | Create a new priority resource with the specified initial count which value becomes -- the upper bound as well. newPriorityResource :: Int                        -- ^ the initial count (and maximal count too) of the resource-                       -> Simulation PriorityResource+                       -> Event PriorityResource newPriorityResource = newResource StaticPriorities  -- | Create a new priority resource with the specified initial and maximum counts,@@ -148,7 +167,7 @@                                    -- ^ the initial count of the resource                                    -> Maybe Int                                    -- ^ the maximum count of the resource, which can be indefinite-                                   -> Simulation PriorityResource+                                   -> Event PriorityResource newPriorityResourceWithMaxCount = newResourceWithMaxCount StaticPriorities  -- | Create a new resource with the specified queue strategy and initial count.@@ -158,18 +177,30 @@                -- ^ the strategy for managing the queuing requests                -> Int                -- ^ the initial count (and maximal count too) of the resource-               -> Simulation (Resource s)+               -> Event (Resource s) newResource s count =-  Simulation $ \r ->-  do when (count < 0) $+  Event $ \p ->+  do let r = pointRun p+         t = pointTime p+     when (count < 0) $        error $        "The resource count cannot be negative: " ++        "newResource."      countRef <- newIORef count+     countStatsRef <- newIORef $ returnTimingStats t count+     countSource <- invokeSimulation r newSignalSource +     utilCountRef <- newIORef 0+     utilCountStatsRef <- newIORef $ returnTimingStats t 0+     utilCountSource <- invokeSimulation r newSignalSource       waitList <- invokeSimulation r $ newStrategyQueue s      return Resource { resourceStrategy = s,                        resourceMaxCount = Just count,                        resourceCountRef = countRef,+                       resourceCountStatsRef = countStatsRef,+                       resourceCountSource = countSource,+                       resourceUtilisationCountRef = utilCountRef,+                       resourceUtilisationCountStatsRef = utilCountStatsRef,+                       resourceUtilisationCountSource = utilCountSource,                        resourceWaitList = waitList }  -- | Create a new resource with the specified queue strategy, initial and maximum counts,@@ -181,10 +212,12 @@                            -- ^ the initial count of the resource                            -> Maybe Int                            -- ^ the maximum count of the resource, which can be indefinite-                           -> Simulation (Resource s)+                           -> Event (Resource s) newResourceWithMaxCount s count maxCount =-  Simulation $ \r ->-  do when (count < 0) $+  Event $ \p ->+  do let r = pointRun p+         t = pointTime p+     when (count < 0) $        error $        "The resource count cannot be negative: " ++        "newResourceWithMaxCount."@@ -196,17 +229,62 @@        _ ->          return ()      countRef <- newIORef count+     countStatsRef <- newIORef $ returnTimingStats t count+     countSource <- invokeSimulation r newSignalSource+     utilCountRef <- newIORef 0+     utilCountStatsRef <- newIORef $ returnTimingStats t 0+     utilCountSource <- invokeSimulation r newSignalSource      waitList <- invokeSimulation r $ newStrategyQueue s      return Resource { resourceStrategy = s,                        resourceMaxCount = maxCount,                        resourceCountRef = countRef,+                       resourceCountStatsRef = countStatsRef,+                       resourceCountSource = countSource,+                       resourceUtilisationCountRef = utilCountRef,+                       resourceUtilisationCountStatsRef = utilCountStatsRef,+                       resourceUtilisationCountSource = utilCountSource,                        resourceWaitList = waitList } --- | Return the current count of the resource.+-- | Return the current available count of the resource. resourceCount :: Resource s -> Event Int resourceCount r =   Event $ \p -> readIORef (resourceCountRef r) +-- | Return the statistics for the available count of the resource.+resourceCountStats :: Resource s -> Event (TimingStats Int)+resourceCountStats r =+  Event $ \p -> readIORef (resourceCountStatsRef r)++-- | Signal triggered when the 'resourceCount' property changes.+resourceCountChanged :: Resource s -> Signal Int+resourceCountChanged r =+  publishSignal $ resourceCountSource r++-- | Signal triggered when the 'resourceCount' property changes.+resourceCountChanged_ :: Resource s -> Signal ()+resourceCountChanged_ r =+  mapSignal (const ()) $ resourceCountChanged r++-- | Return the current utilisation count of the resource.+resourceUtilisationCount :: Resource s -> Event Int+resourceUtilisationCount r =+  Event $ \p -> readIORef (resourceUtilisationCountRef r)++-- | Return the statistics for the utilisation count of the resource.+resourceUtilisationCountStats :: Resource s -> Event (TimingStats Int)+resourceUtilisationCountStats r =+  Event $ \p -> readIORef (resourceUtilisationCountStatsRef r)++-- | Signal triggered when the 'resourceUtilisationCount' property changes.+resourceUtilisationCountChanged :: Resource s -> Signal Int+resourceUtilisationCountChanged r =+  publishSignal $ resourceUtilisationCountSource r++-- | Signal triggered when the 'resourceUtilisationCount' property changes.+resourceUtilisationCountChanged_ :: Resource s -> Signal ()+resourceUtilisationCountChanged_ r =+  mapSignal (const ()) $ resourceUtilisationCountChanged r+ -- | Request for the resource decreasing its count in case of success, -- otherwise suspending the discontinuous process until some other  -- process releases the resource.@@ -227,8 +305,8 @@                     requestResource r                invokeEvent p $                  strategyEnqueue (resourceWaitList r) c-       else do let a' = a - 1-               a' `seq` writeIORef (resourceCountRef r) a'+       else do invokeEvent p $ updateResourceCount r (-1)+               invokeEvent p $ updateResourceUtilisationCount r 1                invokeEvent p $ resumeCont c ()  -- | Request with the priority for the resource decreasing its count@@ -253,8 +331,8 @@                     requestResourceWithPriority r priority                invokeEvent p $                  strategyEnqueueWithPriority (resourceWaitList r) priority c-       else do let a' = a - 1-               a' `seq` writeIORef (resourceCountRef r) a'+       else do invokeEvent p $ updateResourceCount r (-1)+               invokeEvent p $ updateResourceUtilisationCount r 1                invokeEvent p $ resumeCont c ()  -- | Release the resource increasing its count and resuming one of the@@ -278,27 +356,38 @@                               -> Event () releaseResourceWithinEvent r =   Event $ \p ->+  do invokeEvent p $ updateResourceUtilisationCount r (-1)+     invokeEvent p $ releaseResource' r+  +-- | Release the resource without affecting its utilisation.+releaseResource' :: DequeueStrategy s+                    => Resource s+                    -- ^ 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."+         "its maximum value: releaseResource'."        _ ->          return ()      f <- invokeEvent p $           strategyQueueNull (resourceWaitList r)      if f -       then a' `seq` writeIORef (resourceCountRef r) a'+       then invokeEvent p $ updateResourceCount r 1        else do c <- invokeEvent p $                     strategyDequeue (resourceWaitList r)                c <- invokeEvent p $ unfreezeCont c                case c of                  Nothing ->-                   invokeEvent p $ releaseResourceWithinEvent r+                   invokeEvent p $ releaseResource' r                  Just c  ->-                   invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()+                   do invokeEvent p $ updateResourceUtilisationCount r 1+                      invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()  -- | Try to request for the resource decreasing its count in case of success -- and returning 'True' in the 'Event' monad; otherwise, returning 'False'.@@ -310,8 +399,8 @@   do a <- readIORef (resourceCountRef r)      if a == 0         then return False-       else do let a' = a - 1-               a' `seq` writeIORef (resourceCountRef r) a'+       else do invokeEvent p $ updateResourceCount r (-1)+               invokeEvent p $ updateResourceUtilisationCount r 1                return True                 -- | Acquire the resource, perform some action and safely release the resource               @@ -344,6 +433,16 @@   do requestResourceWithPriority r priority      finallyProcess m $ releaseResource r +-- | Decrease the count of available resource.+decResourceCount' :: EnqueueStrategy s+                     => Resource s+                     -- ^ the resource for which to decrease the count+                     -> Process ()+decResourceCount' r =+  do liftEvent $+       updateResourceUtilisationCount r (-1)+     requestResource r+                    -- | Increase the count of available resource by the specified number, -- invoking the awaiting processes as needed. incResourceCount :: DequeueStrategy s@@ -356,6 +455,50 @@   | n < 0     = error "The increment cannot be negative: incResourceCount"   | n == 0    = return ()   | otherwise =-    do releaseResourceWithinEvent r+    do releaseResource' r        incResourceCount r (n - 1) +-- | Decrease the count of available resource by the specified number,+-- waiting for the processes capturing the resource as needed.+decResourceCount :: EnqueueStrategy s+                    => Resource s+                    -- ^ the resource+                    -> Int+                    -- ^ the decrement for the resource count+                    -> Process ()+decResourceCount r n+  | n < 0     = error "The decrement cannot be negative: decResourceCount"+  | n == 0    = return ()+  | otherwise =+    do decResourceCount' r+       decResourceCount r (n - 1)++-- | Signal triggered when one of the resource counters changes.+resourceChanged_ :: Resource s -> Signal ()+resourceChanged_ r =+  resourceCountChanged_ r <>+  resourceUtilisationCountChanged_ r++-- | Update the resource count and its statistics.+updateResourceCount :: Resource s -> Int -> Event ()+updateResourceCount r delta =+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     let a' = a + delta+     a' `seq` writeIORef (resourceCountRef r) a'+     modifyIORef' (resourceCountStatsRef r) $+       addTimingStats (pointTime p) a'+     invokeEvent p $+       triggerSignal (resourceCountSource r) a'++-- | Update the resource utilisation count and its statistics.+updateResourceUtilisationCount :: Resource s -> Int -> Event ()+updateResourceUtilisationCount r delta =+  Event $ \p ->+  do a <- readIORef (resourceUtilisationCountRef r)+     let a' = a + delta+     a' `seq` writeIORef (resourceUtilisationCountRef r) a'+     modifyIORef' (resourceUtilisationCountStatsRef r) $+       addTimingStats (pointTime p) a'+     invokeEvent p $+       triggerSignal (resourceUtilisationCountSource r) a'
+ Simulation/Aivika/Resource/Base.hs view
@@ -0,0 +1,381 @@++-- |+-- Module     : Simulation.Aivika.Resource.Base+-- 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.10.1+--+-- This module defines an optimised version of the resource +-- which can be acquired and then released by the discontinuous +-- process 'Process'. The resource can be either limited by +-- the upper bound (run-time check), or it can have no upper bound. +-- The latter is useful for modeling the infinite queue, for example.+--+-- The module is optimised in the sense that this kind of the resource+-- has neither additional signals, nor counters that would may slow+-- down the simulation.+--+module Simulation.Aivika.Resource.Base+       (-- * Resource Types+        FCFSResource,+        LCFSResource,+        SIROResource,+        PriorityResource,+        Resource,+        -- * Creating Resource+        newFCFSResource,+        newFCFSResourceWithMaxCount,+        newLCFSResource,+        newLCFSResourceWithMaxCount,+        newSIROResource,+        newSIROResourceWithMaxCount,+        newPriorityResource,+        newPriorityResourceWithMaxCount,+        newResource,+        newResourceWithMaxCount,+        -- * Resource Properties+        resourceStrategy,+        resourceMaxCount,+        resourceCount,+        -- * Requesting for and Releasing Resource+        requestResource,+        requestResourceWithPriority,+        tryRequestResourceWithinEvent,+        releaseResource,+        releaseResourceWithinEvent,+        usingResource,+        usingResourceWithPriority,+        -- * Altering Resource+        incResourceCount,+        decResourceCount) 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.DoubleLinkedList as DLL +import qualified Simulation.Aivika.Vector as V+import qualified Simulation.Aivika.PriorityQueue as PQ++-- | The ordinary FCFS (First Come - First Serviced) resource.+type FCFSResource = Resource FCFS++-- | The ordinary LCFS (Last Come - First Serviced) resource.+type LCFSResource = Resource LCFS++-- | The SIRO (Serviced in Random Order) resource.+type SIROResource = Resource SIRO++-- | The resource with static priorities.+type PriorityResource = Resource StaticPriorities++-- | Represents the resource with strategy @s@ applied for queuing the requests.+data Resource s = +  Resource { resourceStrategy :: s,+             -- ^ Return the strategy applied for queuing the requests.+             resourceMaxCount :: Maybe Int,+             -- ^ Return the maximum count of the resource, where 'Nothing'+             -- means that the resource has no upper bound.+             resourceCountRef :: IORef Int, +             resourceWaitList :: StrategyQueue s (FrozenCont ()) }++instance Eq (Resource s) where+  x == y = resourceCountRef x == resourceCountRef y  -- unique references++-- | Create a new FCFS resource with the specified initial count which value becomes+-- the upper bound as well.+newFCFSResource :: Int+                   -- ^ the initial count (and maximal count too) of the resource+                   -> Simulation FCFSResource+newFCFSResource = newResource FCFS++-- | Create a new FCFS resource with the specified initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newFCFSResourceWithMaxCount :: Int+                               -- ^ the initial count of the resource+                               -> Maybe Int+                               -- ^ the maximum count of the resource, which can be indefinite+                               -> Simulation FCFSResource+newFCFSResourceWithMaxCount = newResourceWithMaxCount FCFS++-- | Create a new LCFS resource with the specified initial count which value becomes+-- the upper bound as well.+newLCFSResource :: Int+                   -- ^ the initial count (and maximal count too) of the resource+                   -> Simulation LCFSResource+newLCFSResource = newResource LCFS++-- | Create a new LCFS resource with the specified initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newLCFSResourceWithMaxCount :: Int+                               -- ^ the initial count of the resource+                               -> Maybe Int+                               -- ^ the maximum count of the resource, which can be indefinite+                               -> Simulation LCFSResource+newLCFSResourceWithMaxCount = newResourceWithMaxCount LCFS++-- | Create a new SIRO resource with the specified initial count which value becomes+-- the upper bound as well.+newSIROResource :: Int+                   -- ^ the initial count (and maximal count too) of the resource+                   -> Simulation SIROResource+newSIROResource = newResource SIRO++-- | Create a new SIRO resource with the specified initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newSIROResourceWithMaxCount :: Int+                               -- ^ the initial count of the resource+                               -> Maybe Int+                               -- ^ the maximum count of the resource, which can be indefinite+                               -> Simulation SIROResource+newSIROResourceWithMaxCount = newResourceWithMaxCount SIRO++-- | Create a new priority resource with the specified initial count which value becomes+-- the upper bound as well.+newPriorityResource :: Int+                       -- ^ the initial count (and maximal count too) of the resource+                       -> Simulation PriorityResource+newPriorityResource = newResource StaticPriorities++-- | Create a new priority resource with the specified initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newPriorityResourceWithMaxCount :: Int+                                   -- ^ the initial count of the resource+                                   -> Maybe Int+                                   -- ^ the maximum count of the resource, which can be indefinite+                                   -> Simulation PriorityResource+newPriorityResourceWithMaxCount = newResourceWithMaxCount StaticPriorities++-- | Create a new resource with the specified queue strategy and initial count.+-- The last value becomes the upper bound as well.+newResource :: QueueStrategy s+               => s+               -- ^ the strategy for managing the queuing requests+               -> Int+               -- ^ the initial count (and maximal count too) of the resource+               -> Simulation (Resource s)+newResource s count =+  Simulation $ \r ->+  do when (count < 0) $+       error $+       "The resource count cannot be negative: " +++       "newResource."+     countRef <- newIORef count+     waitList <- invokeSimulation r $ newStrategyQueue s+     return Resource { resourceStrategy = s,+                       resourceMaxCount = Just count,+                       resourceCountRef = countRef,+                       resourceWaitList = waitList }++-- | Create a new resource with the specified queue strategy, initial and maximum counts,+-- where 'Nothing' means that the resource has no upper bound.+newResourceWithMaxCount :: QueueStrategy s+                           => s+                           -- ^ the strategy for managing the queuing requests+                           -> Int+                           -- ^ the initial count of the resource+                           -> Maybe Int+                           -- ^ the maximum count of the resource, which can be indefinite+                           -> Simulation (Resource s)+newResourceWithMaxCount s 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+     waitList <- invokeSimulation r $ newStrategyQueue s+     return Resource { resourceStrategy = s,+                       resourceMaxCount = maxCount,+                       resourceCountRef = countRef,+                       resourceWaitList = waitList }++-- | Return the current count of the resource.+resourceCount :: Resource s -> Event Int+resourceCount r =+  Event $ \p -> readIORef (resourceCountRef r)++-- | Request for the resource decreasing its count in case of success,+-- otherwise suspending the discontinuous process until some other +-- process releases the resource.+requestResource :: EnqueueStrategy s+                   => Resource s+                   -- ^ the requested resource+                   -> Process ()+requestResource r =+  Process $ \pid ->+  Cont $ \c ->+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     if a == 0 +       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+               a' `seq` writeIORef (resourceCountRef r) a'+               invokeEvent p $ resumeCont c ()++-- | 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.+requestResourceWithPriority :: PriorityQueueStrategy s p+                               => Resource s+                               -- ^ the requested resource+                               -> p+                               -- ^ the priority+                               -> Process ()+requestResourceWithPriority r priority =+  Process $ \pid ->+  Cont $ \c ->+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     if a == 0 +       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+               a' `seq` writeIORef (resourceCountRef r) a'+               invokeEvent p $ resumeCont c ()++-- | Release the resource increasing its count and resuming one of the+-- previously suspended processes as possible.+releaseResource :: DequeueStrategy s+                   => Resource s+                   -- ^ the resource to release+                   -> Process ()+releaseResource r = +  Process $ \_ ->+  Cont $ \c ->+  Event $ \p ->+  do invokeEvent p $ releaseResourceWithinEvent r+     invokeEvent p $ resumeCont c ()++-- | Release the resource increasing its count and resuming one of the+-- previously suspended processes as possible.+releaseResourceWithinEvent :: DequeueStrategy s+                              => Resource s+                              -- ^ the resource to release+                              -> Event ()+releaseResourceWithinEvent 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 <- invokeEvent p $+          strategyQueueNull (resourceWaitList r)+     if f +       then a' `seq` writeIORef (resourceCountRef r) a'+       else do c <- invokeEvent p $+                    strategyDequeue (resourceWaitList r)+               c <- invokeEvent p $ unfreezeCont c+               case c of+                 Nothing ->+                   invokeEvent p $ releaseResourceWithinEvent r+                 Just c  ->+                   invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()++-- | Try to request for the resource decreasing its count in case of success+-- and returning 'True' in the 'Event' monad; otherwise, returning 'False'.+tryRequestResourceWithinEvent :: Resource s+                                 -- ^ the resource which we try to request for+                                 -> Event Bool+tryRequestResourceWithinEvent r =+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     if a == 0 +       then return False+       else do let a' = a - 1+               a' `seq` writeIORef (resourceCountRef r) a'+               return True+               +-- | Acquire the resource, perform some action and safely release the resource               +-- in the end, even if the 'IOException' was raised within the action. +usingResource :: EnqueueStrategy s+                 => Resource s+                 -- ^ the resource we are going to request for and then release in the end+                 -> Process a+                 -- ^ the action we are going to apply having the resource+                 -> Process a+                 -- ^ the result of the action+usingResource r m =+  do requestResource r+     finallyProcess m $ releaseResource r++-- | 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 :: PriorityQueueStrategy s p+                             => Resource s+                             -- ^ the resource we are going to request for and then+                             -- release in the end+                             -> p+                             -- ^ the 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++-- | 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)++-- | Decrease the count of available resource by the specified number,+-- waiting for the processes capturing the resource as needed.+decResourceCount :: EnqueueStrategy s+                    => Resource s+                    -- ^ the resource+                    -> Int+                    -- ^ the decrement for the resource count+                    -> Process ()+decResourceCount r n+  | n < 0     = error "The decrement cannot be negative: decResourceCount"+  | n == 0    = return ()+  | otherwise =+    do requestResource r+       decResourceCount r (n - 1)+
Simulation/Aivika/Resource/Preemption.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the preemptible resource. --@@ -18,6 +18,9 @@         -- * Resource Properties         resourceMaxCount,         resourceCount,+        resourceCountStats,+        resourceUtilisationCount,+        resourceUtilisationCountStats,         -- * Requesting for and Releasing Resource         requestResourceWithPriority,         releaseResource,@@ -25,9 +28,16 @@         -- * Altering Resource          incResourceCount,         decResourceCount,-        alterResourceCount) where+        alterResourceCount,+        -- * Signals+        resourceCountChanged,+        resourceCountChanged_,+        resourceUtilisationCountChanged,+        resourceUtilisationCountChanged_,+        resourceChanged_) where  import Data.IORef+import Data.Monoid  import Control.Monad import Control.Monad.Trans@@ -39,6 +49,8 @@ import Simulation.Aivika.Internal.Cont import Simulation.Aivika.Internal.Process import Simulation.Aivika.QueueStrategy+import Simulation.Aivika.Statistics+import Simulation.Aivika.Signal  import qualified Simulation.Aivika.PriorityQueue as PQ @@ -48,6 +60,11 @@              -- ^ Return the maximum count of the resource, where 'Nothing'              -- means that the resource has no upper bound.              resourceCountRef :: IORef Int,+             resourceCountStatsRef :: IORef (TimingStats Int),+             resourceCountSource :: SignalSource Int,+             resourceUtilisationCountRef :: IORef Int,+             resourceUtilisationCountStatsRef :: IORef (TimingStats Int),+             resourceUtilisationCountSource :: SignalSource Int,              resourceActingQueue :: PQ.PriorityQueue ResourceActingItem,              resourceWaitQueue :: PQ.PriorityQueue ResourceAwaitingItem } @@ -79,18 +96,30 @@ -- | 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+               -> Event Resource newResource count =-  Simulation $ \r ->-  do when (count < 0) $+  Event $ \p ->+  do let r = pointRun p+         t = pointTime p+     when (count < 0) $        error $        "The resource count cannot be negative: " ++        "newResource."      countRef <- newIORef count+     countStatsRef <- newIORef $ returnTimingStats t count+     countSource <- invokeSimulation r newSignalSource+     utilCountRef <- newIORef 0+     utilCountStatsRef <- newIORef $ returnTimingStats t 0+     utilCountSource <- invokeSimulation r newSignalSource      actingQueue <- PQ.newQueue      waitQueue <- PQ.newQueue      return Resource { resourceMaxCount = Just count,                        resourceCountRef = countRef,+                       resourceCountStatsRef = countStatsRef,+                       resourceCountSource = countSource,+                       resourceUtilisationCountRef = utilCountRef,+                       resourceUtilisationCountStatsRef = utilCountStatsRef,+                       resourceUtilisationCountSource = utilCountSource,                        resourceActingQueue = actingQueue,                        resourceWaitQueue = waitQueue } @@ -100,10 +129,12 @@                            -- ^ the initial count of the resource                            -> Maybe Int                            -- ^ the maximum count of the resource, which can be indefinite-                           -> Simulation Resource+                           -> Event Resource newResourceWithMaxCount count maxCount =-  Simulation $ \r ->-  do when (count < 0) $+  Event $ \p ->+  do let r = pointRun p+         t = pointTime p+     when (count < 0) $        error $        "The resource count cannot be negative: " ++        "newResourceWithMaxCount."@@ -115,18 +146,63 @@        _ ->          return ()      countRef <- newIORef count+     countStatsRef <- newIORef $ returnTimingStats t count+     countSource <- invokeSimulation r newSignalSource+     utilCountRef <- newIORef 0+     utilCountStatsRef <- newIORef $ returnTimingStats t 0+     utilCountSource <- invokeSimulation r newSignalSource      actingQueue <- PQ.newQueue      waitQueue <- PQ.newQueue      return Resource { resourceMaxCount = maxCount,                        resourceCountRef = countRef,+                       resourceCountStatsRef = countStatsRef,+                       resourceCountSource = countSource,+                       resourceUtilisationCountRef = utilCountRef,+                       resourceUtilisationCountStatsRef = utilCountStatsRef,+                       resourceUtilisationCountSource = utilCountSource,                        resourceActingQueue = actingQueue,                        resourceWaitQueue = waitQueue } --- | Return the current count of the resource.+-- | Return the current available count of the resource. resourceCount :: Resource -> Event Int resourceCount r =   Event $ \p -> readIORef (resourceCountRef r) +-- | Return the statistics for the available count of the resource.+resourceCountStats :: Resource -> Event (TimingStats Int)+resourceCountStats r =+  Event $ \p -> readIORef (resourceCountStatsRef r)++-- | Signal triggered when the 'resourceCount' property changes.+resourceCountChanged :: Resource -> Signal Int+resourceCountChanged r =+  publishSignal $ resourceCountSource r++-- | Signal triggered when the 'resourceCount' property changes.+resourceCountChanged_ :: Resource -> Signal ()+resourceCountChanged_ r =+  mapSignal (const ()) $ resourceCountChanged r++-- | Return the current utilisation count of the resource.+resourceUtilisationCount :: Resource -> Event Int+resourceUtilisationCount r =+  Event $ \p -> readIORef (resourceUtilisationCountRef r)++-- | Return the statistics for the utilisation count of the resource.+resourceUtilisationCountStats :: Resource -> Event (TimingStats Int)+resourceUtilisationCountStats r =+  Event $ \p -> readIORef (resourceUtilisationCountStatsRef r)++-- | Signal triggered when the 'resourceUtilisationCount' property changes.+resourceUtilisationCountChanged :: Resource -> Signal Int+resourceUtilisationCountChanged r =+  publishSignal $ resourceUtilisationCountSource r++-- | Signal triggered when the 'resourceUtilisationCount' property changes.+resourceUtilisationCountChanged_ :: Resource -> Signal ()+resourceUtilisationCountChanged_ r =+  mapSignal (const ()) $ resourceUtilisationCountChanged 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.@@ -168,9 +244,9 @@                                         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+       else do PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+               invokeEvent p $ updateResourceCount r (-1)+               invokeEvent p $ updateResourceUtilisationCount r 1                invokeEvent p $ resumeCont c ()  -- | Release the resource increasing its count and resuming one of the@@ -184,7 +260,8 @@   Event $ \p ->   do f <- PQ.removeBy (resourceActingQueue r) (\item -> actingItemId item == pid)      if f-       then do invokeEvent p $ releaseResource' r+       then do invokeEvent p $ updateResourceUtilisationCount r (-1)+               invokeEvent p $ releaseResource' r                invokeEvent p $ resumeCont c ()        else error $             "The resource was not acquired by this process: releaseResource"@@ -207,7 +284,7 @@          return ()      f <- PQ.queueNull (resourceWaitQueue r)      if f -       then a' `seq` writeIORef (resourceCountRef r) a'+       then invokeEvent p $ updateResourceCount r 1        else do (priority', item) <- PQ.queueFront (resourceWaitQueue r)                PQ.dequeue (resourceWaitQueue r)                case item of@@ -218,6 +295,7 @@                           invokeEvent p $ releaseResource' r                         Just c ->                           do PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+                             invokeEvent p $ updateResourceUtilisationCount r 1                              invokeEvent p $ enqueueEvent (pointTime p) $ resumeCont c ()                  Right (ResourcePreemptedItem priority pid) ->                    do f <- invokeEvent p $ processCancelled pid@@ -226,6 +304,7 @@                           invokeEvent p $ releaseResource' r                         False ->                           do PQ.enqueue (resourceActingQueue r) (- priority) $ ResourceActingItem priority pid+                             invokeEvent p $ updateResourceUtilisationCount r 1                              invokeEvent p $ processPreemptionEnd pid                 -- | Acquire the resource with the specified priority, perform some action and@@ -254,17 +333,15 @@        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'+     unless f $+       do (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 $ processPreemptionBegin pid0+          invokeEvent p $ updateResourceUtilisationCount r (-1)+     invokeEvent p $ updateResourceCount r (-1)  -- | Increase the count of available resource by the specified number, -- invoking the awaiting and preempted processes according to their priorities@@ -296,7 +373,7 @@        decResourceCount r (n - 1)  -- | Alter the resource count either increasing or decreasing it by calling--- 'incResourceCount' or 'decResourceCount' respectively. +-- 'incResourceCount' or 'decResourceCount' respectively. alterResourceCount :: Resource                       -- ^ the resource                       -> Int@@ -306,3 +383,33 @@   | n < 0  = decResourceCount r (- n)   | n > 0  = incResourceCount r n   | n == 0 = return ()++-- | Signal triggered when one of the resource counters changes.+resourceChanged_ :: Resource -> Signal ()+resourceChanged_ r =+  resourceCountChanged_ r <>+  resourceUtilisationCountChanged_ r++-- | Update the resource count and its statistics.+updateResourceCount :: Resource -> Int -> Event ()+updateResourceCount r delta =+  Event $ \p ->+  do a <- readIORef (resourceCountRef r)+     let a' = a + delta+     a' `seq` writeIORef (resourceCountRef r) a'+     modifyIORef' (resourceCountStatsRef r) $+       addTimingStats (pointTime p) a'+     invokeEvent p $+       triggerSignal (resourceCountSource r) a'++-- | Update the resource utilisation count and its statistics.+updateResourceUtilisationCount :: Resource -> Int -> Event ()+updateResourceUtilisationCount r delta =+  Event $ \p ->+  do a <- readIORef (resourceUtilisationCountRef r)+     let a' = a + delta+     a' `seq` writeIORef (resourceUtilisationCountRef r) a'+     modifyIORef' (resourceUtilisationCountStatsRef r) $+       addTimingStats (pointTime p) a'+     invokeEvent p $+       triggerSignal (resourceUtilisationCountSource r) a'
+ Simulation/Aivika/Resource/Preemption/Base.hs view
@@ -0,0 +1,310 @@++-- |+-- Module     : Simulation.Aivika.Resource.Preemption.Base+-- 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.10.1+--+-- This module defines the preemptible resource.+--+-- The module is optimised in the sense that this kind of the resource+-- has neither additional signals, nor counters that would may slow+-- down the simulation.+--+module Simulation.Aivika.Resource.Preemption.Base+       (-- * 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: releaseResource'."+       _ ->+         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)+     unless f $+       do (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 $ processPreemptionBegin 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
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module allows exporting the simulation results from the model. --@@ -124,7 +124,7 @@ import Simulation.Aivika.Statistics import Simulation.Aivika.Statistics.Accumulator import Simulation.Aivika.Ref-import qualified Simulation.Aivika.Ref.Plain as LR+import qualified Simulation.Aivika.Ref.Base as BR import Simulation.Aivika.Var import Simulation.Aivika.QueueStrategy import qualified Simulation.Aivika.Queue as Q@@ -132,6 +132,8 @@ import Simulation.Aivika.Arrival import Simulation.Aivika.Server import Simulation.Aivika.Activity+import Simulation.Aivika.Resource+import qualified Simulation.Aivika.Resource.Preemption as PR import Simulation.Aivika.Results.Locale  -- | A name used for indentifying the results when generating output.@@ -1329,9 +1331,9 @@   computeResultData = readRef   computeResultSignal = ResultSignal . refChanged_ -instance ResultComputing LR.Ref where+instance ResultComputing BR.Ref where -  computeResultData = LR.readRef+  computeResultData = BR.readRef   computeResultSignal = const UnknownResultSignal  instance ResultComputing Var where@@ -1739,6 +1741,75 @@       resultContainerProperty c "idleFactor" ActivityIdleFactorId activityIdleFactor activityIdleFactorChanged_,       resultContainerProperty c "preemptionFactor" ActivityPreemptionFactorId activityPreemptionFactor activityPreemptionFactorChanged_ ] } +-- | Return a source by the specified resource.+resourceResultSource :: (Show s, ResultItemable (ResultValue s))+                        => ResultContainer (Resource s)+                        -- ^ the resource container+                        -> ResultSource+resourceResultSource c =+  ResultObjectSource $+  ResultObject {+    resultObjectName = resultContainerName c,+    resultObjectId = resultContainerId c,+    resultObjectTypeId = ResourceId,+    resultObjectSignal = resultContainerSignal c,+    resultObjectSummary = resourceResultSummary c,+    resultObjectProperties = [+      resultContainerProperty c "count" ResourceCountId resourceCount resourceCountChanged_,+      resultContainerProperty c "countStats" ResourceCountStatsId resourceCountStats resourceCountChanged_,+      resultContainerProperty c "utilisationCount" ResourceUtilisationCountId resourceUtilisationCount resourceUtilisationCountChanged_,+      resultContainerProperty c "utilisationCountStats" ResourceUtilisationCountStatsId resourceUtilisationCountStats resourceUtilisationCountChanged_ ] }++-- | Return a summary by the specified resource.+resourceResultSummary :: ResultContainer (Resource s)+                         -- ^ the resource container+                         -> ResultSource+resourceResultSummary c =+  ResultObjectSource $+  ResultObject {+    resultObjectName = resultContainerName c,+    resultObjectId = resultContainerId c,+    resultObjectTypeId = ResourceId,+    resultObjectSignal = resultContainerSignal c,+    resultObjectSummary = resourceResultSummary c,+    resultObjectProperties = [+      resultContainerProperty c "countStats" ResourceCountStatsId resourceCountStats resourceCountChanged_,+      resultContainerProperty c "utilisationCountStats" ResourceUtilisationCountStatsId resourceUtilisationCountStats resourceUtilisationCountChanged_ ] }++-- | Return a source by the specified resource.+preemptibleResourceResultSource :: ResultContainer PR.Resource+                                   -- ^ the resource container+                                   -> ResultSource+preemptibleResourceResultSource c =+  ResultObjectSource $+  ResultObject {+    resultObjectName = resultContainerName c,+    resultObjectId = resultContainerId c,+    resultObjectTypeId = ResourceId,+    resultObjectSignal = resultContainerSignal c,+    resultObjectSummary = preemptibleResourceResultSummary c,+    resultObjectProperties = [+      resultContainerProperty c "count" ResourceCountId PR.resourceCount PR.resourceCountChanged_,+      resultContainerProperty c "countStats" ResourceCountStatsId PR.resourceCountStats PR.resourceCountChanged_,+      resultContainerProperty c "utilisationCount" ResourceUtilisationCountId PR.resourceUtilisationCount PR.resourceUtilisationCountChanged_,+      resultContainerProperty c "utilisationCountStats" ResourceUtilisationCountStatsId PR.resourceUtilisationCountStats PR.resourceUtilisationCountChanged_ ] }++-- | Return a summary by the specified resource.+preemptibleResourceResultSummary :: ResultContainer PR.Resource+                                    -- ^ the resource container+                                    -> ResultSource+preemptibleResourceResultSummary c =+  ResultObjectSource $+  ResultObject {+    resultObjectName = resultContainerName c,+    resultObjectId = resultContainerId c,+    resultObjectTypeId = ResourceId,+    resultObjectSignal = resultContainerSignal c,+    resultObjectSummary = preemptibleResourceResultSummary c,+    resultObjectProperties = [+      resultContainerProperty c "countStats" ResourceCountStatsId PR.resourceCountStats PR.resourceCountChanged_,+      resultContainerProperty c "utilisationCountStats" ResourceUtilisationCountStatsId PR.resourceUtilisationCountStats PR.resourceUtilisationCountChanged_ ] }+ -- | Return an arbitrary text as a separator source. textResultSource :: String -> ResultSource textResultSource text =@@ -1969,3 +2040,13 @@    resultSource' name i m =     activityResultSource $ ResultContainer name i m (ResultSignal $ activityChanged_ m)++instance (Show s, ResultItemable (ResultValue s)) => ResultProvider (Resource s) where++  resultSource' name i m =+    resourceResultSource $ ResultContainer name i m (ResultSignal $ resourceChanged_ m)++instance ResultProvider PR.Resource where++  resultSource' name i m =+    preemptibleResourceResultSource $ ResultContainer name i m (ResultSignal $ PR.resourceChanged_ m)
Simulation/Aivika/Results/IO.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module allows printing and converting the 'Simulation' 'Results' to a 'String'. --
Simulation/Aivika/Results/Locale.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines locales for outputting and printing the simulation results. --@@ -34,6 +34,7 @@ import Simulation.Aivika.Arrival import Simulation.Aivika.Server import Simulation.Aivika.Activity+import Simulation.Aivika.Resource  -- | A locale to output the simulation results. --@@ -215,6 +216,16 @@                 -- ^ Property 'activityIdleFactor'.               | ActivityPreemptionFactorId                 -- ^ Property 'activityPreemptionFactor'.+              | ResourceId+                -- ^ Represents a 'Resource'.+              | ResourceCountId+                -- ^ Property 'resourceCount'.+              | ResourceCountStatsId+                -- ^ Property 'resourceCountStats'.+              | ResourceUtilisationCountId+                -- ^ Property 'resourceUtilisationCount'.+              | ResourceUtilisationCountStatsId+                -- ^ Property 'resourceUtilisationCountStats'.               | UserDefinedResultId ResultDescription                 -- ^ An user defined description.               | LocalisedResultId (M.Map ResultLocale ResultDescription)@@ -315,6 +326,11 @@ russianResultLocalisation ActivityUtilisationFactorId = "относительное время использования (от 0 до 1)" russianResultLocalisation ActivityIdleFactorId = "относительное время простоя (от 0 до 1)" russianResultLocalisation ActivityPreemptionFactorId = "относительное время вытеснения (от 0 до 1)"+russianResultLocalisation ResourceId = "ресурс"+russianResultLocalisation ResourceCountId = "текущее доступное количество ресурса"+russianResultLocalisation ResourceCountStatsId = "статистика по доступному количеству ресурса"+russianResultLocalisation ResourceUtilisationCountId = "текущее используемое количество ресурса"+russianResultLocalisation ResourceUtilisationCountStatsId = "статистика по используемому количеству ресурса" russianResultLocalisation (UserDefinedResultId m) = m russianResultLocalisation x@(LocalisedResultId m) =   lookupResultLocalisation russianResultLocale x@@ -405,6 +421,11 @@ 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 ResourceId = "the resource"+englishResultLocalisation ResourceCountId = "the current available count"+englishResultLocalisation ResourceCountStatsId = "the available count statistics"+englishResultLocalisation ResourceUtilisationCountId = "the current utilisation count"+englishResultLocalisation ResourceUtilisationCountStatsId = "the utilisation count statistics" englishResultLocalisation (UserDefinedResultId m) = m englishResultLocalisation x@(LocalisedResultId m) =   lookupResultLocalisation englishResultLocale x
Simulation/Aivika/Server.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It models the server that prodives a service. module Simulation.Aivika.Server@@ -81,7 +81,6 @@ import Simulation.Aivika.Dynamics import Simulation.Aivika.Internal.Event import Simulation.Aivika.Signal-import Simulation.Aivika.Resource import Simulation.Aivika.Cont import Simulation.Aivika.Process import Simulation.Aivika.Processor@@ -626,11 +625,11 @@ serverInputReceived :: Server s a b -> Signal a serverInputReceived = publishSignal . serverInputReceivedSource --- | Raised when the task processing by the server was preempted.+-- | Raised when the task processing was preempted. serverTaskPreemptionBeginning :: Server s a b -> Signal a serverTaskPreemptionBeginning = publishSignal . serverTaskPreemptionBeginningSource --- | Raised when the task processing by the server was proceeded after it has been preempeted earlier.+-- | Raised when the task processing was proceeded after it had been preempeted earlier. serverTaskPreemptionEnding :: Server s a b -> Signal a serverTaskPreemptionEnding = publishSignal . serverTaskPreemptionEndingSource 
Simulation/Aivika/Server/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines some useful predefined servers that -- hold the current process for the corresponding random time
Simulation/Aivika/Signal.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the signal which we can subscribe handlers to.  -- These handlers can be disposed. The signal is triggered in the 
Simulation/Aivika/Simulation.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines the 'Simulation' monad that represents a computation within -- the simulation run.
Simulation/Aivika/Specs.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It defines the simulation specs and functions for this data type. module Simulation.Aivika.Specs
Simulation/Aivika/Statistics.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- Represents statistics. --
Simulation/Aivika/Statistics/Accumulator.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This small utility module allows accumulating the timing statistics based on 'Signalable' data -- such as the queue size or the number of lost items in the queue.
Simulation/Aivika/Stream.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The infinite stream of data in time. --@@ -86,7 +86,7 @@ import Simulation.Aivika.Cont import Simulation.Aivika.Process import Simulation.Aivika.Signal-import Simulation.Aivika.Resource+import Simulation.Aivika.Resource.Base import Simulation.Aivika.QueueStrategy import Simulation.Aivika.Queue.Infinite import Simulation.Aivika.Internal.Arrival
Simulation/Aivika/Stream/Random.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines random streams of events, which are useful -- for describing the input of the model.
Simulation/Aivika/SystemDynamics.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines integrals and other functions of System Dynamics. --
Simulation/Aivika/Table.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- It defines the table functions. --
Simulation/Aivika/Task.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The 'Task' value represents a process that was already started in background. -- We can check the completion of the task, receive notifications about changing
Simulation/Aivika/Transform.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The module defines something which is most close to the notion of -- analogous circuit as an opposite to the digital one.
Simulation/Aivika/Transform/Extra.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines auxiliary computations such as interpolation ones -- that complement the memoization, for example. There are scan computations too.
Simulation/Aivika/Transform/Memo.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines memoization transforms. The memoization creates such 'Dynamics' -- computations, which values are cached in the integration time points. Then
Simulation/Aivika/Transform/Memo/Unboxed.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines the unboxed memoization transforms. The memoization creates such 'Dynamics' -- computations, which values are cached in the integration time points. Then
Simulation/Aivika/Unboxed.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- The 'Unboxed' class allows creating unboxed arrays in monad 'IO'. --
Simulation/Aivika/Var.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines a variable that is bound up with the event queue and  -- that keeps the history of changes storing the values in arrays, which
Simulation/Aivika/Var/Unboxed.hs view
@@ -5,7 +5,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- This module defines an unboxed variable that is bound up with the event queue and  -- that keeps the history of changes storing the values in unboxed arrays, which
Simulation/Aivika/Vector.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- An imperative vector. --
Simulation/Aivika/Vector/Unboxed.hs view
@@ -7,7 +7,7 @@ -- License    : BSD3 -- Maintainer : David Sorokin <david.sorokin@gmail.com> -- Stability  : experimental--- Tested with: GHC 7.8.3+-- Tested with: GHC 7.10.1 -- -- An imperative unboxed vector. --
aivika.cabal view
@@ -1,5 +1,5 @@ name:            aivika-version:         4.0.3+version:         4.1 synopsis:        A multi-paradigm simulation library description:     Aivika is a multi-paradigm simulation library with a strong emphasis@@ -96,7 +96,7 @@ homepage:        http://github.com/dsorokin/aivika cabal-version:   >= 1.10 build-type:      Simple-tested-with:     GHC == 7.8.3+tested-with:     GHC == 7.10.1  extra-source-files:  examples/BassDiffusion.hs                      examples/BouncingBall.hs@@ -117,6 +117,8 @@                      examples/TimeOut.hs                      examples/TimeOutInt.hs                      examples/TimeOutWait.hs+                     examples/PingPong.hs+                     examples/PortOperations.hs                      CHANGELOG.md  library@@ -150,9 +152,11 @@                      Simulation.Aivika.Queue.Infinite                      Simulation.Aivika.QueueStrategy                      Simulation.Aivika.Ref-                     Simulation.Aivika.Ref.Plain+                     Simulation.Aivika.Ref.Base                      Simulation.Aivika.Resource+                     Simulation.Aivika.Resource.Base                      Simulation.Aivika.Resource.Preemption+                     Simulation.Aivika.Resource.Preemption.Base                      Simulation.Aivika.Results.Locale                      Simulation.Aivika.Results                      Simulation.Aivika.Results.IO
examples/ChemicalReaction.hs view
@@ -7,8 +7,6 @@ import Simulation.Aivika import Simulation.Aivika.SystemDynamics -import qualified Data.Vector as V- specs = Specs { spcStartTime = 0,                  spcStopTime = 13,                  spcDT = 0.01,
examples/Furnace.hs view
@@ -1,9 +1,51 @@ --- This is a model of the Furnace. It is described in different sources [1, 2].+-- This is a model of the soaking pit furnace. It is described in different sources [1, 2]. -- -- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed. -- -- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006+--+-- Steel ingots arrive at a soaking pit furnace in a steel plant with+-- an interarrival time that is exponentially distributed with mean+-- of 2.25 hours. The soaking pit furnace heats an ingot so that it+-- can be economically rolled in the next stage of the process.+-- The temperature change of an ingot in the soaking pit furnace is+-- described by the following differential equation.+-- +--   d(h_i)/dt = (H - h_i) * C_i,+-- +-- where  h_i is the temperature of the i-th ingot in the soaking pit;+-- C_i is the heating time coefficient of an ingot and is equal to X + 0.1+-- where X is normally distributed with mean of 0.05 and standard deviation+-- of 0.01; and H is the furnace temperature which is heated toward 2600 F+-- with a heating rate constant if 0.2, that is,+-- +--   dH/dt = (2600 - H) * 0.2.+-- +-- The ingots interact with one another in that adding a "cold" ingot+-- to the furnace reduces the temperature of the furnace and thus changes+-- the heating time for all ingots in the furnace. The temperature reduction+-- is equal to the difference between furnace and ingot temperatures, divided+-- by the number of ingots in the furnace. There are 10 soaking pits in+-- the furnace. When a new ingot arrives and the furnace is full, it is+-- stored in an ingot storage bank. It is assumed that the initial temperature+-- of an arriving ingot is uniformly distributed in the interval from 400 to 500 F.+-- All ingots put in the ingot storage bank are assumed to have a temperature of+-- 400 F upon insertion into the soaking pit. The operating policy of the company+-- is to continue heating the ingots in the furnace until one or more ingots+-- reach 2200 F. At such a time all ingots with a temperature greater than 2000 F+-- are removed. The initial conditions are that there are six ingots in the furnace+-- with initial temperatures of 550, 600, 650, 700, 750 and 800 F. Initially,+-- the temperature of the furnace is 1650 F, and the next ingot is due to arrive+-- at time 0.+-- +-- The objective is to simulate the above system for 500 hours to obtain+-- estimates of the following quantities:+-- +-- 1) heating time of the ingots;+-- 2) final temperature distribution of the ingots;+-- 3) waiting time of the ingots in the ingot storage bank; and+-- 4) utilization of the soaking pit furnace.  import Data.Maybe import System.Random
examples/InspectionAdjustmentStations.hs view
@@ -6,10 +6,6 @@ -- This is a model of the workflow with a loop. Also there are two infinite queues. -- -- It is described in different sources [1, 2]. So, this is chapter 8 of [2] and section 5.15 of [1].------ [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.------ [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006 --  -- Assembled television sets move through a series of testing stations in the final  -- stage of their production. At the last of these stations, the vertical control @@ -30,6 +26,9 @@ -- The inspection station and adjustor are to be simulated for 480 minutes to estimate  -- the time to process television sets through the final production stage and to determine  -- the utilization of the inspectors and the adjustors.+--+-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.+-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006  import Prelude hiding (id, (.))  
examples/InventorySystem.hs view
@@ -3,14 +3,40 @@ -- -- It is described in different sources [1, 2]. So, this is chapter 11 of [2] and section 6.7 of [1]. ----- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.+-- A large discount house is planning to install a system to control the inventory of+-- a particular radio. The time between demands for a radio is exponentially distributed+-- with a mean time of 0.2 weeks. In the case where customers demand the radio when it+-- is not in stock, 80 percent will go to another nearby discount house to find it, thereby+-- representing lost sales, while the other 20 percent will backorder the radio and wait+-- for the next shipment arrival. The store employs a periodic review-reorder point+-- inventory system where the inventory status is reviewed every four weeks to decide if+-- an order should be placed. The company policy is to order up to the stock control level+-- of 72 radios whenever the inventory position, consisting of the radios in stock plus+-- the radios on order minus the radios on backorder, is found to be less than or equal to+-- the reorder point of 18 radios. The procurement lead time (the time from the placement+-- of an order to its receipt) is constant and requires three weeks. --+-- The objective of this example is to simulate the inventory system for a period of six+-- years (312 weeks) to obtain statistics on the following quantities:+--+--   1) number of radios in stock;+--   2) inventory position;+--   3) safety stock (radios in stock at order receipt times); and+--   4) time between lost sales.+--+-- The initial conditions for the simulation are an inventory position of 72 and no+-- initial backorders. In order to reduce the bias in the statistics due to the initial+-- starting conditions, all the statistics are to be cleared at the end of the first year+-- of the six year simulation period.+--+-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed. -- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006  import Control.Monad import Control.Monad.Trans  import Simulation.Aivika+import qualified Simulation.Aivika.Resource as R  -- | The simulation specs. specs = Specs { spcStartTime = 0.0,@@ -50,7 +76,7 @@   -- the inventory position   invPos <- newRef $ returnTimingCounter t0 radio0   -- the radios in stock-  radio <- newFCFSResource radio0+  radio <- runEventInStartTime $ R.newFCFSResource radio0   -- the time between lost sales   tbLostSales <- newRef emptySamplingStats   -- the last arrive time for the lost sale@@ -62,7 +88,7 @@            modifyRef invPos $              decTimingCounter t 1            runProcess $-             requestResource radio+             R.requestResource radio   -- a customer has been lost   let customerLost :: Event ()       customerLost = do@@ -79,7 +105,7 @@       customerArrival = do         randomExponentialProcess_ avgRadioDemand         liftEvent $ do-          r <- resourceCount radio+          r <- R.resourceCount radio           if r > 0             then customerOrder             else do b <- liftParameter $@@ -105,10 +131,10 @@                     setTimingCounter t stockControlLevel              holdProcess leadTime              liftEvent $-               do r <- resourceCount radio+               do r <- R.resourceCount radio                   modifyRef safetyStock $                     addSamplingStats r-                  incResourceCount radio orderQty+                  R.incResourceCount radio orderQty   -- start the inventory review process   runEventInStartTime $     enqueueEventWithTimes [t0, t0 + reviewPeriod ..] $@@ -126,7 +152,7 @@     results     [resultSource      "radio" "the number of radios in stock"-     (resourceCount radio),+     radio,      --      resultSource      "invPos" "the inventory position"
examples/MachineBreakdowns.hs view
@@ -3,10 +3,6 @@ -- -- It is described in different sources [1, 2]. So, this is chapter 13 of [2] and section 6.12 of [1]. ----- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.------ [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006--- -- Jobs arrive to a machine tool on the average of one per hour. The distribution of  -- these interarrival times is exponential. During normal operation, the jobs are  -- processed on a first-in, first-out basis. The time to process a job in hours is @@ -30,6 +26,9 @@ -- The machine tool is to be analyzed for 500 hours to obtain information on  -- the utilization of the machine tool and the time required to process a job.  -- Statistics are to be collected for thousand simulation runs.+--+-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.+-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006  import Control.Monad import Control.Monad.Trans@@ -92,7 +91,7 @@   let inputStream =         randomExponentialStream jobArrivingMu   -- create a preemptible resource-  tool <- PR.newResource 1+  tool <- runEventInStartTime $ PR.newResource 1   -- the machine setting up   machineSettingUp <-     newPreemptibleRandomUniformServer True minSetUpTime maxSetUpTime@@ -145,7 +144,11 @@      --      resultSource      "jobsCompleted" "a counter of the completed jobs"-     jobsCompleted]+     jobsCompleted,+     --+     resultSource+     "tool" "the machine tool"+     tool]  main =   printSimulationResultsInStopTime
+ examples/PingPong.hs view
@@ -0,0 +1,41 @@++-- A classic Ping-Pong example.++import Control.Monad.Trans++import Simulation.Aivika++delta = 1.0++specs = Specs { spcStartTime = 0,+                spcStopTime = 10 * delta,+                spcDT = delta,+                spcMethod = RungeKutta4,+                spcGeneratorType = SimpleGenerator }+        +model :: Simulation ()+model =+  do pingSource <- newSignalSource+     pongSource <- newSignalSource+     let pingSignal = publishSignal pingSource+         pongSignal = publishSignal pongSource+         ping =+           do holdProcess delta+              liftEvent $+                traceEvent "ping" $+                triggerSignal pingSource ()+              processAwait pongSignal+              ping+         pong =+           do processAwait pingSignal+              liftEvent $+                traceEvent "pong" $+                triggerSignal pongSource ()+              pong+     runProcessInStartTime ping+     runProcessInStartTime pong+     runEventInStopTime $+       traceEvent "end" $+       return ()++main = runSimulation model specs
+ examples/PortOperations.hs view
@@ -0,0 +1,177 @@++{-# LANGUAGE RecursiveDo #-}++-- Example: Port Operations+--+-- It is described in different sources [1, 2]. So, this is chapter 12 of [2] and section 6.13 of [1].+--+-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.+-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006+-- +-- A port in Africa is used to load tankers with crude oil for overwater shipment.+-- The port has facilities for loading as many as three tankers simultaneously.+-- The  tankers, which arrive at the port every 11 +/- 7 hours, are of three different+-- types. The relative frequency of the various types, and their loading time+-- requirements, are as follows:+-- +-- Type      Relative Frequency      Loading Time, Hours+--   1              0.25                   18 +/- 2+--   2              0.55                   24 +/- 3+--   3              0.20                   36 +/- 4+-- +-- There is one tug at the port. Tankers of all types require the services of this tug+-- to move into a berth, and later to move out of a berth. When the tug is available,+-- any berthing or de-berthing activity takes about one hour. Top priority is given to+-- the berthing activity.+-- +-- A shipper is considering bidding on a contract to transport oil from the port to+-- the United Kingdom. He has determined that 5 tankers of a particular type would+-- have to be committed to this task to meet contract specifications. These tankers+-- would require 21 +/- 3 hours to load oil at the port. After loading and de-berthing,+-- they would travel to the United Kingdom, offload the oil, and return to the port for+-- reloading. Their round-trip travel time, including offloading, is estimated to be+-- 240 +/- hours.+-- +-- A complicated factor is that the port experiences storms. The time between+-- the onset of storms is exponentially distributed with a mean of 48 hours and a +-- storm lasts 4 +/- 2 hours. No tug can start an operation until a storm is over.+-- +-- Before the port authorities can commit themselves to accommodating the+-- proposed 5 tankers, the effect of the additional port traffic on the in-port residence+-- time of the current port users must be determined. It is desired to simulate the+-- operation of the port for a one-year period (= 8640 hours) under the proposed new+-- commitment to measure in-port residence time of the proposed additional tankers,+-- as well as the three types of tankers which already use the port. All durations+-- given as ranges are uniformly distributed.        ++import Prelude hiding (id, (.)) ++import Control.Monad+import Control.Monad.Trans+import Control.Arrow+import Control.Category (id, (.))++import Data.Array++import Simulation.Aivika+import Simulation.Aivika.Queue+import qualified Simulation.Aivika.Resource as R++-- | The simulation specs.+specs = Specs { spcStartTime = 0.0,+                spcStopTime = 8760.0,+                spcDT = 0.1,+                spcMethod = RungeKutta4,+                spcGeneratorType = SimpleGenerator }++data Tunker =+  Tunker { tunkerLoadingTime :: Double,+           tunkerType :: Int }++model :: Simulation Results+model = mdo+  portTime' <- forM [1..4] $ \i ->+    newRef emptySamplingStats+  let portTime =+        array (1, 4) $ zip [1..] portTime'+  berth <-+    runEventInStartTime $+    R.newFCFSResource 3+  tug   <-+    runEventInStartTime $+    R.newFCFSResource 1+  let tunkers13 = randomUniformStream 4 18+      tunkers4  = takeStream 5 $+                  randomUniformStream 48 48+  runProcessInStartTime $+    flip consumeStream tunkers13 $ \x ->+    do p <- liftParameter $+            randomUniform 0 1+       let tp | p <= 0.25 = 1+              | p <= 0.25 + 0.55 = 2+              | otherwise = 3+       case tp of+         1 -> liftEvent arv1+         2 -> liftEvent arv2+         3 -> liftEvent arv3+  runProcessInStartTime $+    flip consumeStream tunkers4 $ \x ->+    liftEvent arv4+  let arv1 :: Event ()+      arv1 = do+        loadingTime <- liftParameter $+                       randomUniform 16 20+        let t = Tunker loadingTime 1+        runProcess (port t)+      arv2 :: Event ()+      arv2 = do+        loadingTime <- liftParameter $+                       randomUniform 21 27+        let t = Tunker loadingTime 2+        runProcess (port t)+      arv3 :: Event ()+      arv3 = do+        loadingTime <- liftParameter $+                       randomUniform 32 40+        let t = Tunker loadingTime 3+        runProcess (port t)+      arv4 :: Event ()+      arv4 = do+        loadingTime <- liftParameter $+                       randomUniform 18 24+        let t = Tunker loadingTime 4+        runProcess (port t)+  let port :: Tunker -> Process ()+      port t = do+        t0 <- liftDynamics time+        R.requestResource berth+        R.requestResource tug+        holdProcess 1+        R.releaseResource tug+        holdProcess (tunkerLoadingTime t)+        R.requestResource tug+        holdProcess 1+        R.releaseResource tug+        R.releaseResource berth+        t1 <- liftDynamics time+        let tp = tunkerType t +        liftEvent $+          modifyRef (portTime ! tp) $+          addSamplingStats (t1 - t0)+        when (tp == 4) $+          liftEvent $+          runProcess $+          do randomUniformProcess_  216 264+             liftEvent arv4+      storm :: Process ()+      storm = do+        randomExponentialProcess_ 48+        R.decResourceCount tug 1+        randomUniformProcess_ 2 6+        liftEvent $+          R.incResourceCount tug 1+        storm+  runProcessInStartTime storm+  return $+    results+    [resultSource+     "portTime" "Port Time"+     portTime,+     --+     resultSource+     "berth" "Berth"+     berth,+     --+     resultSource+     "tug" "Tug"+     tug ]++modelSummary :: Simulation Results+modelSummary =+  fmap resultSummary model++main =+  printSimulationResultsInStopTime+  printResultSourceInEnglish+  -- model specs+  modelSummary specs
examples/QuarryOperations.hs view
@@ -6,8 +6,25 @@ -- It is described in different sources [1, 2]. So, this is chapter 10 of [2] and section 5.16 of [1]. -- -- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.--- -- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006+-- +-- In this example, the operations of a quarry are modeled. In the quarry,+-- trucks deliver ore from three shovels to a crusher. A truck always+-- returns to its assigned shovel after dumping a load at the crusher.+-- There are two different truck sizes in use, twenty-ton and fifty-ton.+-- The size of the truck affects its loading time at the shovel, travel+-- time to the crusher, dumping time at the crusher and return trip time+-- from the crusher back to the appropriate shovel. For the twenty-ton+-- trucks, there loading, travel, dumping and return trip times are:+-- exponentially distributed with a mean 5; a constant 2.5; exponentially+-- distributed with mean 2; and a constant 1.5. The corresponding times+-- for the fifty-ton trucks are: exponentially distributed with mean 10;+-- a constant 3; exponentially distributed with mean 4; and a constant 2.+-- To each shovel is assigned two twenty-ton trucks are one fifty-ton truck.+-- The shovel queues are all ranked on a first-in, first-out basis.+-- The crusher queue is ranked on truck size, largest trucks first.+-- It is desired to analyze this system over 480 time units to determine+-- the utilization and queue lengths associated with the shovels and crusher.  import Control.Monad import Control.Monad.Trans@@ -138,19 +155,13 @@              IQ.enqueue q t   -- utilise the crusher's activity   let utiliseCrusher q t =-        do dumpingTime <--             liftParameter $-             randomExponential $+        do randomExponentialProcess_ $              truckAvgDumpingTime t-           holdProcess dumpingTime            return t   -- utilise the shovel's activity   let utiliseShovel q t =-        do loadingTime <--             liftParameter $-             randomExponential $+        do randomExponentialProcess_ $              truckAvgLoadingTime t-           holdProcess loadingTime            return t   -- create shovel activities   shovelAct1 <-
examples/WorkStationsInSeries.hs view
@@ -5,10 +5,6 @@ -- -- It is described in different sources [1, 2]. So, this is chapter 7 of [2] and section 5.14 of [1]. ----- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.------ [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006--- -- The maintenance facility of a large manufacturer performs two operations.  -- These operations must be performed in series; operation 2 always follows operation 1.  -- The units that are maintained are bulky, and space is available for only eight units @@ -25,6 +21,9 @@ -- work station 2 is full, that is, if there are two units awaiting for work station 2,  -- the first station is blocked and a unit cannot leave the station. A blocked work  -- station cannot server other units.+--+-- [1] A. Alan B. Pritsker, Simulation with Visual SLAM and AweSim, 2nd ed.+-- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006  import Prelude hiding (id, (.))