{-# LANGUAGE RecursiveDo, Arrows #-} -- 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]. -- -- [1] { add a foreign source in English } -- -- [2] Труб И.И., Объектно-ориентированное моделирование на C++: Учебный курс. - СПб.: Питер, 2006 -- CAUTION: this is model is not yet fully tested and it may contain logical errors. import Prelude hiding (id, (.)) import Control.Monad import Control.Monad.Trans import Control.Arrow import Control.Category (id, (.)) import Simulation.Aivika import Simulation.Aivika.Queue.Infinite -- | The simulation specs. specs = Specs { spcStartTime = 0.0, spcStopTime = 480.0, spcDT = 0.1, spcMethod = RungeKutta4, spcGeneratorType = SimpleGenerator } -- the minimum delay for arriving the next TV set minArrivalDelay = 3.5 -- the maximum delay for arriving the next TV set maxArrivalDelay = 7.5 -- the minimum test time minTestTime = 6 -- the maximum test time maxTestTime = 12 -- the probability of passing the test testPassingProb = 0.85 -- how many testers are there? testerWorkplaceCount = 2 -- the minimum time of tuning the TV set -- that has not passed the test minTuningTime = 20 -- the maximum time of tuning the TV set -- that has not passed the test maxTuningTime = 40 -- how many persons perform a tuning of TV sets? tunerWorkplaceCount = 1 -- create an accumulator to gather the queue size statistics newQueueSizeAccumulator queue = newTimingStatsAccumulator $ Signalable (queueCount queue) (queueCountChanged_ queue) -- create a tester's workplace newTesterWorkplace = newServer $ \a -> do holdProcess =<< (liftParameter $ randomUniform minTestTime maxTestTime) passed <- liftParameter $ randomTrue testPassingProb if passed then return $ Right a else return $ Left a -- create a tuner's workplace newTunerWorkplace = newServer $ \a -> do holdProcess =<< (liftParameter $ randomUniform minTuningTime maxTuningTime) return a model :: Simulation () model = mdo -- it will gather the statistics of the processing time inputArrivalTimer <- newArrivalTimer outputArrivalTimer <- newArrivalTimer -- define a stream of input events let inputStream = randomUniformStream minArrivalDelay maxArrivalDelay -- create a queue before the tester's work place testerQueue <- newFCFSQueue -- create a queue before the tuner's work place tunerQueue <- newFCFSQueue -- the tester's queue size statistics testerQueueSizeAcc <- runEventInStartTime $ newQueueSizeAccumulator testerQueue -- the tuner's queue size statistics tunerQueueSizeAcc <- runEventInStartTime $ newQueueSizeAccumulator tunerQueue -- create the tester's work places, i.e. the "servers" testerWorkplaces <- forM [1 .. testerWorkplaceCount] $ \_ -> newTesterWorkplace -- create the tuner's work places, i.e. the "servers" tunerWorkplaces <- forM [1 .. tunerWorkplaceCount] $ \_ -> newTunerWorkplace -- a processor loop for the tester's queue let testerQueueProcessorLoop = queueProcessorLoopSeq (liftEvent . enqueue testerQueue) (dequeue testerQueue) testerProcessor (tunerQueueProcessor >>> tunerProcessor) -- a processor for the tuner's queue let tunerQueueProcessor = queueProcessor (liftEvent . enqueue tunerQueue) (dequeue tunerQueue) -- the parallel work of all the testers let testerProcessor = processorParallel (map serverProcessor testerWorkplaces) -- the parallel work of all the tuners let tunerProcessor = processorParallel (map serverProcessor tunerWorkplaces) -- the entire processor from input to output let entireProcessor = arrivalTimerProcessor inputArrivalTimer >>> testerQueueProcessorLoop >>> arrivalTimerProcessor outputArrivalTimer -- start simulating the model runProcessInStartTime $ sinkStream $ runProcessor entireProcessor inputStream -- show the results in the final time runEventInStopTime $ do testerQueueSum <- queueSummary testerQueue 2 tunerQueueSum <- queueSummary tunerQueue 2 testerWorkplaceSums <- forM testerWorkplaces $ \x -> serverSummary x 2 tunerWorkplaceSums <- forM tunerWorkplaces $ \x -> serverSummary x 2 inputProcessingTime <- arrivalProcessingTime inputArrivalTimer outputProcessingTime <- arrivalProcessingTime outputArrivalTimer testerQueueSize <- timingStatsAccumulated testerQueueSizeAcc tunerQueueSize <- timingStatsAccumulated tunerQueueSizeAcc liftIO $ do putStrLn "" putStrLn "--- the tester's queue summary (in the final time) ---" putStrLn "" putStrLn $ testerQueueSum [] putStrLn "" forM_ (zip [1..] testerWorkplaceSums) $ \(i, x) -> do putStrLn $ "--- the tester's work place no." ++ show i ++ " (in the final time) ---" putStrLn "" putStrLn $ x [] putStrLn "" putStrLn "--- the tuner's queue summary (in the final time) ---" putStrLn "" putStrLn $ tunerQueueSum [] putStrLn "" forM_ (zip [1..] tunerWorkplaceSums) $ \(i, x) -> do putStrLn $ "--- the tuner's work place no. " ++ show i ++ " (in the final time) ---" putStrLn "" putStrLn $ x [] putStrLn "" putStrLn "--- the arrival receiving time summary (we are interested in their count) ---" putStrLn "" putStrLn $ samplingStatsSummary inputProcessingTime 2 [] putStrLn "" putStrLn "--- the arrival processing time summary ---" putStrLn "" putStrLn $ samplingStatsSummary outputProcessingTime 2 [] putStrLn "" putStrLn "--- the tester's queue size summary (updated when enqueueing and dequeueing) ---" putStrLn "" putStrLn $ timingStatsSummary testerQueueSize 2 [] putStrLn "" putStrLn "--- the tuner's queue size summary (updated when enqueueing and dequeueing) ---" putStrLn "" putStrLn $ timingStatsSummary tunerQueueSize 2 [] putStrLn "" main = runSimulation model specs