-- |
-- Module     : Simulation.Aivika.Trans.Transform.Extra
-- 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 auxiliary computations such as interpolation ones
-- that complement the memoization, for example. There are scan computations too.
--

module Simulation.Aivika.Trans.Transform.Extra
       (-- * Interpolation
        initTransform,
        discreteTransform,
        interpolatingTransform,
        -- * Scans
        scanTransform,
        scan1Transform) where

import Control.Monad
import Control.Monad.Fix

import Simulation.Aivika.Trans.Dynamics
import Simulation.Aivika.Trans.Dynamics.Extra
import Simulation.Aivika.Trans.Transform
import Simulation.Aivika.Trans.Transform.Memo

-- | A transform that returns the initial value.
initTransform :: Monad m => Transform m a a
{-# INLINE initTransform #-}
initTransform :: forall (m :: * -> *) a. Monad m => Transform m a a
initTransform = (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall (m :: * -> *) a b.
(Dynamics m a -> Simulation m (Dynamics m b)) -> Transform m a b
Transform ((Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a)
-> (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall a b. (a -> b) -> a -> b
$ Dynamics m a -> Simulation m (Dynamics m a)
forall a. a -> Simulation m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Dynamics m a -> Simulation m (Dynamics m a))
-> (Dynamics m a -> Dynamics m a)
-> Dynamics m a
-> Simulation m (Dynamics m a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dynamics m a -> Dynamics m a
forall (m :: * -> *) a. Dynamics m a -> Dynamics m a
initDynamics

-- | A transform that discretizes the computation in the integration time points.
discreteTransform :: Monad m => Transform m a a
{-# INLINE discreteTransform #-}
discreteTransform :: forall (m :: * -> *) a. Monad m => Transform m a a
discreteTransform = (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall (m :: * -> *) a b.
(Dynamics m a -> Simulation m (Dynamics m b)) -> Transform m a b
Transform ((Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a)
-> (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall a b. (a -> b) -> a -> b
$ Dynamics m a -> Simulation m (Dynamics m a)
forall a. a -> Simulation m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Dynamics m a -> Simulation m (Dynamics m a))
-> (Dynamics m a -> Dynamics m a)
-> Dynamics m a
-> Simulation m (Dynamics m a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dynamics m a -> Dynamics m a
forall (m :: * -> *) a. Dynamics m a -> Dynamics m a
discreteDynamics

-- | A tranform that interpolates the computation based on the integration time points only.
-- Unlike the 'discreteTransform' computation it knows about the intermediate 
-- time points that are used in the Runge-Kutta method.
interpolatingTransform :: Monad m => Transform m a a
{-# INLINE interpolatingTransform #-}
interpolatingTransform :: forall (m :: * -> *) a. Monad m => Transform m a a
interpolatingTransform = (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall (m :: * -> *) a b.
(Dynamics m a -> Simulation m (Dynamics m b)) -> Transform m a b
Transform ((Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a)
-> (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall a b. (a -> b) -> a -> b
$ Dynamics m a -> Simulation m (Dynamics m a)
forall a. a -> Simulation m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Dynamics m a -> Simulation m (Dynamics m a))
-> (Dynamics m a -> Dynamics m a)
-> Dynamics m a
-> Simulation m (Dynamics m a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Dynamics m a -> Dynamics m a
forall (m :: * -> *) a. Dynamics m a -> Dynamics m a
interpolateDynamics 

-- | Like the standard 'scanl1' function but applied to values in 
-- the integration time points. The accumulator values are transformed
-- according to the second argument, which should be either  
-- 'memo0Transform' or its unboxed version.
scan1Transform :: MonadFix m => (a -> a -> a) -> Transform m a a -> Transform m a a
{-# INLINE scan1Transform #-}
scan1Transform :: forall (m :: * -> *) a.
MonadFix m =>
(a -> a -> a) -> Transform m a a -> Transform m a a
scan1Transform a -> a -> a
f (Transform Dynamics m a -> Simulation m (Dynamics m a)
tr) = (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall (m :: * -> *) a b.
(Dynamics m a -> Simulation m (Dynamics m b)) -> Transform m a b
Transform ((Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a)
-> (Dynamics m a -> Simulation m (Dynamics m a)) -> Transform m a a
forall a b. (a -> b) -> a -> b
$ (a -> a -> a)
-> (Dynamics m a -> Simulation m (Dynamics m a))
-> Dynamics m a
-> Simulation m (Dynamics m a)
forall (m :: * -> *) a.
MonadFix m =>
(a -> a -> a)
-> (Dynamics m a -> Simulation m (Dynamics m a))
-> Dynamics m a
-> Simulation m (Dynamics m a)
scan1Dynamics a -> a -> a
f Dynamics m a -> Simulation m (Dynamics m a)
tr

-- | Like the standard 'scanl' function but applied to values in 
-- the integration time points. The accumulator values are transformed
-- according to the third argument, which should be either
-- 'memo0Transform' or its unboxed version.
scanTransform :: MonadFix m => (a -> b -> a) -> a -> Transform m a a -> Transform m b a
{-# INLINE scanTransform #-}
scanTransform :: forall (m :: * -> *) a b.
MonadFix m =>
(a -> b -> a) -> a -> Transform m a a -> Transform m b a
scanTransform a -> b -> a
f a
acc (Transform Dynamics m a -> Simulation m (Dynamics m a)
tr) = (Dynamics m b -> Simulation m (Dynamics m a)) -> Transform m b a
forall (m :: * -> *) a b.
(Dynamics m a -> Simulation m (Dynamics m b)) -> Transform m a b
Transform ((Dynamics m b -> Simulation m (Dynamics m a)) -> Transform m b a)
-> (Dynamics m b -> Simulation m (Dynamics m a)) -> Transform m b a
forall a b. (a -> b) -> a -> b
$ (a -> b -> a)
-> a
-> (Dynamics m a -> Simulation m (Dynamics m a))
-> Dynamics m b
-> Simulation m (Dynamics m a)
forall (m :: * -> *) a b.
MonadFix m =>
(a -> b -> a)
-> a
-> (Dynamics m a -> Simulation m (Dynamics m a))
-> Dynamics m b
-> Simulation m (Dynamics m a)
scanDynamics a -> b -> a
f a
acc Dynamics m a -> Simulation m (Dynamics m a)
tr