mcmc 0.2.0 → 0.2.1
raw patch · 14 files changed
+274/−249 lines, 14 filesdep +double-conversiondep −text
Dependencies added: double-conversion
Dependencies removed: text
Files
- ChangeLog.md +12/−3
- bench/Normal.hs +1/−1
- bench/Poisson.hs +2/−2
- mcmc.cabal +3/−3
- src/Mcmc/Internal/ByteString.hs +46/−0
- src/Mcmc/Mcmc.hs +19/−20
- src/Mcmc/Monitor.hs +80/−83
- src/Mcmc/Monitor/Log.hs +4/−5
- src/Mcmc/Monitor/Parameter.hs +34/−45
- src/Mcmc/Monitor/ParameterBatch.hs +29/−48
- src/Mcmc/Monitor/Time.hs +7/−8
- src/Mcmc/Proposal.hs +33/−27
- src/Mcmc/Save.hs +3/−3
- test/Mcmc/SaveSpec.hs +1/−1
ChangeLog.md view
@@ -2,10 +2,19 @@ # Markov chain Monte Carlo sampling - ChangeLog -## 0.1.3+## Unreleased changes -Many changes; notably it is now possible to continue a Markov chain run. +## 0.2.1 -## Unreleased changes+- Consistently use ByteString instead of Text.+- Verbosity levels.+- Improved handling of proposals, moves, and monitors.+- Bactrian moves.+- Many small changes.+++## 0.1.3++Many changes; notably it is now possible to continue a Markov chain run.
bench/Normal.hs view
@@ -40,7 +40,7 @@ [slideSymmetric "medium" 1 1.0 True] mons :: [MonitorParameter Double]-mons = [monitorRealFloat "mu"]+mons = [monitorDouble "mu"] monStd :: MonitorStdOut Double monStd = monitorStdOut mons 200
bench/Poisson.hs view
@@ -60,10 +60,10 @@ initial = (0, 0) monAlpha :: MonitorParameter I-monAlpha = _1 @. monitorRealFloat "alpha"+monAlpha = _1 @. monitorDouble "alpha" monBeta :: MonitorParameter I-monBeta = _2 @. monitorRealFloat "beta"+monBeta = _2 @. monitorDouble "beta" monStd :: MonitorStdOut I monStd = monitorStdOut [monAlpha, monBeta] 150
mcmc.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: mcmc-version: 0.2.0+version: 0.2.1 synopsis: Sample from a posterior using Markov chain Monte Carlo description: Please see the README on GitHub at <https://github.com/dschrempf/mcmc#readme> category: Math, Statistics@@ -27,6 +27,7 @@ library exposed-modules: Mcmc+ Mcmc.Internal.ByteString Mcmc.Item Mcmc.Mcmc Mcmc.Metropolis@@ -59,11 +60,11 @@ , containers , data-default , directory+ , double-conversion , log-domain , microlens , mwc-random , statistics- , text , time , transformers , vector@@ -111,6 +112,5 @@ , microlens , mwc-random , statistics- , text , vector default-language: Haskell2010
+ src/Mcmc/Internal/ByteString.hs view
@@ -0,0 +1,46 @@+-- |+-- Module : Mcmc.Internal.ByteString+-- Description : ByteString tools+-- Copyright : (c) Dominik Schrempf, 2020+-- License : GPL-3.0-or-later+--+-- Maintainer : dominik.schrempf@gmail.com+-- Stability : unstable+-- Portability : portable+--+-- Creation date: Mon Aug 3 10:46:27 2020.+module Mcmc.Internal.ByteString+ ( alignRightWith,+ alignRight,+ alignLeftWith,+ alignLeft,+ )+where++import qualified Data.ByteString.Lazy.Char8 as BL++-- | For a given width, align string to the right; use given fill character;+-- trim on the left if string is longer.+alignRightWith :: Char -> Int -> BL.ByteString -> BL.ByteString+alignRightWith c n s =+ BL.replicate (fromIntegral n - l) c <> BL.take (fromIntegral n) s+ where+ l = BL.length s++-- | For a given width, align string to the right; trim on the left if string is+-- longer.+alignRight :: Int -> BL.ByteString -> BL.ByteString+alignRight = alignRightWith ' '++-- | For a given width, align string to the left; use given fill character; trim+-- on the right if string is longer.+alignLeftWith :: Char -> Int -> BL.ByteString -> BL.ByteString+alignLeftWith c n s =+ BL.take (fromIntegral n) s <> BL.replicate (fromIntegral n - l) c+ where+ l = BL.length s++-- | For a given width, align string to the left; trim on the right if string is+-- longer.+alignLeft :: Int -> BL.ByteString -> BL.ByteString+alignLeft = alignLeftWith ' '
src/Mcmc/Mcmc.hs view
@@ -35,10 +35,8 @@ import Control.Monad.IO.Class import Control.Monad.Trans.State import Data.Aeson+import qualified Data.ByteString.Lazy.Char8 as BL import Data.Maybe-import qualified Data.Text.Lazy as T-import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.IO as T import Data.Time.Clock import Data.Time.Format import Mcmc.Monitor@@ -55,54 +53,54 @@ -- required, but it is used by the different inference algorithms. type Mcmc a = StateT (Status a) IO -msgPrepare :: Char -> Text -> Text-msgPrepare c t = T.cons c $ ": " <> t+msgPrepare :: Char -> BL.ByteString -> BL.ByteString+msgPrepare c t = BL.cons c $ ": " <> t -- | Write to standard output and log file.-mcmcOutT :: Text -> Mcmc a ()+mcmcOutT :: BL.ByteString -> Mcmc a () mcmcOutT msg = do h <- fromMaybe (error "mcmcOut: Log handle is missing.") <$> gets logHandle- liftIO $ T.putStrLn msg >> T.hPutStrLn h msg+ liftIO $ BL.putStrLn msg >> BL.hPutStrLn h msg -- | Write to standard output and log file. mcmcOutS :: String -> Mcmc a ()-mcmcOutS = mcmcOutT . T.pack+mcmcOutS = mcmcOutT . BL.pack -- Perform warning action. mcmcWarnA :: Mcmc a () -> Mcmc a () mcmcWarnA a = gets verbosity >>= \v -> info v a -- | Print warning message.-mcmcWarnT :: Text -> Mcmc a ()+mcmcWarnT :: BL.ByteString -> Mcmc a () mcmcWarnT = mcmcWarnA . mcmcOutT . msgPrepare 'W' -- | Print warning message. mcmcWarnS :: String -> Mcmc a ()-mcmcWarnS = mcmcWarnT . T.pack+mcmcWarnS = mcmcWarnT . BL.pack -- Perform info action. mcmcInfoA :: Mcmc a () -> Mcmc a () mcmcInfoA a = gets verbosity >>= \v -> info v a -- | Print info message.-mcmcInfoT :: Text -> Mcmc a ()+mcmcInfoT :: BL.ByteString -> Mcmc a () mcmcInfoT = mcmcInfoA . mcmcOutT . msgPrepare 'I' -- | Print info message. mcmcInfoS :: String -> Mcmc a ()-mcmcInfoS = mcmcInfoT . T.pack+mcmcInfoS = mcmcInfoT . BL.pack -- Perform debug action. mcmcDebugA :: Mcmc a () -> Mcmc a () mcmcDebugA a = gets verbosity >>= \v -> debug v a -- | Print debug message.-mcmcDebugT :: Text -> Mcmc a ()+mcmcDebugT :: BL.ByteString -> Mcmc a () mcmcDebugT = mcmcDebugA . mcmcOutT . msgPrepare 'D' -- | Print debug message. mcmcDebugS :: String -> Mcmc a ()-mcmcDebugS = mcmcDebugT . T.pack+mcmcDebugS = mcmcDebugT . BL.pack -- | Auto tune the 'Proposal's in the 'Cycle' of the chain. Reset acceptance counts. -- See 'autotuneCycle'.@@ -124,7 +122,7 @@ put $ s {acceptance = resetA a} -- | Print short summary of 'Proposal's in 'Cycle'. See 'summarizeCycle'.-mcmcSummarizeCycle :: Mcmc a Text+mcmcSummarizeCycle :: Mcmc a BL.ByteString mcmcSummarizeCycle = do a <- gets acceptance c <- gets cycle@@ -143,11 +141,12 @@ fe <- liftIO $ doesFileExist lfn mh <- liftIO $ case verbosity s of Quiet -> return Nothing- _ -> Just <$> case (fe, n, frc) of- (False, _, _) -> openFile lfn WriteMode- (True, 0, True) -> openFile lfn WriteMode- (True, 0, False) -> error "mcmcInit: Log file exists; use 'force' to overwrite output files."- (True, _, _) -> openFile lfn AppendMode+ _ ->+ Just <$> case (fe, n, frc) of+ (False, _, _) -> openFile lfn WriteMode+ (True, 0, True) -> openFile lfn WriteMode+ (True, 0, False) -> error "mcmcInit: Log file exists; use 'force' to overwrite output files."+ (True, _, _) -> openFile lfn AppendMode put s {logHandle = mh} mcmcDebugS $ "Log file name: " ++ lfn ++ "." mcmcDebugT "Log file opened."
src/Mcmc/Monitor.hs view
@@ -31,12 +31,11 @@ where import Control.Monad+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy.Char8 as BL import Data.Int-import qualified Data.Text.Lazy as T-import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Lazy.IO as T import Data.Time.Clock+import Mcmc.Internal.ByteString import Mcmc.Item import Mcmc.Monitor.Log import Mcmc.Monitor.Parameter@@ -52,23 +51,21 @@ -- | A 'Monitor' describes which part of the Markov chain should be logged and -- where. Further, they allow output of summary statistics per iteration in a -- flexible way.-data Monitor a- = Monitor- { -- | Monitor writing to standard output.- mStdOut :: MonitorStdOut a,- -- | Monitors writing to files.- mFiles :: [MonitorFile a],- -- | Monitors calculating batch means and- -- writing to files.- mBatches :: [MonitorBatch a]- }+data Monitor a = Monitor+ { -- | Monitor writing to standard output.+ mStdOut :: MonitorStdOut a,+ -- | Monitors writing to files.+ mFiles :: [MonitorFile a],+ -- | Monitors calculating batch means and+ -- writing to files.+ mBatches :: [MonitorBatch a]+ } -- | Monitor to standard output; constructed with 'monitorStdOut'.-data MonitorStdOut a- = MonitorStdOut- { msParams :: [MonitorParameter a],- msPeriod :: Int- }+data MonitorStdOut a = MonitorStdOut+ { msParams :: [MonitorParameter a],+ msPeriod :: Int+ } -- | Monitor to standard output. monitorStdOut ::@@ -81,27 +78,27 @@ | p < 1 = error "monitorStdOut: Monitor period has to be 1 or larger." | otherwise = MonitorStdOut ps p -msIWidth :: Int64+msIWidth :: Int msIWidth = 12 -msWidth :: Int64+msWidth :: Int msWidth = 22 -msRenderRow :: [Text] -> Text-msRenderRow xs = T.justifyRight msIWidth ' ' (head xs) <> T.concat vals+msRenderRow :: [BL.ByteString] -> BL.ByteString+msRenderRow xs = alignRight msIWidth (head xs) <> BL.concat vals where- vals = map (T.justifyRight msWidth ' ') (tail xs)+ vals = map (alignRight msWidth) (tail xs) -msHeader :: MonitorStdOut a -> Text-msHeader m = T.intercalate "\n" [row, sep]+msHeader :: MonitorStdOut a -> BL.ByteString+msHeader m = BL.intercalate "\n" [row, sep] where row = msRenderRow $ ["Iteration", "Log-Prior", "Log-Likelihood", "Log-Posterior"] ++ nms ++ ["Runtime", "ETA"]- sep = " " <> T.replicate (T.length row - 3) "─"- nms = [T.pack $ mpName p | p <- msParams m]+ sep = " " <> BL.replicate (BL.length row - 3) '-'+ nms = [BL.pack $ mpName p | p <- msParams m] msExec :: Int ->@@ -110,35 +107,36 @@ UTCTime -> Int -> MonitorStdOut a ->- IO (Maybe Text)+ IO (Maybe BL.ByteString) msExec i (Item x p l) ss st j m | i `mod` msPeriod m /= 0 = return Nothing | otherwise = do- ct <- getCurrentTime- let dt = ct `diffUTCTime` st- -- Careful, don't evaluate this when i == ss.- timePerIter = dt / fromIntegral (i - ss)- -- -- Always 0; doesn't make much sense.- -- tpi = if (i - ss) < 10- -- then ""- -- else renderDurationS timePerIter- eta =- if (i - ss) < 10+ ct <- getCurrentTime+ let dt = ct `diffUTCTime` st+ -- Careful, don't evaluate this when i == ss.+ timePerIter = dt / fromIntegral (i - ss)+ -- -- Always 0; doesn't make much sense.+ -- tpi = if (i - ss) < 10+ -- then ""+ -- else renderDurationS timePerIter+ eta =+ if (i - ss) < 10 then "" else renderDuration $ timePerIter * fromIntegral (j - i)- return $ Just $ msRenderRow $- [T.pack (show i), renderLog p, renderLog l, renderLog (p * l)]- ++ [T.toLazyText $ mpFunc mp x | mp <- msParams m]- ++ [renderDuration dt, eta]+ return $+ Just $+ msRenderRow $+ [BL.pack (show i), renderLog p, renderLog l, renderLog (p * l)]+ ++ [BB.toLazyByteString $ mpFunc mp x | mp <- msParams m]+ ++ [renderDuration dt, eta] -- | Monitor to a file; constructed with 'monitorFile'.-data MonitorFile a- = MonitorFile- { mfName :: String,- mfHandle :: Maybe Handle,- mfParams :: [MonitorParameter a],- mfPeriod :: Int- }+data MonitorFile a = MonitorFile+ { mfName :: String,+ mfHandle :: Maybe Handle,+ mfParams :: [MonitorParameter a],+ mfPeriod :: Int+ } -- XXX: The file monitor also includes iteration, prior, likelihood, and -- posterior. What if I want to log trees; or other complex objects? In this@@ -157,8 +155,8 @@ | p < 1 = error "monitorFile: Monitor period has to be 1 or larger." | otherwise = MonitorFile n Nothing ps p -mfRenderRow :: [Text] -> Text-mfRenderRow = T.intercalate "\t"+mfRenderRow :: [BL.ByteString] -> BL.ByteString+mfRenderRow = BL.intercalate "\t" open' :: String -> Bool -> IO Handle open' n frc = do@@ -194,10 +192,10 @@ <> mfName m <> "." Just h ->- T.hPutStrLn h- $ mfRenderRow- $ ["Iteration", "Log-Prior", "Log-Likelihood", "Log-Posterior"]- ++ [T.pack $ mpName p | p <- mfParams m]+ BL.hPutStrLn h $+ mfRenderRow $+ ["Iteration", "Log-Prior", "Log-Likelihood", "Log-Posterior"]+ ++ [BL.pack $ mpName p | p <- mfParams m] mfExec :: Int ->@@ -213,13 +211,13 @@ <> mfName m <> "." Just h ->- T.hPutStrLn h- $ mfRenderRow- $ T.pack (show i)- : renderLog p- : renderLog l- : renderLog (p * l)- : [T.toLazyText $ mpFunc mp x | mp <- mfParams m]+ BL.hPutStrLn h $+ mfRenderRow $+ BL.pack (show i) :+ renderLog p :+ renderLog l :+ renderLog (p * l) :+ [BB.toLazyByteString $ mpFunc mp x | mp <- mfParams m] mfClose :: MonitorFile a -> IO () mfClose m = case mfHandle m of@@ -231,13 +229,12 @@ -- -- Batch monitors are slow at the moment because the monitored parameter has to -- be extracted from the state for each iteration.-data MonitorBatch a- = MonitorBatch- { mbName :: String,- mbHandle :: Maybe Handle,- mbParams :: [MonitorParameterBatch a],- mbSize :: Int- }+data MonitorBatch a = MonitorBatch+ { mbName :: String,+ mbHandle :: Maybe Handle,+ mbParams :: [MonitorParameterBatch a],+ mbSize :: Int+ } -- XXX: The batch monitor also includes iteration, prior, likelihood, and -- posterior. What if I want to log trees; or other complex objects? In this@@ -283,10 +280,10 @@ <> mbName m <> "." Just h ->- T.hPutStrLn h- $ mfRenderRow- $ ["Iteration", "Mean log-Prior", "Mean log-Likelihood", "Mean log-Posterior"]- ++ [T.pack $ mbpName mbp | mbp <- mbParams m]+ BL.hPutStrLn h $+ mfRenderRow $+ ["Iteration", "Mean log-Prior", "Mean log-Likelihood", "Mean log-Posterior"]+ ++ [BL.pack $ mbpName mbp | mbp <- mbParams m] mean :: [Log Double] -> Log Double mean xs = sum xs / fromIntegral (length xs)@@ -305,13 +302,13 @@ <> mbName m <> "." Just h ->- T.hPutStrLn h- $ mfRenderRow- $ T.pack (show i)- : renderLog mlps- : renderLog mlls- : renderLog mlos- : [T.toLazyText $ mbpFunc mbp (map state t) | mbp <- mbParams m]+ BL.hPutStrLn h $+ mfRenderRow $+ BL.pack (show i) :+ renderLog mlps :+ renderLog mlls :+ renderLog mlos :+ [BB.toLazyByteString $ mbpFunc mbp (map state t) | mbp <- mbParams m] where t = takeT (mbSize m) t' lps = map prior t@@ -343,7 +340,7 @@ return $ Monitor s fs' bs' -- | Get header line of 'MonitorStdOut'.-mHeader :: Monitor a -> Text+mHeader :: Monitor a -> BL.ByteString mHeader (Monitor s _ _) = msHeader s -- | Execute monitors; print status information to files and return text to be@@ -363,7 +360,7 @@ Int -> -- | The monitor. Monitor a ->- IO (Maybe Text)+ IO (Maybe BL.ByteString) mExec v i ss st xs j (Monitor s fs bs) = do mapM_ (mfExec i $ headT xs) fs mapM_ (mbExec i xs) bs
src/Mcmc/Monitor/Log.hs view
@@ -14,12 +14,11 @@ ) where -import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Lazy.Builder.RealFloat as T+import qualified Data.ByteString.Lazy.Char8 as BL+import qualified Data.Double.Conversion.ByteString as BC import Numeric.Log -- | Print a log value.-renderLog :: Log Double -> Text-renderLog = T.toLazyText . T.formatRealFloat T.Fixed (Just 8) . ln+renderLog :: Log Double -> BL.ByteString+renderLog = BL.fromStrict . BC.toFixed 8 . ln {-# INLINEABLE renderLog #-}
src/Mcmc/Monitor/Parameter.hs view
@@ -16,70 +16,59 @@ MonitorParameter (..), (@.), monitorInt,- monitorRealFloat,- monitorRealFloatF,- monitorRealFloatS,+ monitorDouble,+ monitorDoubleF,+ monitorDoubleE, ) where -import Data.Text.Lazy.Builder (Builder)-import qualified Data.Text.Lazy.Builder.Int as T-import qualified Data.Text.Lazy.Builder.RealFloat as T+import qualified Data.ByteString.Builder as BB+import qualified Data.Double.Conversion.ByteString as BC import Lens.Micro -- | Instruction about a parameter to monitor.-data MonitorParameter a- = MonitorParameter- { -- | Name of parameter.- mpName :: String,- -- | Instruction about how to extract the parameter from the state.- mpFunc :: a -> Builder- }+data MonitorParameter a = MonitorParameter+ { -- | Name of parameter.+ mpName :: String,+ -- | Instruction about how to extract the parameter from the state.+ mpFunc :: a -> BB.Builder+ } -- | Convert a parameter monitor from one data type to another using a lens. ----- For example, to monitor a real float value being the first entry of a tuple:+-- For example, to monitor a 'Double' value being the first entry of a tuple: -- -- @--- mon = _1 @@ monitorRealFloat+-- mon = _1 @@ monitorDouble -- @ (@.) :: Lens' b a -> MonitorParameter a -> MonitorParameter b-(@.) l (MonitorParameter n f) = MonitorParameter n (\x -> f $ x^.l)+(@.) l (MonitorParameter n f) = MonitorParameter n (\x -> f $ x ^. l) --- | Monitor integral parameters such as 'Int'.+-- | Monitor 'Int'. monitorInt ::- Integral a =>- -- | Name of monitor.+ -- | Name. String ->- MonitorParameter a-monitorInt n = MonitorParameter n T.decimal-{-# SPECIALIZE monitorInt :: String -> MonitorParameter Int #-}+ MonitorParameter Int+monitorInt n = MonitorParameter n BB.intDec --- | Monitor real float parameters such as 'Double' with eight decimal places--- (half precision).-monitorRealFloat ::- RealFloat a =>- -- | Name of monitor.+-- | Monitor 'Double' with eight decimal places (half precision).+monitorDouble ::+ -- | Name. String ->- MonitorParameter a-monitorRealFloat n = MonitorParameter n (T.formatRealFloat T.Fixed (Just 8))-{-# SPECIALIZE monitorRealFloat :: String -> MonitorParameter Double #-}+ MonitorParameter Double+monitorDouble n = MonitorParameter n (BB.byteString . BC.toFixed 8) --- | Monitor real float parameters such as 'Double' with full precision.-monitorRealFloatF ::- RealFloat a =>- -- | Name of monitor.+-- | Monitor 'Double' with full precision computing the shortest string of+-- digits that correctly represent the number.+monitorDoubleF ::+ -- | Name. String ->- MonitorParameter a-monitorRealFloatF n = MonitorParameter n T.realFloat-{-# SPECIALIZE monitorRealFloatF :: String -> MonitorParameter Double #-}+ MonitorParameter Double+monitorDoubleF n = MonitorParameter n (BB.byteString . BC.toShortest) --- | Monitor real float parameters such as 'Double' with scientific notation and--- eight decimal places.-monitorRealFloatS ::- RealFloat a =>- -- | Name of monitor.+-- | Monitor 'Double' in exponential format and half precision.+monitorDoubleE ::+ -- | Name. String ->- MonitorParameter a-monitorRealFloatS n = MonitorParameter n (T.formatRealFloat T.Exponent (Just 8))-{-# SPECIALIZE monitorRealFloatS :: String -> MonitorParameter Double #-}+ MonitorParameter Double+monitorDoubleE n = MonitorParameter n (BB.byteString . BC.toExponential 8)
src/Mcmc/Monitor/ParameterBatch.hs view
@@ -17,17 +17,15 @@ ( -- * Batch parameter monitors MonitorParameterBatch (..), (@#),- monitorBatchMeanInt,- monitorBatchMeanIntF,- monitorBatchMeanRealFloat,- monitorBatchMeanRealFloatF,- monitorBatchMeanRealFloatS,+ monitorBatchMean,+ monitorBatchMeanF,+ monitorBatchMeanE, monitorBatchCustom, ) where -import Data.Text.Lazy.Builder (Builder)-import qualified Data.Text.Lazy.Builder.RealFloat as T+import qualified Data.ByteString.Builder as BB+import qualified Data.Double.Conversion.ByteString as BC import Lens.Micro -- | Instruction about a parameter to monitor via batch means. Usually, the@@ -42,7 +40,7 @@ { -- | Name of batch monitored parameter. mbpName :: String, -- | Instruction about how to extract the batch mean from the trace.- mbpFunc :: [a] -> Builder+ mbpFunc :: [a] -> BB.Builder } -- | Convert a batch parameter monitor from one data type to another using a@@ -61,62 +59,45 @@ {-# SPECIALIZE mean :: [Double] -> Double #-} {-# SPECIALIZE mean :: [Int] -> Double #-} --- | Batch monitor integral parameters such as 'Int'. Print the mean with eight--- decimal places (half precision).-monitorBatchMeanInt ::- Integral a =>- -- | Name of monitor.- String ->- MonitorParameterBatch a-monitorBatchMeanInt n = MonitorParameterBatch n (T.formatRealFloat T.Fixed (Just 8) . mean)-{-# SPECIALIZE monitorBatchMeanInt :: String -> MonitorParameterBatch Int #-}---- | Batch monitor integral parameters such as 'Int'. Print the mean with full--- precision.-monitorBatchMeanIntF ::- Integral a =>- -- | Name of monitor.- String ->- MonitorParameterBatch a-monitorBatchMeanIntF n = MonitorParameterBatch n (T.realFloat . mean)-{-# SPECIALIZE monitorBatchMeanIntF :: String -> MonitorParameterBatch Int #-}---- | Batch monitor real float parameters such as 'Double' with eight decimal--- places (half precision).-monitorBatchMeanRealFloat ::- RealFloat a =>- -- | Name of monitor.+-- | Batch monitor. Print the mean with eight decimal places (half precision).+monitorBatchMean ::+ Real a =>+ -- | Name. String -> MonitorParameterBatch a-monitorBatchMeanRealFloat n = MonitorParameterBatch n (T.formatRealFloat T.Fixed (Just 8) . mean)-{-# SPECIALIZE monitorBatchMeanRealFloat :: String -> MonitorParameterBatch Double #-}+monitorBatchMean n = MonitorParameterBatch n (BB.byteString . BC.toFixed 8 . mean)+{-# SPECIALIZE monitorBatchMean :: String -> MonitorParameterBatch Int #-}+{-# SPECIALIZE monitorBatchMean :: String -> MonitorParameterBatch Double #-} --- | Batch monitor real float parameters such as 'Double' with full precision.-monitorBatchMeanRealFloatF ::- RealFloat a =>- -- | Name of monitor.+-- | 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-monitorBatchMeanRealFloatF n = MonitorParameterBatch n (T.realFloat . mean)-{-# SPECIALIZE monitorBatchMeanRealFloatF :: String -> MonitorParameterBatch Double #-}+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.-monitorBatchMeanRealFloatS ::- RealFloat a =>- -- | Name of monitor.+monitorBatchMeanE ::+ Real a =>+ -- | Name. String -> MonitorParameterBatch a-monitorBatchMeanRealFloatS n = MonitorParameterBatch n (T.formatRealFloat T.Exponent (Just 8) . mean)-{-# SPECIALIZE monitorBatchMeanRealFloatS :: String -> MonitorParameterBatch Double #-}+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 of monitor.+ -- | Name. String -> -- | Function to calculate the batch mean. ([a] -> a) -> -- | Custom builder.- (a -> Builder) ->+ (a -> BB.Builder) -> MonitorParameterBatch a monitorBatchCustom n f b = MonitorParameterBatch n (b . f)
src/Mcmc/Monitor/Time.hs view
@@ -17,15 +17,14 @@ ) where -import qualified Data.Text.Lazy as T-import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.Builder as T-import qualified Data.Text.Lazy.Builder.Int as T+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy.Char8 as BL+import Mcmc.Internal.ByteString import Data.Time.Clock -- | Adapted from System.ProgressBar.renderDuration of package -- [terminal-progressbar-0.4.1](https://hackage.haskell.org/package/terminal-progress-bar-0.4.1).-renderDuration :: NominalDiffTime -> Text+renderDuration :: NominalDiffTime -> BL.ByteString renderDuration dt = hTxt <> mTxt <> sTxt where hTxt = renderDecimal h <> ":"@@ -36,11 +35,11 @@ -- Total amount of seconds ts :: Int ts = round dt- renderDecimal n = T.justifyRight 2 '0' $ T.toLazyText $ T.decimal n+ renderDecimal n = alignRightWith '0' 2 $ BB.toLazyByteString $ BB.intDec n -- | Render duration in seconds.-renderDurationS :: NominalDiffTime -> Text-renderDurationS dt = T.toLazyText $ T.decimal ts+renderDurationS :: NominalDiffTime -> BL.ByteString+renderDurationS dt = BB.toLazyByteString $ BB.intDec ts where ts :: Int ts = round dt
src/Mcmc/Proposal.hs view
@@ -50,18 +50,17 @@ where import Data.Aeson+import qualified Data.ByteString.Builder as BB+import qualified Data.ByteString.Lazy.Char8 as BL import Data.Default+import qualified Data.Double.Conversion.ByteString as BC import Data.Function import Data.List-import qualified Data.Map.Strict as M import Data.Map.Strict (Map)+import qualified Data.Map.Strict as M import Data.Maybe-import qualified Data.Text.Lazy as T-import Data.Text.Lazy (Text)-import qualified Data.Text.Lazy.Builder as B-import qualified Data.Text.Lazy.Builder.Int as B-import qualified Data.Text.Lazy.Builder.RealFloat as B import Lens.Micro+import Mcmc.Internal.ByteString import Mcmc.Tools.Shuffle import Numeric.Log hiding (sum) import System.Random.MWC@@ -115,7 +114,7 @@ -- ratio of the backward to forward kernels (i.e., the probability masses or -- probability densities). For unbiased proposals, this ratio is 1.0. newtype ProposalSimple a = ProposalSimple- { pSample :: a -> GenIO -> IO (a, Log Double)+ { pSample :: a -> GenIO -> IO (a, Log Double) } convertS :: Lens' b a -> ProposalSimple a -> ProposalSimple b@@ -257,43 +256,50 @@ autotuneCycle :: Acceptance (Proposal a) -> Cycle a -> Cycle a autotuneCycle a = tuneCycle (M.map (\x -> exp $ x - ratioOpt) $ acceptanceRatios a) -renderRow :: Text -> Text -> Text -> Text -> Text -> Text -> Text+renderRow ::+ BL.ByteString ->+ BL.ByteString ->+ BL.ByteString ->+ BL.ByteString ->+ BL.ByteString ->+ BL.ByteString ->+ BL.ByteString renderRow name weight nAccept nReject acceptRatio tuneParam = " " <> nm <> wt <> na <> nr <> ra <> tp where- nm = T.justifyLeft 30 ' ' name- wt = T.justifyRight 8 ' ' weight- na = T.justifyRight 15 ' ' nAccept- nr = T.justifyRight 15 ' ' nReject- ra = T.justifyRight 15 ' ' acceptRatio- tp = T.justifyRight 20 ' ' tuneParam+ nm = alignLeft 30 name+ wt = alignRight 8 weight+ na = alignRight 15 nAccept+ nr = alignRight 15 nReject+ ra = alignRight 15 acceptRatio+ tp = alignRight 20 tuneParam -proposalHeader :: Text+proposalHeader :: BL.ByteString proposalHeader = renderRow "Proposal" "Weight" "Accepted" "Rejected" "Ratio" "Tuning parameter" -summarizeProposal :: Proposal a -> Maybe (Int, Int, Double) -> Text-summarizeProposal m r = renderRow (T.pack name) weight nAccept nReject acceptRatio tuneParamStr+summarizeProposal :: Proposal a -> Maybe (Int, Int, Double) -> BL.ByteString+summarizeProposal m r = renderRow (BL.pack name) weight nAccept nReject acceptRatio tuneParamStr where name = pName m- weight = B.toLazyText $ B.decimal $ pWeight m- nAccept = B.toLazyText $ maybe "" (B.decimal . (^. _1)) r- nReject = B.toLazyText $ maybe "" (B.decimal . (^. _2)) r- acceptRatio = B.toLazyText $ maybe "" (B.formatRealFloat B.Fixed (Just 3) . (^. _3)) r- tuneParamStr = B.toLazyText $ maybe "" (B.formatRealFloat B.Fixed (Just 3)) (tParam <$> pTuner m)+ weight = BB.toLazyByteString $ BB.intDec $ pWeight m+ nAccept = BB.toLazyByteString $ maybe "" (BB.intDec . (^. _1)) r+ nReject = BB.toLazyByteString $ maybe "" (BB.intDec . (^. _2)) r+ acceptRatio = BL.fromStrict $ maybe "" (BC.toFixed 3 . (^. _3)) r+ tuneParamStr = BL.fromStrict $ maybe "" (BC.toFixed 3) (tParam <$> pTuner m) -- | Summarize the 'Proposal's in the 'Cycle'. Also report acceptance ratios.-summarizeCycle :: Acceptance (Proposal a) -> Cycle a -> Text+summarizeCycle :: Acceptance (Proposal a) -> Cycle a -> BL.ByteString summarizeCycle a c =- T.intercalate "\n" $+ BL.intercalate "\n" $ [ "Summary of proposal(s) in cycle. " <> mpi <> " proposal(s) per iteration.", proposalHeader,- " " <> T.replicate (T.length proposalHeader - 3) "─"+ " " <> BL.replicate (BL.length proposalHeader - 3) '-' ] ++ [summarizeProposal m (ar m) | m <- ps]- ++ [" " <> T.replicate (T.length proposalHeader - 3) "─"]+ ++ [" " <> BL.replicate (BL.length proposalHeader - 3) '-'] where ps = ccProposals c- mpi = B.toLazyText $ B.decimal $ sum $ map pWeight ps+ mpi = BB.toLazyByteString $ BB.intDec $ sum $ map pWeight ps ar m = acceptanceRatio m a -- | For each key @k@, store the number of accepted and rejected proposals.
src/Mcmc/Save.hs view
@@ -26,7 +26,7 @@ import Control.Monad import Data.Aeson import Data.Aeson.TH-import qualified Data.ByteString.Lazy as B+import qualified Data.ByteString.Lazy.Char8 as BL import Data.List hiding (cycle) import qualified Data.Map as M import Data.Vector.Unboxed (Vector)@@ -104,7 +104,7 @@ -- - cycle -- - monitor saveStatus :: ToJSON a => FilePath -> Status a -> IO ()-saveStatus fn s = B.writeFile fn $ compress $ encode (toSave s)+saveStatus fn s = BL.writeFile fn $ compress $ encode (toSave s) -- fromSav prior lh cycle monitor save fromSave ::@@ -157,7 +157,7 @@ FilePath -> IO (Status a) loadStatus p l c m fn = do- res <- eitherDecode . decompress <$> B.readFile fn+ res <- eitherDecode . decompress <$> BL.readFile fn let s = case res of Left err -> error err Right sv -> fromSave p l c m sv
test/Mcmc/SaveSpec.hs view
@@ -46,7 +46,7 @@ ] monStd :: MonitorStdOut Double-monStd = monitorStdOut [monitorRealFloat "mu"] 10+monStd = monitorStdOut [monitorDouble "mu"] 10 mon :: Monitor Double mon = Monitor monStd [] []