flat-mcmc

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

commit 920c4203bb1742b894830e07003702cc00119f8c
parent 2c72f387f130d4db53d8316f5bfea52aeb3d97af
Author: Jared Tobin <jared@jtobin.ca>
Date:   Mon, 26 Nov 2012 14:26:57 +1300

Slight API change.  Update examples accordingly.

Diffstat:
MExamples/code/BNN_Flat.hs | 22+++++++++-------------
DExamples/code/Booth_Flat.hs | 41-----------------------------------------
MExamples/code/Himmelblau_Flat.hs | 21+++++++++------------
MExamples/code/Rosenbrock_Flat.hs | 18++++++++----------
MExamples/code/SPDE_Flat.hs | 19+++++++++----------
MNumeric/MCMC/Flat.hs | 61++++++++++++++++++++++++++++++++++---------------------------
Mflat-mcmc.cabal | 4++--
7 files changed, 71 insertions(+), 115 deletions(-)

diff --git a/Examples/code/BNN_Flat.hs b/Examples/code/BNN_Flat.hs @@ -23,19 +23,15 @@ main = do inits <- readInits (args !! 1) - let nepochs = read (head args) :: Int - params = Options target (V.length inits) 30 - config = MarkovChain inits 0 - - g <- create - results <- runChain params nepochs 0 1 config g - - hPutStrLn stderr $ - let nAcc = accepts results - total = nepochs * V.length inits * length (V.head inits) - in show nAcc ++ " / " ++ show total ++ " (" ++ - show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ - ") proposals accepted" + let nepochs = read (head args) :: Int + opts = Options { _size = V.length inits + , _nEpochs = nepochs + , _burnIn = 0 + , _thinEvery = 1 + , _csize = 30 } + initState = MarkovChain inits 0 + g <- create + void $ runChain target opts initState g diff --git a/Examples/code/Booth_Flat.hs b/Examples/code/Booth_Flat.hs @@ -1,41 +0,0 @@ -import System.IO -import System.Exit -import System.Environment -import System.Random.MWC -import Control.Monad -import Numeric.MCMC.Flat -import qualified Data.Vector as V - -target :: [Double] -> Double -target [x0, x1] = (-1)*((x0 + 2*x1 -7)^2 + (2*x0 + x1 - 5)^2) -{-# INLINE target #-} - -main = do - args <- getArgs - when (args == []) $ do - putStrLn "(flat-mcmc) Booth density " - putStrLn "Usage: ./Booth_Flat <numSteps> <inits> " - putStrLn " " - putStrLn "numSteps : Number of Markov chain iterations to run." - putStrLn "inits : Filepath containing points at which to " - putStrLn " initialize the ensemble. " - exitSuccess - - inits <- readInits (args !! 1) - - let nepochs = read (head args) :: Int - params = Options target (V.length inits) 30 - config = MarkovChain inits 0 - - g <- create - results <- runChain params nepochs 0 1 config g - - hPutStrLn stderr $ - let nAcc = accepts results - total = nepochs * V.length inits * length (V.head inits) - in show nAcc ++ " / " ++ show total ++ " (" ++ - show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ - ") proposals accepted" - - - diff --git a/Examples/code/Himmelblau_Flat.hs b/Examples/code/Himmelblau_Flat.hs @@ -26,18 +26,15 @@ main = do let nepochs = read (head args) :: Int burnIn = read (args !! 1) :: Int - params = Options target (V.length inits) 30 - config = MarkovChain inits 0 - - g <- create - results <- runChain params nepochs burnIn 1 config g - - hPutStrLn stderr $ - let nAcc = accepts results - total = nepochs * V.length inits * length (V.head inits) - in show nAcc ++ " / " ++ show total ++ " (" ++ - show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ - ") proposals accepted" + + opts = Options { _size = V.length inits + , _nEpochs = nepochs + , _burnIn = burnIn + , _thinEvery = 1 + , _csize = 30 } + initState = MarkovChain inits 0 + g <- create + void $ runChain target opts initState g diff --git a/Examples/code/Rosenbrock_Flat.hs b/Examples/code/Rosenbrock_Flat.hs @@ -24,16 +24,14 @@ main = do inits <- readInits (args !! 1) let nepochs = read (head args) :: Int - params = Options target (V.length inits) 20 - config = MarkovChain inits 0 + opts = Options { _size = V.length inits + , _nEpochs = nepochs + , _burnIn = 0 + , _thinEvery = 1 + , _csize = 30 } - g <- create - results <- runChain params nepochs 0 1 config g + initState = MarkovChain inits 0 - hPutStrLn stderr $ - let nAcc = accepts results - total = nepochs * V.length inits * length (V.head inits) - in show nAcc ++ " / " ++ show total ++ " (" ++ - show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ - ") proposals accepted" + g <- create + void $ runChain target opts initState g diff --git a/Examples/code/SPDE_Flat.hs b/Examples/code/SPDE_Flat.hs @@ -34,16 +34,15 @@ main = do thinEvery = read (args !! 2) :: Int burnIn = read (args !! 3) :: Int gran = read (args !! 4) :: Int - params = Options target (V.length inits) gran - config = MarkovChain inits 0 + + opts = Options { _size = V.length inits + , _nEpochs = nepochs + , _burnIn = burnIn + , _thinEvery = thinEvery + , _csize = gran } + + initState = MarkovChain inits 0 g <- create - results <- runChain params nepochs burnIn thinEvery config g - - hPutStrLn stderr $ - let nAcc = accepts results - total = nepochs * V.length inits * length (V.head inits) - in show nAcc ++ " / " ++ show total ++ " (" ++ - show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ - ") proposals accepted" + void $ runChain target opts initState g diff --git a/Numeric/MCMC/Flat.hs b/Numeric/MCMC/Flat.hs @@ -40,9 +40,11 @@ instance Show MarkovChain where -- | Options for the chain. The target (expected to be a log density), as -- well as the size of the ensemble. The size should be an even number. Also -- holds the specified parallel granularity as 'csize'. -data Options = Options { _target :: [Double] -> Double - , _size :: {-# UNPACK #-} !Int - , _csize :: {-# UNPACK #-} !Int } +data Options = Options { _size :: {-# UNPACK #-} !Int + , _nEpochs :: {-# UNPACK #-} !Int + , _burnIn :: {-# UNPACK #-} !Int + , _thinEvery :: {-# UNPACK #-} !Int + , _csize :: {-# UNPACK #-} !Int } -- | An ensemble of particles. type Ensemble = V.Vector [Double] @@ -76,13 +78,14 @@ metropolisResult w0 w1 z zc target = -- perturbing them with affine transformations based on particles -- in a complementary ensemble, in parallel. executeMoves :: (Functor m, PrimMonad m) - => Ensemble -- Target sub-ensemble + => ([Double] -> Double) -- Target to sample + -> Ensemble -- Target sub-ensemble -> Ensemble -- Complementary sub-ensemble -> Int -- Size of the sub-ensembles -> Gen (PrimState m) -- MWC PRNG -> ViewsOptions m (Ensemble, Int) -- Updated ensemble and # of accepts -executeMoves e0 e1 n g = do - Options t _ csize <- ask +executeMoves t e0 e1 n g = do + Options _ _ _ _ csize <- ask zs <- replicateM n (lift $ symmetricVariate g) zcs <- replicateM n (lift $ uniformR (0 :: Double, 1 :: Double) g) @@ -103,18 +106,19 @@ executeMoves e0 e1 n g = do -- perturbing each element and accepting/rejecting the perturbation in -- parallel. metropolisStep :: (Functor m, PrimMonad m) - => MarkovChain -- State of the Markov chain + => ([Double] -> Double) -- Target to sample + -> MarkovChain -- State of the Markov chain -> Gen (PrimState m) -- MWC PRNG -> ViewsOptions m MarkovChain -- Updated sub-ensemble -metropolisStep state g = do - Options _ n _ <- ask +metropolisStep t state g = do + Options n _ _ _ _ <- ask let n0 = truncate (fromIntegral n / (2 :: Double)) :: Int (e, nacc) = (ensemble &&& accepts) state (e0, e1) = (V.slice (0 :: Int) n0 &&& V.slice n0 n0) e -- Update each sub-ensemble - result0 <- executeMoves e0 e1 n0 g - result1 <- executeMoves e1 (fst result0) n0 g + result0 <- executeMoves t e0 e1 n0 g + result1 <- executeMoves t e1 (fst result0) n0 g return $! MarkovChain (V.concat $ map fst [result0, result1]) @@ -122,33 +126,36 @@ metropolisStep state g = do {-# INLINE metropolisStep #-} -- | Diffuse through states. -runChain :: Options -- Options of the Markov chain - -> Int -- Number of epochs to iterate the chain - -> Int -- Burn-in period - -> 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 opts nepochs burnIn thinEvery initConfig g +runChain :: ([Double] -> Double) -- ^ Target to sample + -> Options -- ^ Options of the Markov chain + -> MarkovChain -- ^ Initial state of the Markov chain + -> Gen RealWorld -- ^ MWC PRNG + -> IO MarkovChain -- ^ End state of the Markov chain, wrapped in IO +runChain target opts initState g | l == 0 = error "runChain: ensemble must contain at least one particle" - | l < (length . V.head) (ensemble initConfig) + | l < (length . V.head) (ensemble initState) = do hPutStrLn stderr $ "runChain: ensemble should be twice as large as " ++ "the target's dimension. Continuing anyway." - go opts nepochs thinEvery initConfig g + go opts nepochs thinEvery initState g | burnIn < 0 || thinEvery < 0 = error "runChain: nonsensical burn-in or thinning input." - | otherwise = go opts nepochs thinEvery initConfig g + | otherwise = go opts nepochs thinEvery initState g where - l = V.length (ensemble initConfig) - go o n t !c g0 | n == 0 = return c + Options l nepochs burnIn thinEvery _ = opts + go o n t !c g0 | n == 0 = hPutStrLn stderr + (let nAcc = accepts c + total = nepochs * l * length (V.head $ ensemble c) + in show nAcc ++ " / " ++ show total ++ " (" ++ + show ((fromIntegral nAcc / fromIntegral total) :: Float) ++ + ") proposals accepted") >> return c | n > (nepochs - burnIn) = do - r <- runReaderT (metropolisStep c g0) o + r <- runReaderT (metropolisStep target c g0) o go o (n - 1) t r g0 | n `rem` t /= 0 = do - r <- runReaderT (metropolisStep c g0) o + r <- runReaderT (metropolisStep target c g0) o go o (n - 1) t r g0 | otherwise = do - r <- runReaderT (metropolisStep c g0) o + r <- runReaderT (metropolisStep target c g0) o print r go o (n - 1) t r g0 {-# INLINE runChain #-} diff --git a/flat-mcmc.cabal b/flat-mcmc.cabal @@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: flat-mcmc -version: 0.1.0.0 +version: 0.2.0.0 synopsis: Painless general-purpose sampling. -- description: homepage: http://jtobin.github.com/flat-mcmc @@ -26,6 +26,6 @@ Source-repository head library exposed-modules: Numeric.MCMC.Flat -- other-modules: - build-depends: base ==4.*, mtl ==2.1.*, primitive ==0.4.*, mwc-random ==0.12.*, vector ==0.9.*, monad-par ==0.3.*, monad-par-extras ==0.3.* + build-depends: base >= 4.3, mtl >= 2.1, primitive >= 0.4, mwc-random >= 0.12, vector >= 0.9, monad-par >= 0.3, monad-par-extras >= 0.3 ghc-options: -Wall