module Simulation.Aivika.Net
(
Net(..),
iterateNet,
iterateNetMaybe,
iterateNetEither,
emptyNet,
arrNet,
accumNet,
withinNet,
netUsingId,
arrivalNet,
delayNet,
netProcessor,
processorNet,
traceNet) where
import qualified Control.Category as C
import Control.Arrow
import Control.Monad.Trans
import Data.IORef
import Simulation.Aivika.Simulation
import Simulation.Aivika.Dynamics
import Simulation.Aivika.Event
import Simulation.Aivika.Cont
import Simulation.Aivika.Process
import Simulation.Aivika.Stream
import Simulation.Aivika.QueueStrategy
import Simulation.Aivika.Resource.Base
import Simulation.Aivika.Processor
import Simulation.Aivika.Ref
import Simulation.Aivika.Circuit
import Simulation.Aivika.Internal.Arrival
newtype Net a b =
Net { runNet :: a -> Process (b, Net a b)
}
instance C.Category Net where
id = Net $ \a -> return (a, C.id)
(.) = dot
where
(Net g) `dot` (Net f) =
Net $ \a ->
do (b, p1) <- f a
(c, p2) <- g b
return (c, p2 `dot` p1)
instance Arrow Net where
arr f = Net $ \a -> return (f a, arr f)
first (Net f) =
Net $ \(b, d) ->
do (c, p) <- f b
return ((c, d), first p)
second (Net f) =
Net $ \(d, b) ->
do (c, p) <- f b
return ((d, c), second p)
(Net f) *** (Net g) =
Net $ \(b, b') ->
do (c, p1) <- f b
(c', p2) <- g b'
return ((c, c'), p1 *** p2)
(Net f) &&& (Net g) =
Net $ \b ->
do (c, p1) <- f b
(c', p2) <- g b
return ((c, c'), p1 &&& p2)
instance ArrowChoice Net where
left x@(Net f) =
Net $ \ebd ->
case ebd of
Left b ->
do (c, p) <- f b
return (Left c, left p)
Right d ->
return (Right d, left x)
right x@(Net f) =
Net $ \edb ->
case edb of
Right b ->
do (c, p) <- f b
return (Right c, right p)
Left d ->
return (Left d, right x)
x@(Net f) +++ y@(Net g) =
Net $ \ebb' ->
case ebb' of
Left b ->
do (c, p1) <- f b
return (Left c, p1 +++ y)
Right b' ->
do (c', p2) <- g b'
return (Right c', x +++ p2)
x@(Net f) ||| y@(Net g) =
Net $ \ebc ->
case ebc of
Left b ->
do (d, p1) <- f b
return (d, p1 ||| y)
Right b' ->
do (d, p2) <- g b'
return (d, x ||| p2)
emptyNet :: Net a b
emptyNet = Net $ const neverProcess
arrNet :: (a -> Process b) -> Net a b
arrNet f =
let x =
Net $ \a ->
do b <- f a
return (b, x)
in x
accumNet :: (acc -> a -> Process (acc, b)) -> acc -> Net a b
accumNet f acc =
Net $ \a ->
do (acc', b) <- f acc a
return (b, accumNet f acc')
withinNet :: Process () -> Net a a
withinNet m =
Net $ \a ->
do { m; return (a, withinNet m) }
netUsingId :: ProcessId -> Net a b -> Net a b
netUsingId pid (Net f) =
Net $ processUsingId pid . f
netProcessor :: Net a b -> Processor a b
netProcessor = Processor . loop
where loop x as =
Cons $
do (a, as') <- runStream as
(b, x') <- runNet x a
return (b, loop x' as')
processorNet :: Processor a b -> Net a b
processorNet x =
Net $ \a ->
do readingA <- liftSimulation $ newResourceWithMaxCount FCFS 0 (Just 1)
writingA <- liftSimulation $ newResourceWithMaxCount FCFS 1 (Just 1)
readingB <- liftSimulation $ newResourceWithMaxCount FCFS 0 (Just 1)
writingB <- liftSimulation $ newResourceWithMaxCount FCFS 1 (Just 1)
conting <- liftSimulation $ newResourceWithMaxCount FCFS 0 (Just 1)
refA <- liftIO $ newIORef Nothing
refB <- liftIO $ newIORef Nothing
let input =
do requestResource readingA
Just a <- liftIO $ readIORef refA
liftIO $ writeIORef refA Nothing
releaseResource writingA
return (a, Cons input)
consume bs =
do (b, bs') <- runStream bs
requestResource writingB
liftIO $ writeIORef refB (Just b)
releaseResource readingB
requestResource conting
consume bs'
loop a =
do requestResource writingA
liftIO $ writeIORef refA (Just a)
releaseResource readingA
requestResource readingB
Just b <- liftIO $ readIORef refB
liftIO $ writeIORef refB Nothing
releaseResource writingB
return (b, Net $ \a -> releaseResource conting >> loop a)
spawnProcess $
consume $ runProcessor x (Cons input)
loop a
arrivalNet :: Net a (Arrival a)
arrivalNet =
let loop t0 =
Net $ \a ->
do t <- liftDynamics time
let b = Arrival { arrivalValue = a,
arrivalTime = t,
arrivalDelay =
case t0 of
Nothing -> Nothing
Just t0 -> Just (t t0) }
return (b, loop $ Just t)
in loop Nothing
delayNet :: a -> Net a a
delayNet a0 =
Net $ \a ->
return (a0, delayNet a)
iterateNet :: Net a a -> a -> Process ()
iterateNet (Net f) a =
do (a', x) <- f a
iterateNet x a'
iterateNetMaybe :: Net a (Maybe a) -> a -> Process ()
iterateNetMaybe (Net f) a =
do (a', x) <- f a
case a' of
Nothing -> return ()
Just a' -> iterateNetMaybe x a'
iterateNetEither :: Net a (Either b a) -> a -> Process b
iterateNetEither (Net f) a =
do (ba', x) <- f a
case ba' of
Left b' -> return b'
Right a' -> iterateNetEither x a'
traceNet :: Maybe String
-> Maybe String
-> Net a b
-> Net a b
traceNet request response x = Net $ loop x where
loop x a =
do (b, x') <-
case request of
Nothing -> runNet x a
Just message ->
traceProcess message $
runNet x a
case response of
Nothing -> return (b, Net $ loop x')
Just message ->
traceProcess message $
return (b, Net $ loop x')