mdp-0.1.0.0: src/Algorithms/MDP/Examples/MM1.hs
-- | We model an M/M/1 queue, i.e. a single-server queue with Poisson
-- arrivals and service times.
--
-- See "Stochastic Dynamic Programming and the Control of Queueing
-- Systems", Linn I. Sennot,, p. 242 for details.
module Algorithms.MDP.Examples.MM1 where
import qualified Algorithms.MDP.CTMDP as CTMDP
-- | A description of an MDP.
data Scenario = Scenario
{ _arrivalRate :: Double
, _serviceRates :: [Double]
, _serviceCosts :: [Double]
, _holdingCosts :: Int -> Double
, _maxWaiting :: Int
, _scenarioCost :: Double
}
-- | The state space is the count of customers in the queue.
newtype State = State Int
deriving (Show, Eq)
-- | There are a number of services we can provide each customer, and
-- if there are no customers we do nothing.
data Action = NullAction
| Action Int
deriving (Show, Eq)
-- | Generate an MDP from a Scenario.
mkInstance :: Scenario -> CTMDP.CTMDP State Action Double
mkInstance scenario =
let
-- (State i) represents i customers waiting in the queue.
states = map State [0..(_maxWaiting scenario)]
-- (Action i) represents serving a customer with the ith service
-- profile, while the NullAction represents what we do in the
-- empty queue (wait).
actions = NullAction : map Action [0..length (_serviceRates scenario) - 1]
-- All actions but the null action have an associated cost
rateCost (Action ac) (State i) = hc + sc
where
hc = _holdingCosts scenario i
sc = _serviceCosts scenario !! ac
rateCost NullAction _ = 0
-- There can always be an arrival, and if we don't take the null
-- action there can be a departure.
rates (Action ac) _ = _arrivalRate scenario + _serviceRates scenario !! ac
rates NullAction _ = _arrivalRate scenario
-- There are no fixed costs.
fixedCost _ _= 0
-- We can only take the null action in state 0, and can take any
-- other action in all other states.
actionSet (State 0) = [NullAction]
actionSet _ = (tail actions)
-- If we take the null action, we wait for an arrival. Otherwise,
-- we can increase or decrease the length of the queue by 1.
--
-- Note that since we cannot transition about the maximum state,
-- we instead allow a self-transition.
trans NullAction (State 0) (State 1) = 1
trans NullAction _ _ = 0
trans (Action ac) (State i) (State j)
| j == i + 1 = lambda / (lambda + a)
| j == i && i == maxN = lambda / (lambda + a)
| j == i - 1 = a / (lambda + a)
| otherwise = 0
where
maxN = _maxWaiting scenario
lambda = _arrivalRate scenario
a = _serviceRates scenario !! ac
in
CTMDP.mkCTMDP states actions trans rates fixedCost rateCost actionSet 1.0
-- | A specific scenario.
scenario1 :: Scenario
scenario1 = Scenario
{ _arrivalRate = 3
, _serviceRates = [2, 4, 8]
, _serviceCosts = [9, 13, 21]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 48
, _scenarioCost = 8.475
}
-- | A specific scenario.
scenario2 :: Scenario
scenario2 = Scenario
{ _arrivalRate = 2.0
, _serviceRates = [1, 4, 7]
, _serviceCosts = [1, 50, 500]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 21.091
}
-- | A specific scenario.
scenario3 :: Scenario
scenario3 = Scenario
{ _arrivalRate = 2.0
, _serviceRates = [1, 4, 7]
, _serviceCosts = [1, 50, 150]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 21.091
}
-- | A specific scenario.
scenario4 :: Scenario
scenario4 = Scenario
{ _arrivalRate = 2.0
, _serviceRates = [1, 4, 7]
, _serviceCosts = [1, 50, 100]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 21.971
}
-- | A specific scenario.
scenario5 :: Scenario
scenario5 = Scenario
{ _arrivalRate = 2.0
, _serviceRates = [5.0, 5.5, 5.8]
, _serviceCosts = [0, 10, 100]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 17.043
}
-- | A specific scenario.
scenario6 :: Scenario
scenario6 = Scenario
{ _arrivalRate = 5.0
, _serviceRates = [5.1, 5.3, 6.0]
, _serviceCosts = [0, 10, 25]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 15.193
}
-- | A specific scenario.
scenario7 :: Scenario
scenario7 = Scenario
{ _arrivalRate = 10.0
, _serviceRates = [10.2, 10.6, 12]
, _serviceCosts = [0, 10, 25]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 15.193
}
-- | A specific scenario.
scenario8 :: Scenario
scenario8 = Scenario
{ _arrivalRate = 20.0
, _serviceRates = [24, 27, 30]
, _serviceCosts = [1, 1.5, 5.0]
, _holdingCosts = \i -> fromIntegral i
, _maxWaiting = 84
, _scenarioCost = 3.902
}