module Simulation.Aivika.Circuit
(
Circuit(..),
iterateCircuitInIntegTimes,
iterateCircuitInIntegTimes_,
iterateCircuitInIntegTimesMaybe,
iterateCircuitInIntegTimesEither,
iterateCircuitInTimes,
iterateCircuitInTimes_,
iterateCircuitInTimesMaybe,
iterateCircuitInTimesEither,
arrCircuit,
accumCircuit,
arrivalCircuit,
delayCircuit,
timeCircuit,
(<?<),
(>?>),
filterCircuit,
filterCircuitM,
neverCircuit,
circuitSignaling,
circuitProcessor,
integCircuit,
integCircuitEither,
sumCircuit,
sumCircuitEither,
circuitTransform,
traceCircuit) 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.Process
import Simulation.Aivika.Processor
import Simulation.Aivika.Task
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)
integCircuitEither :: Double
-> Circuit (Either Double Double) Double
integCircuitEither 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
case a0 of
Left v ->
v `seq` return (v, next t v a)
Right a0 -> do
let 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)
sumCircuitEither :: Num a =>
a
-> Circuit (Either a a) a
sumCircuitEither init = start
where
start =
Circuit $ \a ->
Event $ \p ->
return (init, next init a)
next v0 a0 =
Circuit $ \a ->
Event $ \p ->
case a0 of
Left v ->
v `seq` return (v, next v a)
Right a0 -> 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
iterateCircuitInPoints_ :: [Point] -> Circuit a a -> a -> Event ()
iterateCircuitInPoints_ [] cir a = return ()
iterateCircuitInPoints_ (p : ps) cir a =
enqueueEvent (pointTime p) $
Event $ \p' ->
do (a', cir') <- invokeEvent p $ runCircuit cir a
invokeEvent p $ iterateCircuitInPoints_ ps cir' a'
iterateCircuitInPoints :: [Point] -> Circuit a a -> a -> Event (Task a)
iterateCircuitInPoints ps cir a =
do let loop [] cir a source = triggerSignal source a
loop (p : ps) cir a source =
enqueueEvent (pointTime p) $
Event $ \p' ->
do (a', cir') <- invokeEvent p $ runCircuit cir a
invokeEvent p $ loop ps cir' a' source
source <- liftSimulation newSignalSource
task <- runTask $ processAwait $ publishSignal source
loop ps cir a source
return task
iterateCircuitInIntegTimes_ :: Circuit a a -> a -> Event ()
iterateCircuitInIntegTimes_ cir a =
Event $ \p ->
do let ps = integPointsStartingFrom p
invokeEvent p $
iterateCircuitInPoints_ ps cir a
iterateCircuitInTimes_ :: [Double] -> Circuit a a -> a -> Event ()
iterateCircuitInTimes_ ts cir a =
Event $ \p ->
do let ps = map (pointAt $ pointRun p) ts
invokeEvent p $
iterateCircuitInPoints_ ps cir a
iterateCircuitInIntegTimes :: Circuit a a -> a -> Event (Task a)
iterateCircuitInIntegTimes cir a =
Event $ \p ->
do let ps = integPointsStartingFrom p
invokeEvent p $
iterateCircuitInPoints ps cir a
iterateCircuitInTimes :: [Double] -> Circuit a a -> a -> Event (Task a)
iterateCircuitInTimes ts cir a =
Event $ \p ->
do let ps = map (pointAt $ pointRun p) ts
invokeEvent p $
iterateCircuitInPoints ps cir a
iterateCircuitInPointsMaybe :: [Point] -> Circuit a (Maybe a) -> a -> Event ()
iterateCircuitInPointsMaybe [] cir a = return ()
iterateCircuitInPointsMaybe (p : ps) cir a =
enqueueEvent (pointTime p) $
Event $ \p' ->
do (a', cir') <- invokeEvent p $ runCircuit cir a
case a' of
Nothing -> return ()
Just a' ->
invokeEvent p $ iterateCircuitInPointsMaybe ps cir' a'
iterateCircuitInIntegTimesMaybe :: Circuit a (Maybe a) -> a -> Event ()
iterateCircuitInIntegTimesMaybe cir a =
Event $ \p ->
do let ps = integPointsStartingFrom p
invokeEvent p $
iterateCircuitInPointsMaybe ps cir a
iterateCircuitInTimesMaybe :: [Double] -> Circuit a (Maybe a) -> a -> Event ()
iterateCircuitInTimesMaybe ts cir a =
Event $ \p ->
do let ps = map (pointAt $ pointRun p) ts
invokeEvent p $
iterateCircuitInPointsMaybe ps cir a
iterateCircuitInPointsEither :: [Point] -> Circuit a (Either b a) -> a -> Event (Task (Either b a))
iterateCircuitInPointsEither ps cir a =
do let loop [] cir ba source = triggerSignal source ba
loop ps cir ba@(Left b) source = triggerSignal source ba
loop (p : ps) cir (Right a) source =
enqueueEvent (pointTime p) $
Event $ \p' ->
do (ba', cir') <- invokeEvent p $ runCircuit cir a
invokeEvent p $ loop ps cir' ba' source
source <- liftSimulation newSignalSource
task <- runTask $ processAwait $ publishSignal source
loop ps cir (Right a) source
return task
iterateCircuitInIntegTimesEither :: Circuit a (Either b a) -> a -> Event (Task (Either b a))
iterateCircuitInIntegTimesEither cir a =
Event $ \p ->
do let ps = integPointsStartingFrom p
invokeEvent p $
iterateCircuitInPointsEither ps cir a
iterateCircuitInTimesEither :: [Double] -> Circuit a (Either b a) -> a -> Event (Task (Either b a))
iterateCircuitInTimesEither ts cir a =
Event $ \p ->
do let ps = map (pointAt $ pointRun p) ts
invokeEvent p $
iterateCircuitInPointsEither ps cir a
traceCircuit :: Maybe String
-> Maybe String
-> Circuit a b
-> Circuit a b
traceCircuit request response cir = Circuit $ loop cir where
loop cir a =
do (b, cir') <-
case request of
Nothing -> runCircuit cir a
Just message ->
traceEvent message $
runCircuit cir a
case response of
Nothing -> return (b, Circuit $ loop cir')
Just message ->
traceEvent message $
return (b, Circuit $ loop cir')