flat-mcmc

Painless, efficient, general-purpose sampling from continuous distributions.
Log | Files | Refs | README | LICENSE

commit c1b2e366f4928ea9747dce09097f07af9d6d0600
parent e47c49ce4e7d250e6f618d34858beba3fd0b5d9f
Author: Jared Tobin <jared@jtobin.ca>
Date:   Mon,  5 Nov 2012 09:18:23 +1300

Add thinning parameter.

Diffstat:
MExamples/code/BNN_Flat.hs | 2+-
MExamples/code/Booth_Flat.hs | 2+-
MExamples/code/Himmelblau_Flat.hs | 2+-
MExamples/code/Rosenbrock_Flat.hs | 2+-
MExamples/code/SPDE_Flat.hs | 14++++++++------
MNumeric/MCMC/Flat.hs | 33+++++++++++++++++++++++++++------
6 files changed, 39 insertions(+), 16 deletions(-)

diff --git a/Examples/code/BNN_Flat.hs b/Examples/code/BNN_Flat.hs @@ -28,7 +28,7 @@ main = do config = MarkovChain inits 0 g <- create - results <- runChain params nepochs config g + results <- runChain params nepochs 1 config g hPutStrLn stderr $ let nAcc = accepts results diff --git a/Examples/code/Booth_Flat.hs b/Examples/code/Booth_Flat.hs @@ -28,7 +28,7 @@ main = do config = MarkovChain inits 0 g <- create - results <- runChain params nepochs config g + results <- runChain params nepochs 1 config g hPutStrLn stderr $ let nAcc = accepts results diff --git a/Examples/code/Himmelblau_Flat.hs b/Examples/code/Himmelblau_Flat.hs @@ -28,7 +28,7 @@ main = do config = MarkovChain inits 0 g <- create - results <- runChain params nepochs config g + results <- runChain params nepochs 1 config g hPutStrLn stderr $ let nAcc = accepts results diff --git a/Examples/code/Rosenbrock_Flat.hs b/Examples/code/Rosenbrock_Flat.hs @@ -28,7 +28,7 @@ main = do config = MarkovChain inits 0 g <- create - results <- runChain params nepochs config g + results <- runChain params nepochs 1 config g hPutStrLn stderr $ let nAcc = accepts results diff --git a/Examples/code/SPDE_Flat.hs b/Examples/code/SPDE_Flat.hs @@ -18,23 +18,25 @@ main = do args <- getArgs when (args == []) $ do putStrLn "(flat-mcmc) Stochastic partial differential equation " - putStrLn "Usage: ./SPDE_Flat <numSteps> <inits> <granularity> " + putStrLn "Usage: ./SPDE_Flat <numSteps> <inits> <thinEvery> <granularity> " putStrLn " " putStrLn "numSteps : Number of Markov chain iterations to run." putStrLn "inits : Filepath containing points at which to " putStrLn " initialize the ensemble. " + putStrLn "thinEvery : Print every n^th iteration. " putStrLn "granularity : Parallel granularity (smaller is finer). " exitSuccess inits <- readInits (args !! 1) - let nepochs = read (head args) :: Int - gran = read (args !! 2) :: Int - params = Options target (V.length inits) gran - config = MarkovChain inits 0 + let nepochs = read (head args) :: Int + thinEvery = read (args !! 2) :: Int + gran = read (args !! 3) :: Int + params = Options target (V.length inits) gran + config = MarkovChain inits 0 g <- create - results <- runChain params nepochs config g + results <- runChain params nepochs thinEvery config g hPutStrLn stderr $ let nAcc = accepts results diff --git a/Numeric/MCMC/Flat.hs b/Numeric/MCMC/Flat.hs @@ -1,4 +1,5 @@ {-# OPTIONS_GHC -Wall #-} +{-# LANGUAGE BangPatterns #-} module Numeric.MCMC.Flat ( MarkovChain(..), Options(..), Ensemble @@ -15,6 +16,7 @@ import qualified Data.Vector.Unboxed as U import Control.Monad.Par (NFData) import Control.Monad.Par.Scheds.Direct import Control.Monad.Par.Combinator +import System.IO -- | Parallel map with a specified granularity. parMapChunk :: NFData b => Int -> (a -> b) -> [a] -> Par [b] @@ -53,6 +55,7 @@ symmetricVariate :: PrimMonad m => Gen (PrimState m) -> m Double symmetricVariate g = do z <- uniformR (0 :: Double, 1 :: Double) g return $! 0.5*(z + 1)^(2 :: Int) +{-# INLINE symmetricVariate #-} -- | The result of a single-particle Metropolis accept/reject step. This -- compares a particle's state to a perturbation made by an affine @@ -66,6 +69,7 @@ metropolisResult w0 w1 z zc target = let val = target proposal - target w0 + (fromIntegral (length w0) - 1) * log z proposal = zipWith (+) (map (*z) w0) (map (*(1-z)) w1) in if zc <= min 1 (exp val) then (proposal, 1) else (w0, 0) +{-# INLINE metropolisResult #-} -- | Execute Metropolis steps on the particles of a sub-ensemble by -- perturbing them with affine transformations based on particles @@ -92,6 +96,7 @@ executeMoves e0 e1 n g = do (newstate, nacc) = (V.fromList . map fst &&& sum . map snd) result return (newstate, nacc) +{-# INLINE executeMoves #-} -- | Perform a Metropolis accept/reject step on the ensemble by -- perturbing each element and accepting/rejecting the perturbation in @@ -113,23 +118,39 @@ metropolisStep state g = do return $! MarkovChain (V.concat $ map fst [result0, result1]) (nacc + snd result0 + snd result1) +{-# INLINE metropolisStep #-} -- | Diffuse through states. runChain :: Options -- Options of the Markov chain -> Int -- Number of epochs to iterate the chain + -> Int -- Print every nth iteration. -> MarkovChain -- Initial state of the Markov chain -> Gen RealWorld -- MWC PRNG -> IO MarkovChain -- End state of the Markov chain, wrapped in IO -runChain params nepochs initConfig g - | nepochs == 0 = return initConfig - | otherwise = do - result <- runReaderT (metropolisStep initConfig g) params - print result - runChain params (nepochs - 1) result g +runChain opts nepochs thinEvery initConfig g + | l == 0 + = error "runChain: ensemble must contain at least one particle" + | l < (length . V.head) (ensemble initConfig) + = do hPutStrLn stderr $ "runChain: ensemble should be twice as large as " + ++ "the target's dimension. Continuing anyway." + go opts nepochs thinEvery initConfig g + | otherwise = go opts nepochs thinEvery initConfig g + where + l = V.length (ensemble initConfig) + go o n t !c g0 | n == 0 = return c + | n `rem` t /= 0 = do + r <- runReaderT (metropolisStep c g0) o + go o (n - 1) t r g0 + | otherwise = do + r <- runReaderT (metropolisStep c g0) o + print r + go o (n - 1) t r g0 +{-# INLINE runChain #-} -- | A convenience function to read and parse ensemble inits from disk. -- Assumes a text file with one particle per line, where each particle -- element is separated by whitespace. readInits :: FilePath -> IO Ensemble readInits p = fmap (V.fromList . map (map read . words) . lines) (readFile p) +{-# INLINE readInits #-}