mcmc-0.2.4: src/Mcmc/Monitor/ParameterBatch.hs
{-# LANGUAGE RankNTypes #-}
-- |
-- Module : Mcmc.Monitor.ParameterBatch
-- Description : Monitor parameters
-- Copyright : (c) Dominik Schrempf, 2020
-- License : GPL-3.0-or-later
--
-- Maintainer : dominik.schrempf@gmail.com
-- Stability : unstable
-- Portability : portable
--
-- Creation date: Fri May 29 11:11:49 2020.
--
-- Batch mean monitors.
module Mcmc.Monitor.ParameterBatch
( -- * Batch parameter monitors
MonitorParameterBatch (..),
(>$<),
(@#),
monitorBatchMean,
monitorBatchMeanF,
monitorBatchMeanE,
monitorBatchCustom,
)
where
import qualified Data.ByteString.Builder as BB
import qualified Data.Double.Conversion.ByteString as BC
import Data.Functor.Contravariant
-- | Instruction about a parameter to monitor via batch means. Usually, the
-- monitored parameter is average over the batch size. However, arbitrary
-- functions performing more complicated analyses on the states in the batch can
-- be provided.
--
-- Convert a batch monitor from one data type to another with '(>$<)'.
--
-- For example, batch monitor the mean of the first entry of a tuple:
--
-- @
-- mon = fst >$< monitorBatchMean
-- @
--
-- XXX: Batch monitors are slow at the moment because the monitored parameter
-- has to be extracted from the state for each iteration.
data MonitorParameterBatch a = MonitorParameterBatch
{ -- | Name of batch monitored parameter.
mbpName :: String,
-- | Instruction about how to extract the batch mean from the trace.
mbpFunc :: [a] -> BB.Builder
}
instance Contravariant (MonitorParameterBatch) where
contramap f (MonitorParameterBatch n m) = MonitorParameterBatch n (m . map f)
-- | Convert a batch parameter monitor from one data type to another.
--
-- For example, to batch monitor the mean of the first entry of a tuple:
--
-- @
-- mon = fst @# monitorBatchMean
-- @
(@#) :: (b -> a) -> MonitorParameterBatch a -> MonitorParameterBatch b
(@#) f (MonitorParameterBatch n m) = MonitorParameterBatch n (m . map f)
{-# DEPRECATED (@#) "Superseded by the contravariant instance, use '(>$<)'." #-}
mean :: Real a => [a] -> Double
mean xs = realToFrac (sum xs) / fromIntegral (length xs)
{-# SPECIALIZE mean :: [Double] -> Double #-}
{-# SPECIALIZE mean :: [Int] -> Double #-}
-- | Batch monitor. Print the mean with eight decimal places (half precision).
monitorBatchMean ::
Real a =>
-- | Name.
String ->
MonitorParameterBatch a
monitorBatchMean n = MonitorParameterBatch n (BB.byteString . BC.toFixed 8 . mean)
{-# SPECIALIZE monitorBatchMean :: String -> MonitorParameterBatch Int #-}
{-# SPECIALIZE monitorBatchMean :: String -> MonitorParameterBatch Double #-}
-- | Batch monitor. Print the mean with full precision computing the shortest
-- string of digits that correctly represent the number.
monitorBatchMeanF ::
Real a =>
-- | Name.
String ->
MonitorParameterBatch a
monitorBatchMeanF n = MonitorParameterBatch n (BB.byteString . BC.toShortest . mean)
{-# SPECIALIZE monitorBatchMeanF :: String -> MonitorParameterBatch Int #-}
{-# SPECIALIZE monitorBatchMeanF :: String -> MonitorParameterBatch Double #-}
-- | Batch monitor real float parameters such as 'Double' with scientific
-- notation and eight decimal places.
monitorBatchMeanE ::
Real a =>
-- | Name.
String ->
MonitorParameterBatch a
monitorBatchMeanE n = MonitorParameterBatch n (BB.byteString . BC.toExponential 8 . mean)
{-# SPECIALIZE monitorBatchMeanE :: String -> MonitorParameterBatch Int #-}
{-# SPECIALIZE monitorBatchMeanE :: String -> MonitorParameterBatch Double #-}
-- | Batch monitor parameters with custom lens and builder.
monitorBatchCustom ::
-- | Name.
String ->
-- | Function to calculate the batch mean.
([a] -> a) ->
-- | Custom builder.
(a -> BB.Builder) ->
MonitorParameterBatch a
monitorBatchCustom n f b = MonitorParameterBatch n (b . f)