synthesizer-llvm-0.5: src/Synthesizer/LLVM/CausalParameterized/ProcessPrivate.hs
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE Rank2Types #-}
module Synthesizer.LLVM.CausalParameterized.ProcessPrivate where
import qualified Synthesizer.LLVM.Parameterized.SignalPrivate as Sig
import qualified Synthesizer.LLVM.Parameter as Param
import qualified LLVM.Extra.Arithmetic as A
import qualified LLVM.Extra.MaybeContinuation as Maybe
import qualified LLVM.Extra.Memory as Memory
import qualified LLVM.Core as LLVM
import LLVM.Extra.Class (MakeValueTuple, ValueTuple, )
import LLVM.Util.Loop (Phi, )
import LLVM.Core (Value, valueOf, CodeGenFunction, )
import qualified Control.Arrow as Arr
import qualified Control.Category as Cat
import Control.Arrow (arr, (^<<), (<<<), (&&&), )
import Control.Monad (liftM2, )
import Control.Applicative (Applicative, pure, (<*>), )
import Data.Word (Word32, )
import Foreign.Storable.Tuple ()
import Foreign.Storable (Storable, )
import qualified Number.Ratio as Ratio
import qualified Algebra.Field as Field
import qualified Algebra.Ring as Ring
import qualified Algebra.Additive as Additive
import NumericPrelude.Numeric
import NumericPrelude.Base hiding (and, iterate, map, zip, zipWith, take, takeWhile, )
import qualified Prelude as P
data T p a b =
forall state ioContext startParamTuple nextParamTuple.
(Storable startParamTuple,
Storable nextParamTuple,
MakeValueTuple startParamTuple,
MakeValueTuple nextParamTuple,
Memory.C (ValueTuple startParamTuple),
Memory.C (ValueTuple nextParamTuple),
Memory.C state) =>
Cons
(forall r c.
(Phi c) =>
ValueTuple nextParamTuple ->
a -> state -> Maybe.T r c (b, state))
-- compute next value
(forall r.
ValueTuple startParamTuple ->
CodeGenFunction r state)
-- initial state
(p -> IO (ioContext, (nextParamTuple, startParamTuple)))
{- initialization from IO monad
This will be run within Unsafe.performIO,
so no observable In/Out actions please!
-}
(ioContext -> IO ())
-- finalization from IO monad, also run within Unsafe.performIO
simple ::
(Storable startParamTuple,
Storable nextParamTuple,
MakeValueTuple startParamTuple, ValueTuple startParamTuple ~ startParamValue,
MakeValueTuple nextParamTuple, ValueTuple nextParamTuple ~ nextParamValue,
Memory.C startParamValue,
Memory.C nextParamValue,
Memory.C state) =>
(forall r c.
(Phi c) =>
nextParamValue ->
a -> state -> Maybe.T r c (b, state)) ->
(forall r.
startParamValue ->
CodeGenFunction r state) ->
Param.T p nextParamTuple ->
Param.T p startParamTuple -> T p a b
simple f start selectParam initial = Cons
(f . Param.value selectParam)
(start . Param.value initial)
(return . (,) () . Param.get (selectParam &&& initial))
(const $ return ())
toSignal :: T p () a -> Sig.T p a
toSignal (Cons next start createIOContext deleteIOContext) = Sig.Cons
(\ioContext -> next ioContext ())
start
createIOContext deleteIOContext
fromSignal :: Sig.T p b -> T p a b
fromSignal (Sig.Cons next start createIOContext deleteIOContext) = Cons
(\ioContext _ -> next ioContext)
start
createIOContext deleteIOContext
mapAccum ::
(Storable pnh, MakeValueTuple pnh, ValueTuple pnh ~ pnl, Memory.C pnl,
Storable psh, MakeValueTuple psh, ValueTuple psh ~ psl, Memory.C psl,
Memory.C s) =>
(forall r. pnl -> a -> s -> CodeGenFunction r (b,s)) ->
(forall r. psl -> CodeGenFunction r s) ->
Param.T p pnh ->
Param.T p psh ->
T p a b
mapAccum next start selectParamN selectParamS =
simple
(\p a s -> Maybe.lift $ next p a s)
start
selectParamN selectParamS
map ::
(Storable ph, MakeValueTuple ph, ValueTuple ph ~ pl, Memory.C pl) =>
(forall r. pl -> a -> CodeGenFunction r b) ->
Param.T p ph ->
T p a b
map f selectParamF =
mapAccum
(\p a s -> fmap (flip (,) s) $ f p a)
(const $ return ())
selectParamF
(return ())
mapSimple ::
(forall r. a -> CodeGenFunction r b) ->
T p a b
mapSimple f =
map (const f) (return ())
zipWithSimple ::
(forall r. a -> b -> CodeGenFunction r c) ->
T p (a,b) c
zipWithSimple f =
mapSimple (uncurry f)
apply :: T p a b -> Sig.T p a -> Sig.T p b
apply proc sig =
toSignal (proc <<< fromSignal sig)
feedFst :: Sig.T p a -> T p b (a,b)
feedFst sig =
fromSignal sig &&& Cat.id
feedSnd :: Sig.T p a -> T p b (b,a)
feedSnd sig =
Cat.id &&& fromSignal sig
{-
Very similar to 'apply',
since 'apply' can be considered being of type
@T p a b -> T p () a -> T p () b@.
-}
compose :: T p a b -> T p b c -> T p a c
compose
(Cons nextA startA createIOContextA deleteIOContextA)
(Cons nextB startB createIOContextB deleteIOContextB) =
Cons
(\(paramA, paramB) a (sa0,sb0) ->
do (b,sa1) <- nextA paramA a sa0
(c,sb1) <- nextB paramB b sb0
return (c, (sa1,sb1)))
(\(paramA, paramB) ->
liftM2 (,)
(startA paramA)
(startB paramB))
(\p -> do
(ca,(nextParamA,startParamA)) <- createIOContextA p
(cb,(nextParamB,startParamB)) <- createIOContextB p
return ((ca,cb),
((nextParamA, nextParamB),
(startParamA, startParamB))))
(\(ca,cb) ->
deleteIOContextA ca >>
deleteIOContextB cb)
first :: T p b c -> T p (b, d) (c, d)
first (Cons next start createIOContext deleteIOContext) = Cons
(\ioContext (b,d) sa0 ->
do (c,sa1) <- next ioContext b sa0
return ((c,d), sa1))
start
createIOContext deleteIOContext
instance Cat.Category (T p) where
id = mapSimple return
(.) = flip compose
instance Arr.Arrow (T p) where
arr f = mapSimple (return . f)
first = first
instance Functor (T p a) where
fmap = (^<<)
instance Applicative (T p a) where
pure x = Arr.arr (const x)
f <*> x = uncurry ($) ^<< f&&&x
instance (A.Additive b) => Additive.C (T p a b) where
zero = pure A.zero
negate x = mapSimple A.neg <<< x
x + y = zipWithSimple A.add <<< x&&&y
x - y = zipWithSimple A.sub <<< x&&&y
instance (A.PseudoRing b, A.IntegerConstant b) => Ring.C (T p a b) where
one = pure A.one
fromInteger n = pure (A.fromInteger' n)
x * y = zipWithSimple A.mul <<< x&&&y
instance (A.Field b, A.RationalConstant b) => Field.C (T p a b) where
fromRational' x = pure (A.fromRational' $ Ratio.toRational98 x)
x / y = zipWithSimple A.fdiv <<< x&&&y
instance (A.PseudoRing b, A.Real b, A.IntegerConstant b) => P.Num (T p a b) where
fromInteger n = pure (A.fromInteger' n)
negate x = mapSimple A.neg <<< x
x + y = zipWithSimple A.add <<< x&&&y
x - y = zipWithSimple A.sub <<< x&&&y
x * y = zipWithSimple A.mul <<< x&&&y
abs x = mapSimple A.abs <<< x
signum x = mapSimple A.signum <<< x
instance (A.Field b, A.Real b, A.RationalConstant b) => P.Fractional (T p a b) where
fromRational x = pure (A.fromRational' x)
x / y = zipWithSimple A.fdiv <<< x&&&y
{- |
Not quite the loop of ArrowLoop
because we need a delay of one time step
and thus an initialization value.
For a real ArrowLoop.loop, that is a zero-delay loop,
we would formally need a MonadFix instance of CodeGenFunction.
But this will not become reality, since LLVM is not able to re-order code
in a way that allows to access a result before creating the input.
-}
loop ::
(Storable ch,
MakeValueTuple ch, ValueTuple ch ~ c,
Memory.C c) =>
Param.T p ch -> T p (a,c) (b,c) -> T p a b
loop initial (Cons next start createIOContext deleteIOContext) =
Cons
(\p a0 (c0,s0) -> do
((b1,c1), s1) <- next p (a0,c0) s0
return (b1,(c1,s1)))
(\(i,p) -> fmap ((,) (Param.value initial i)) $ start p)
(\p -> do
(ctx,(nextParam,startParam)) <- createIOContext p
return (ctx,
(nextParam, (Param.get initial p, startParam))))
deleteIOContext
takeWhile ::
(Storable ph, MakeValueTuple ph, ValueTuple ph ~ pl, Memory.C pl) =>
(forall r. pl -> a -> CodeGenFunction r (Value Bool)) ->
Param.T p ph ->
T p a a
takeWhile check selectParam = simple
(\p a () -> do
Maybe.guard =<< Maybe.lift (check p a)
return (a, ()))
return
selectParam
(return ())
take ::
Param.T p Int ->
T p a a
take len =
snd ^<<
takeWhile (const $ A.cmp LLVM.CmpLT (valueOf 0) . fst) (return ()) <<<
feedFst
(Sig.iterate (const A.dec) (return ())
((fromIntegral :: Int -> Word32) . max 0 ^<< len))
{- |
The first output value is the initial value.
Thus 'integrate' delays by one sample compared with 'integrate0'.
-}
integrate ::
(Storable a, A.Additive al,
MakeValueTuple a, ValueTuple a ~ al, Memory.C al) =>
Param.T p a ->
T p al al
integrate =
flip loop (arr snd &&& zipWithSimple A.add)
integrate0 ::
(Storable a, A.Additive al,
MakeValueTuple a, ValueTuple a ~ al, Memory.C al) =>
Param.T p a ->
T p al al
integrate0 =
flip loop ((\a -> (a,a)) ^<< zipWithSimple A.add)