module Simulation.Aivika.Trans.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 Simulation.Aivika.Trans.Session
import Simulation.Aivika.Trans.ProtoRef
import Simulation.Aivika.Trans.Comp
import Simulation.Aivika.Trans.Internal.Specs
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Dynamics
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Dynamics.Memo
import Simulation.Aivika.Trans.Transform
import Simulation.Aivika.Trans.SystemDynamics
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Stream
import Simulation.Aivika.Trans.Processor
import Simulation.Aivika.Arrival (Arrival(..))
newtype Circuit m a b =
Circuit { runCircuit :: a -> Event m (b, Circuit m a b)
}
instance MonadComp m => C.Category (Circuit m) 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 MonadComp m => Arrow (Circuit m) 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 (MonadComp m, MonadFix m) => ArrowLoop (Circuit m) where
loop (Circuit f) =
Circuit $ \b ->
Event $ \p ->
do rec ((c, d), cir) <- invokeEvent p (f (b, d))
return (c, loop cir)
instance MonadComp m => ArrowChoice (Circuit m) 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 :: MonadComp m => Circuit m a b -> Signal m a -> Signal m b
circuitSignaling (Circuit cir) sa =
Signal { handleSignal = \f ->
Event $ \p ->
do let s = runSession (pointRun p)
r <- newProtoRef s cir
invokeEvent p $
handleSignal sa $ \a ->
Event $ \p ->
do cir <- readProtoRef r
(b, Circuit cir') <- invokeEvent p (cir a)
writeProtoRef r cir'
invokeEvent p (f b) }
circuitProcessor :: MonadComp m => Circuit m a b -> Processor m 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 :: MonadComp m => (a -> Event m b) -> Circuit m a b
arrCircuit f =
let x =
Circuit $ \a ->
Event $ \p ->
do b <- invokeEvent p (f a)
return (b, x)
in x
accumCircuit :: MonadComp m => (acc -> a -> Event m (acc, b)) -> acc -> Circuit m a b
accumCircuit f acc =
Circuit $ \a ->
Event $ \p ->
do (acc', b) <- invokeEvent p (f acc a)
return (b, accumCircuit f acc')
arrivalCircuit :: MonadComp m => Circuit m 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 :: MonadComp m => a -> Circuit m a a
delayCircuit a0 =
Circuit $ \a ->
return (a0, delayCircuit a)
timeCircuit :: MonadComp m => Circuit m a Double
timeCircuit =
Circuit $ \a ->
Event $ \p ->
return (pointTime p, timeCircuit)
(>?>) :: MonadComp m
=> Circuit m a (Maybe b)
-> Circuit m b c
-> Circuit m 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')
(<?<) :: MonadComp m
=> Circuit m b c
-> Circuit m a (Maybe b)
-> Circuit m a (Maybe c)
(<?<) = flip (>?>)
filterCircuit :: MonadComp m => (a -> Bool) -> Circuit m a b -> Circuit m a (Maybe b)
filterCircuit pred = filterCircuitM (return . pred)
filterCircuitM :: MonadComp m => (a -> Event m Bool) -> Circuit m a b -> Circuit m 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 :: MonadComp m => Circuit m a (Maybe b)
neverCircuit =
Circuit $ \a -> return (Nothing, neverCircuit)
integCircuit :: MonadComp m
=> Double
-> Circuit m 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 :: (MonadComp m, Num a) =>
a
-> Circuit m 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 :: MonadComp m => Circuit m a b -> Transform m a b
circuitTransform cir = Transform start
where
start m =
Simulation $ \r ->
do let s = runSession r
ref <- newProtoRef s cir
invokeSimulation r $
memo0Dynamics (next ref m)
next ref m =
Dynamics $ \p ->
do a <- invokeDynamics p m
cir <- readProtoRef ref
(b, cir') <-
invokeDynamics p $
runEvent (runCircuit cir a)
writeProtoRef ref cir'
return b