module Simulation.Aivika.Trans.Var.Unboxed
(Var,
varChanged,
varChanged_,
newVar,
readVar,
varMemo,
writeVar,
modifyVar,
freezeVar) where
import Data.Array
import Simulation.Aivika.Trans.Session
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.Internal.Signal
import Simulation.Aivika.Trans.Ref
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Unboxed
import qualified Simulation.Aivika.Trans.Vector.Unboxed as UV
data Var m a =
Var { varXS :: UV.Vector m Double,
varMS :: UV.Vector m a,
varYS :: UV.Vector m a,
varChangedSource :: SignalSource m a }
newVar :: (MonadComp m, Unboxed m a) => a -> Simulation m (Var m a)
newVar a =
Simulation $ \r ->
do let sn = runSession r
xs <- UV.newVector sn
ms <- UV.newVector sn
ys <- UV.newVector sn
UV.appendVector xs $ spcStartTime $ runSpecs r
UV.appendVector ms a
UV.appendVector ys a
s <- invokeSimulation r newSignalSource
return Var { varXS = xs,
varMS = ms,
varYS = ms,
varChangedSource = s }
varMemo :: (MonadComp m, Unboxed m a) => Var m a -> Dynamics m a
varMemo v =
runEventWith CurrentEventsOrFromPast $
Event $ \p ->
do let xs = varXS v
ms = varMS v
ys = varYS v
t = pointTime p
count <- UV.vectorCount xs
let i = count 1
x <- UV.readVector xs i
if x < t
then do a <- UV.readVector ys i
UV.appendVector xs t
UV.appendVector ms a
UV.appendVector ys a
return a
else if x == t
then UV.readVector ms i
else do i <- UV.vectorBinarySearch xs t
if i >= 0
then UV.readVector ms i
else UV.readVector ms $ (i + 1) 1
readVar :: (MonadComp m, Unboxed m a) => Var m a -> Event m a
readVar v =
Event $ \p ->
do let xs = varXS v
ys = varYS v
t = pointTime p
count <- UV.vectorCount xs
let i = count 1
x <- UV.readVector xs i
if x <= t
then UV.readVector ys i
else do i <- UV.vectorBinarySearch xs t
if i >= 0
then UV.readVector ys i
else UV.readVector ys $ (i + 1) 1
writeVar :: (MonadComp m, Unboxed m a) => Var m a -> a -> Event m ()
writeVar v a =
Event $ \p ->
do let xs = varXS v
ms = varMS v
ys = varYS v
t = pointTime p
s = varChangedSource v
count <- UV.vectorCount xs
let i = count 1
x <- UV.readVector xs i
if t < x
then error "Cannot update the past data: writeVar."
else if t == x
then UV.writeVector ys i $! a
else do UV.appendVector xs t
UV.appendVector ms $! a
UV.appendVector ys $! a
invokeEvent p $ triggerSignal s a
modifyVar :: (MonadComp m, Unboxed m a) => Var m a -> (a -> a) -> Event m ()
modifyVar v f =
Event $ \p ->
do let xs = varXS v
ms = varMS v
ys = varYS v
t = pointTime p
s = varChangedSource v
count <- UV.vectorCount xs
let i = count 1
x <- UV.readVector xs i
if t < x
then error "Cannot update the past data: modifyVar."
else if t == x
then do a <- UV.readVector ys i
let b = f a
UV.writeVector ys i $! b
invokeEvent p $ triggerSignal s b
else do a <- UV.readVector ys i
let b = f a
UV.appendVector xs t
UV.appendVector ms $! b
UV.appendVector ys $! b
invokeEvent p $ triggerSignal s b
freezeVar :: (MonadComp m, Unboxed m a) => Var m a -> Event m (Array Int Double, Array Int a, Array Int a)
freezeVar v =
Event $ \p ->
do xs <- UV.freezeVector (varXS v)
ms <- UV.freezeVector (varMS v)
ys <- UV.freezeVector (varYS v)
return (xs, ms, ys)
varChanged :: Var m a -> Signal m a
varChanged v = publishSignal (varChangedSource v)
varChanged_ :: MonadComp m => Var m a -> Signal m ()
varChanged_ v = mapSignal (const ()) $ varChanged v