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 (b, Circuit a b)
}
instance C.Category Circuit where
id = Circuit $ \a -> return (a, C.id)
(.) = dot
where
(Circuit g) `dot` (Circuit f) =
Circuit $ \a ->
Event $ \p ->
do (b, cir1) <- invokeEvent p (f a)
(c, cir2) <- invokeEvent p (g b)
return (c, cir2 `dot` cir1)
instance Arrow Circuit where
arr f = Circuit $ \a -> return (f a, arr f)
first (Circuit f) =
Circuit $ \(b, d) ->
Event $ \p ->
do (c, cir) <- invokeEvent p (f b)
return ((c, d), first cir)
second (Circuit f) =
Circuit $ \(d, b) ->
Event $ \p ->
do (c, cir) <- invokeEvent p (f b)
return ((d, c), second cir)
(Circuit f) *** (Circuit g) =
Circuit $ \(b, b') ->
Event $ \p ->
do (c, cir1) <- invokeEvent p (f b)
(c', cir2) <- invokeEvent p (g b')
return ((c, c'), cir1 *** cir2)
(Circuit f) &&& (Circuit g) =
Circuit $ \b ->
Event $ \p ->
do (c, cir1) <- invokeEvent p (f b)
(c', cir2) <- invokeEvent p (g b)
return ((c, c'), cir1 &&& cir2)
instance ArrowLoop Circuit where
loop (Circuit f) =
Circuit $ \b ->
Event $ \p ->
do rec ((c, d), cir) <- invokeEvent p (f (b, d))
return (c, loop cir)
instance ArrowChoice Circuit where
left x@(Circuit f) =
Circuit $ \ebd ->
Event $ \p ->
case ebd of
Left b ->
do (c, cir) <- invokeEvent p (f b)
return (Left c, left cir)
Right d ->
return (Right d, left x)
right x@(Circuit f) =
Circuit $ \edb ->
Event $ \p ->
case edb of
Right b ->
do (c, cir) <- invokeEvent p (f b)
return (Right c, right cir)
Left d ->
return (Left d, right x)
x@(Circuit f) +++ y@(Circuit g) =
Circuit $ \ebb' ->
Event $ \p ->
case ebb' of
Left b ->
do (c, cir1) <- invokeEvent p (f b)
return (Left c, cir1 +++ y)
Right b' ->
do (c', cir2) <- invokeEvent p (g b')
return (Right c', x +++ cir2)
x@(Circuit f) ||| y@(Circuit g) =
Circuit $ \ebc ->
Event $ \p ->
case ebc of
Left b ->
do (d, cir1) <- invokeEvent p (f b)
return (d, cir1 ||| y)
Right b' ->
do (d, cir2) <- invokeEvent p (g b')
return (d, x ||| cir2)
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
(b, Circuit cir') <- 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
(b, cir') <- 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 (b, x)
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 (b, accumCircuit f acc')
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 -> Nothing
Just t0 -> Just (t t0) }
in return (b, loop $ Just t)
in loop Nothing
delayCircuit :: a -> Circuit a a
delayCircuit a0 =
Circuit $ \a ->
return (a0, delayCircuit a)
timeCircuit :: Circuit a Double
timeCircuit =
Circuit $ \a ->
Event $ \p ->
return (pointTime p, timeCircuit)
(>?>) :: Circuit a (Maybe b)
-> Circuit b c
-> Circuit a (Maybe c)
whether >?> process =
Circuit $ \a ->
Event $ \p ->
do (b, whether') <- invokeEvent p (runCircuit whether a)
case b of
Nothing ->
return (Nothing, whether' >?> process)
Just b ->
do (c, process') <- invokeEvent p (runCircuit process b)
return (Just c, whether' >?> process')
(<?<) :: 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 (b, cir') <- invokeEvent p (runCircuit cir a)
return (Just b, filterCircuitM pred cir')
else return (Nothing, filterCircuitM pred cir)
neverCircuit :: Circuit a (Maybe b)
neverCircuit =
Circuit $ \a -> return (Nothing, neverCircuit)
integCircuit :: Double
-> Circuit Double Double
integCircuit init = start
where
start =
Circuit $ \a ->
Event $ \p ->
do let t = pointTime p
return (init, next t init a)
next t0 v0 a0 =
Circuit $ \a ->
Event $ \p ->
do let t = pointTime p
dt = t t0
v = v0 + a0 * dt
v `seq` return (v, next t v a)
sumCircuit :: Num a =>
a
-> Circuit a a
sumCircuit init = start
where
start =
Circuit $ \a ->
Event $ \p ->
return (init, next init a)
next v0 a0 =
Circuit $ \a ->
Event $ \p ->
do let v = v0 + a0
v `seq` return (v, next v a)
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
(b, cir') <-
invokeDynamics p $
runEvent (runCircuit cir a)
writeIORef ref cir'
return b