{-# LANGUAGE TypeFamilies, ConstrainedClassMethods #-}
-- |
-- Module : Simulation.Aivika.Trans.Var
-- Copyright : Copyright (c) 2009-2017, David Sorokin <david.sorokin@gmail.com>
-- License : BSD3
-- Maintainer : David Sorokin <david.sorokin@gmail.com>
-- Stability : experimental
-- Tested with: GHC 8.0.1
--
-- This module defines a variable that is bound up with the event queue and
-- that keeps the history of changes storing the values in arrays, which
-- allows using the variable in differential and difference equations of
-- System Dynamics within hybrid discrete-continuous simulation.
--
-- Because of using the arrays, it would usually be a logical mistake to
-- use this variable for collecting statistics. In most cases,
-- the statistics can actually be collected with a very small footprint
-- by updating immutable 'SamplingStats' and 'TimingStats' values in
-- a mutable 'Ref' reference.
--
module Simulation.Aivika.Trans.Var (MonadVar(..)) where
import Data.Array
import Simulation.Aivika.Trans.Ref
import Simulation.Aivika.Trans.DES
import Simulation.Aivika.Trans.Internal.Simulation
import Simulation.Aivika.Trans.Internal.Dynamics
import Simulation.Aivika.Trans.Internal.Event
import Simulation.Aivika.Trans.Signal
import Simulation.Aivika.Trans.Statistics
-- | A type class of monads within which we can create mutable variables.
class MonadDES m => MonadVar m where
-- | Like the 'Ref' reference but keeps the history of changes in
-- different time points. The 'Var' variable is safe to be used in
-- the hybrid discrete-continuous simulation. Only this variable can
-- be much slower than the reference.
--
-- For example, the memoised values of the variable can be used in
-- the differential and difference equations of System Dynamics, while
-- the variable iself can be updated within the discrete event simulation.
--
-- Because of using arrays, it would usually be a logical mistake to use
-- the variable for collecting statistics. In most cases, the statistics
-- can actually be collected with a very small footprint by updating immutable
-- 'SamplingStats' and 'TimingStats' values in a mutable @Ref@ reference.
data Var m a
-- | Create a new variable.
newVar :: a -> Simulation m (Var m a)
-- | Read the first actual, i.e. memoised, value of a variable for the requested time
-- actuating the current events from the queue if needed.
--
-- This computation can be used in the ordinary differential and
-- difference equations of System Dynamics.
varMemo :: Var m a -> Dynamics m a
-- | Read the recent actual value of a variable for the requested time.
--
-- This computation is destined to be used within discrete event simulation.
readVar :: Var m a -> Event m a
-- | Write a new value into the variable.
writeVar :: Var m a -> a -> Event m ()
-- | Mutate the contents of the variable.
modifyVar :: Var m a -> (a -> a) -> Event m ()
-- | Freeze the variable and return in arrays the time points and the corresponding
-- first and last values when the variable had changed or had been memoised in
-- different time points: (1) the time points are sorted in ascending order;
-- (2) the first and last actual values per each time point are provided.
--
-- If you need to get all changes including those ones that correspond to the same
-- simulation time points then you can use the 'newSignalHistory' function passing
-- in the 'varChanged' signal to it and then call function 'readSignalHistory'.
freezeVar :: Var m a -> Event m (Array Int Double, Array Int a, Array Int a)
-- | Return a signal that notifies about every change of the variable state.
varChanged :: Var m a -> Signal m a
-- | Return a signal that notifies about every change of the variable state.
varChanged_ :: MonadDES m => Var m a -> Signal m ()