module Simulation.Aivika.Circuit
(
Circuit(..),
arrCircuit,
accumCircuit,
arrivalCircuit,
delayCircuit,
timeCircuit,
(<?<),
(>?>),
filterCircuit,
filterCircuitM,
neverCircuit,
circuitSignaling,
circuitProcessor,
integCircuit,
sumCircuit,
circuitTransform) where
import qualified Control.Category as C
import Control.Arrow
import Control.Monad.Fix
import Data.IORef
import Simulation.Aivika.Internal.Arrival
import Simulation.Aivika.Internal.Specs
import Simulation.Aivika.Internal.Simulation
import Simulation.Aivika.Internal.Dynamics
import Simulation.Aivika.Internal.Event
import Simulation.Aivika.Dynamics.Memo
import Simulation.Aivika.Transform
import Simulation.Aivika.SystemDynamics
import Simulation.Aivika.Signal
import Simulation.Aivika.Stream
import Simulation.Aivika.Processor
newtype Circuit a b =
Circuit { runCircuit :: a -> Event (Circuit a b, b)
}
instance C.Category Circuit where
id = Circuit $ \a -> return (C.id, a)
(.) = dot
where
(Circuit g) `dot` (Circuit f) =
Circuit $ \a ->
Event $ \p ->
do (cir1, b) <- invokeEvent p (f a)
(cir2, c) <- invokeEvent p (g b)
return (cir2 `dot` cir1, c)
instance Arrow Circuit where
arr f = Circuit $ \a -> return (arr f, f a)
first (Circuit f) =
Circuit $ \(b, d) ->
Event $ \p ->
do (cir, c) <- invokeEvent p (f b)
return (first cir, (c, d))
second (Circuit f) =
Circuit $ \(d, b) ->
Event $ \p ->
do (cir, c) <- invokeEvent p (f b)
return (second cir, (d, c))
(Circuit f) *** (Circuit g) =
Circuit $ \(b, b') ->
Event $ \p ->
do (cir1, c) <- invokeEvent p (f b)
(cir2, c') <- invokeEvent p (g b')
return (cir1 *** cir2, (c, c'))
(Circuit f) &&& (Circuit g) =
Circuit $ \b ->
Event $ \p ->
do (cir1, c) <- invokeEvent p (f b)
(cir2, c') <- invokeEvent p (g b)
return (cir1 &&& cir2, (c, c'))
instance ArrowLoop Circuit where
loop (Circuit f) =
Circuit $ \b ->
Event $ \p ->
do rec (cir, (c, d)) <- invokeEvent p (f (b, d))
return (loop cir, c)
instance ArrowChoice Circuit where
left x@(Circuit f) =
Circuit $ \ebd ->
Event $ \p ->
case ebd of
Left b ->
do (cir, c) <- invokeEvent p (f b)
return (left cir, Left c)
Right d ->
return (left x, Right d)
right x@(Circuit f) =
Circuit $ \edb ->
Event $ \p ->
case edb of
Right b ->
do (cir, c) <- invokeEvent p (f b)
return (right cir, Right c)
Left d ->
return (right x, Left d)
x@(Circuit f) +++ y@(Circuit g) =
Circuit $ \ebb' ->
Event $ \p ->
case ebb' of
Left b ->
do (cir1, c) <- invokeEvent p (f b)
return (cir1 +++ y, Left c)
Right b' ->
do (cir2, c') <- invokeEvent p (g b')
return (x +++ cir2, Right c')
x@(Circuit f) ||| y@(Circuit g) =
Circuit $ \ebc ->
Event $ \p ->
case ebc of
Left b ->
do (cir1, d) <- invokeEvent p (f b)
return (cir1 ||| y, d)
Right b' ->
do (cir2, d) <- invokeEvent p (g b')
return (x ||| cir2, d)
circuitSignaling :: Circuit a b -> Signal a -> Signal b
circuitSignaling (Circuit cir) sa =
Signal { handleSignal = \f ->
Event $ \p ->
do r <- newIORef cir
invokeEvent p $
handleSignal sa $ \a ->
Event $ \p ->
do cir <- readIORef r
(Circuit cir', b) <- invokeEvent p (cir a)
writeIORef r cir'
invokeEvent p (f b) }
circuitProcessor :: Circuit a b -> Processor a b
circuitProcessor (Circuit cir) = Processor $ \sa ->
Cons $
do (a, xs) <- runStream sa
(cir', b) <- liftEvent (cir a)
let f = runProcessor (circuitProcessor cir')
return (b, f xs)
arrCircuit :: (a -> Event b) -> Circuit a b
arrCircuit f =
let x =
Circuit $ \a ->
Event $ \p ->
do b <- invokeEvent p (f a)
return (x, b)
in x
accumCircuit :: (acc -> a -> Event (acc, b)) -> acc -> Circuit a b
accumCircuit f acc =
Circuit $ \a ->
Event $ \p ->
do (acc', b) <- invokeEvent p (f acc a)
return (accumCircuit f acc', b)
arrivalCircuit :: Circuit a (Arrival a)
arrivalCircuit =
let loop t0 =
Circuit $ \a ->
Event $ \p ->
let t = pointTime p
b = Arrival { arrivalValue = a,
arrivalTime = t,
arrivalDelay =
case t0 of
Nothing -> 0
Just t0 -> t t0 }
in return (loop $ Just t, b)
in loop Nothing
delayCircuit :: a -> Circuit a a
delayCircuit a0 =
Circuit $ \a ->
return (delayCircuit a, a0)
timeCircuit :: Circuit a Double
timeCircuit =
Circuit $ \a ->
Event $ \p ->
return (timeCircuit, pointTime p)
(>?>) :: Circuit a (Maybe b)
-> Circuit b c
-> Circuit a (Maybe c)
whether >?> process =
Circuit $ \a ->
Event $ \p ->
do (whether', b) <- invokeEvent p (runCircuit whether a)
case b of
Nothing ->
return (whether' >?> process, Nothing)
Just b ->
do (process', c) <- invokeEvent p (runCircuit process b)
return (whether' >?> process', Just c)
(<?<) :: Circuit b c
-> Circuit a (Maybe b)
-> Circuit a (Maybe c)
(<?<) = flip (>?>)
filterCircuit :: (a -> Bool) -> Circuit a b -> Circuit a (Maybe b)
filterCircuit pred = filterCircuitM (return . pred)
filterCircuitM :: (a -> Event Bool) -> Circuit a b -> Circuit a (Maybe b)
filterCircuitM pred cir =
Circuit $ \a ->
Event $ \p ->
do x <- invokeEvent p (pred a)
if x
then do (cir', b) <- invokeEvent p (runCircuit cir a)
return (filterCircuitM pred cir', Just b)
else return (filterCircuitM pred cir, Nothing)
neverCircuit :: Circuit a (Maybe b)
neverCircuit =
Circuit $ \a -> return (neverCircuit, Nothing)
integCircuit :: Double
-> Circuit Double Double
integCircuit init = start
where
start =
Circuit $ \a ->
Event $ \p ->
do let t = pointTime p
return (next t init a, init)
next t0 v0 a0 =
Circuit $ \a ->
Event $ \p ->
do let t = pointTime p
dt = t t0
v = v0 + a0 * dt
v `seq` return (next t v a, v)
sumCircuit :: Num a =>
a
-> Circuit a a
sumCircuit init = start
where
start =
Circuit $ \a ->
Event $ \p ->
return (next init a, init)
next v0 a0 =
Circuit $ \a ->
Event $ \p ->
do let v = v0 + a0
v `seq` return (next v a, v)
circuitTransform :: Circuit a b -> Transform a b
circuitTransform cir = Transform start
where
start m =
Simulation $ \r ->
do ref <- newIORef cir
invokeSimulation r $
memo0Dynamics (next ref m)
next ref m =
Dynamics $ \p ->
do a <- invokeDynamics p m
cir <- readIORef ref
(cir', b) <-
invokeDynamics p $
runEvent (runCircuit cir a)
writeIORef ref cir'
return b