packages feed

fei-nn-1.0.0: src/MXNet/NN/Session.hs

{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TemplateHaskell        #-}
module MXNet.NN.Session where

import           Data.Kind            (Constraint)
import qualified Data.Type.Index      as DT
import qualified Data.Type.Product    as DT
import qualified GHC.TypeLits         as L
import           RIO
import qualified RIO.State            as ST

import           MXNet.Base
import           MXNet.NN.TaggedState (liftSub, toPair)
import           MXNet.NN.Types       (Module, ModuleSet, ModuleState,
                                       TaggedModuleState)

class Session (sess :: (* -> *) -> * -> *) (sst :: *) | sess -> sst, sst -> sess where
    type SessionDType sst
    type SessionHasModule sst (t :: L.Symbol) :: Constraint
    runSession    :: sess m r -> sst -> m (r, sst)
    subSession    :: MonadIO m => SessionHasModule sst t => Module t (SessionDType sst) m r -> sess m r
    sessionStates :: MonadIO m => sess m [(String, ModuleState (SessionDType sst))]

class HasSessionRef e s | e -> s where
    sessionRefL :: Lens' e (MVar s)

askSession :: (MonadIO m, MonadReader e m, HasSessionRef e s, Session sess s)
           => sess m r -> m r
askSession proc = do
    env <- ask
    let var = env ^. sessionRefL
    st <- liftIO $ takeMVar var
    (rt, st) <- runSession proc st
    liftIO $ putMVar var st
    return rt

withSession :: (MonadIO m, Session sess s)
            => MVar s -> sess m r -> m r
withSession var proc = do
    st <- liftIO $ takeMVar var
    (rt, st) <- runSession proc st
    liftIO $ putMVar var st
    return rt

instance (DT.Every L.KnownSymbol t) => Session (ModuleSet t a) (DT.Prod (TaggedModuleState a) t) where
    type SessionDType (DT.Prod (TaggedModuleState a) t) = a
    type SessionHasModule (DT.Prod (TaggedModuleState a) t) t' = DT.Elem t t'
    runSession = ST.runStateT
    subSession = liftSub
    sessionStates = walk <$> ST.get
      where
        walk :: DT.Every L.KnownSymbol t => DT.Prod (TaggedModuleState a) t -> [(String, ModuleState a)]
        walk DT.Ø           = []
        walk (v DT.:< rest) = toPair v : walk rest

instance (L.KnownSymbol t) => Session (Module t a) (TaggedModuleState a t) where
    type SessionDType (TaggedModuleState a t) = a
    type SessionHasModule (TaggedModuleState a t) t' = t ~ t'
    runSession = ST.runStateT
    subSession = id
    sessionStates = (:[]) . toPair <$> ST.get

class CallbackClass c where
    begOfBatch :: ( L.KnownSymbol t
                  , DType a
                  , MonadIO m
                  , MonadReader env m
                  , HasLogFunc env
                  , HasCallStack)
        => Int -> Int -> c -> Module t a m ()
    begOfBatch _ _ _ = return ()
    endOfBatch :: ( L.KnownSymbol t
                  , DType a
                  , MonadIO m
                  , MonadReader env m
                  , HasLogFunc env
                  , HasCallStack)
        => Int -> Int -> c -> Module t a m ()
    endOfBatch _ _ _ = return ()
    begOfEpoch :: ( L.KnownSymbol t
                  , DType a
                  , MonadIO m
                  , MonadReader env m
                  , HasLogFunc env
                  , HasCallStack)
        => Int -> Int -> c -> Module t a m ()
    begOfEpoch _ _ _ = return ()
    endOfEpoch :: ( L.KnownSymbol t
                  , DType a
                  , MonadIO m
                  , MonadReader env m
                  , HasLogFunc env
                  , HasCallStack)
        => Int -> Int -> c -> Module t a m ()
    endOfEpoch _ _ _ = return ()
    endOfVal   :: ( L.KnownSymbol t
                  , DType a
                  , MonadIO m
                  , MonadReader env m
                  , HasLogFunc env
                  , HasCallStack)
        => Int -> Int -> c -> Module t a m ()
    endOfVal   _ _ _ = return ()
data Callback where
    Callback :: CallbackClass a => a -> Callback

instance CallbackClass Callback where
    begOfBatch i n (Callback a) = begOfBatch i n a
    endOfBatch i n (Callback a) = endOfBatch i n a
    begOfEpoch i n (Callback a) = begOfEpoch i n a
    endOfEpoch i n (Callback a) = endOfEpoch i n a
    endOfVal   i n (Callback a) = endOfVal   i n a