packages feed

mcmc 0.2.4 → 0.3.0

raw patch · 21 files changed

+710/−297 lines, 21 filesdep +dirichletdep +math-functionsdep +primitivePVP ok

version bump matches the API change (PVP)

Dependencies added: dirichlet, math-functions, primitive

API changes (from Hackage documentation)

- Mcmc: slideUniform :: Double -> String -> Int -> Bool -> Proposal Double
- Mcmc.Internal.ByteString: alignLeft :: Int -> ByteString -> ByteString
- Mcmc.Internal.ByteString: alignLeftWith :: Char -> Int -> ByteString -> ByteString
- Mcmc.Internal.ByteString: alignRight :: Int -> ByteString -> ByteString
- Mcmc.Internal.ByteString: alignRightWith :: Char -> Int -> ByteString -> ByteString
- Mcmc.Mcmc: mcmcDebugT :: ByteString -> Mcmc a ()
- Mcmc.Mcmc: mcmcInfoT :: ByteString -> Mcmc a ()
- Mcmc.Mcmc: mcmcOutT :: ByteString -> Mcmc a ()
- Mcmc.Mcmc: mcmcWarnT :: ByteString -> Mcmc a ()
- Mcmc.Proposal.Slide: slideUniform :: Double -> String -> Int -> Bool -> Proposal Double
- Mcmc.Tools.Shuffle: grabble :: [a] -> Int -> Int -> GenIO -> IO [[a]]
- Mcmc.Tools.Shuffle: shuffle :: [a] -> GenIO -> IO [a]
- Mcmc.Tools.Shuffle: shuffleN :: [a] -> Int -> GenIO -> IO [[a]]
+ Mcmc: Cleaner :: Int -> (a -> a) -> Cleaner a
+ Mcmc: NoTune :: Tune
+ Mcmc: PName :: String -> PName
+ Mcmc: PWeight :: Int -> PWeight
+ Mcmc: Tune :: Tune
+ Mcmc: [clEvery] :: Cleaner a -> Int
+ Mcmc: [clFunction] :: Cleaner a -> a -> a
+ Mcmc: [fromPName] :: PName -> String
+ Mcmc: [fromPWeight] :: PWeight -> Int
+ Mcmc: cleanWith :: Cleaner a -> Status a -> Status a
+ Mcmc: data Cleaner a
+ Mcmc: data Tune
+ Mcmc: newtype PName
+ Mcmc: newtype PWeight
+ Mcmc: noData :: Status a -> Status a
+ Mcmc: slideUniformSymmetric :: Double -> PName -> PWeight -> Tune -> Proposal Double
+ Mcmc.Mcmc: mcmcClean :: Mcmc a ()
+ Mcmc.Mcmc: mcmcDebugB :: ByteString -> Mcmc a ()
+ Mcmc.Mcmc: mcmcInfoB :: ByteString -> Mcmc a ()
+ Mcmc.Mcmc: mcmcOutB :: ByteString -> Mcmc a ()
+ Mcmc.Mcmc: mcmcWarnB :: ByteString -> Mcmc a ()
+ Mcmc.Prior: largerThan :: Double -> Double -> Log Double
+ Mcmc.Prior: lowerThan :: Double -> Double -> Log Double
+ Mcmc.Proposal: NoTune :: Tune
+ Mcmc.Proposal: PDescription :: String -> PDescription
+ Mcmc.Proposal: PName :: String -> PName
+ Mcmc.Proposal: PWeight :: Int -> PWeight
+ Mcmc.Proposal: Tune :: Tune
+ Mcmc.Proposal: [fromPDescription] :: PDescription -> String
+ Mcmc.Proposal: [fromPName] :: PName -> String
+ Mcmc.Proposal: [fromPWeight] :: PWeight -> Int
+ Mcmc.Proposal: [pDescription] :: Proposal a -> PDescription
+ Mcmc.Proposal: data Tune
+ Mcmc.Proposal: instance GHC.Classes.Eq Mcmc.Proposal.PDescription
+ Mcmc.Proposal: instance GHC.Classes.Eq Mcmc.Proposal.PName
+ Mcmc.Proposal: instance GHC.Classes.Eq Mcmc.Proposal.PWeight
+ Mcmc.Proposal: instance GHC.Classes.Eq Mcmc.Proposal.Tune
+ Mcmc.Proposal: instance GHC.Classes.Ord Mcmc.Proposal.PDescription
+ Mcmc.Proposal: instance GHC.Classes.Ord Mcmc.Proposal.PName
+ Mcmc.Proposal: instance GHC.Classes.Ord Mcmc.Proposal.PWeight
+ Mcmc.Proposal: instance GHC.Show.Show Mcmc.Proposal.PDescription
+ Mcmc.Proposal: instance GHC.Show.Show Mcmc.Proposal.PName
+ Mcmc.Proposal: instance GHC.Show.Show Mcmc.Proposal.PWeight
+ Mcmc.Proposal: instance GHC.Show.Show Mcmc.Proposal.Tune
+ Mcmc.Proposal: newtype PDescription
+ Mcmc.Proposal: newtype PName
+ Mcmc.Proposal: newtype PWeight
+ Mcmc.Proposal.Simplex: beta :: Int -> PName -> PWeight -> Tune -> Proposal Simplex
+ Mcmc.Proposal.Simplex: data Simplex
+ Mcmc.Proposal.Simplex: dirichlet :: PName -> PWeight -> Tune -> Proposal Simplex
+ Mcmc.Proposal.Simplex: instance Data.Aeson.Types.FromJSON.FromJSON Mcmc.Proposal.Simplex.Simplex
+ Mcmc.Proposal.Simplex: instance Data.Aeson.Types.ToJSON.ToJSON Mcmc.Proposal.Simplex.Simplex
+ Mcmc.Proposal.Simplex: instance GHC.Classes.Eq Mcmc.Proposal.Simplex.Simplex
+ Mcmc.Proposal.Simplex: instance GHC.Show.Show Mcmc.Proposal.Simplex.Simplex
+ Mcmc.Proposal.Simplex: simplexFromVector :: Vector Double -> Either String Simplex
+ Mcmc.Proposal.Simplex: simplexUniform :: Int -> Simplex
+ Mcmc.Proposal.Slide: slideUniformSymmetric :: Double -> PName -> PWeight -> Tune -> Proposal Double
+ Mcmc.Status: Cleaner :: Int -> (a -> a) -> Cleaner a
+ Mcmc.Status: [clEvery] :: Cleaner a -> Int
+ Mcmc.Status: [clFunction] :: Cleaner a -> a -> a
+ Mcmc.Status: [cleaner] :: Status a -> Maybe (Cleaner a)
+ Mcmc.Status: cleanWith :: Cleaner a -> Status a -> Status a
+ Mcmc.Status: data Cleaner a
+ Mcmc.Status: noData :: Status a -> Status a
- Mcmc: loadStatus :: FromJSON a => (a -> Log Double) -> (a -> Log Double) -> Cycle a -> Monitor a -> FilePath -> IO (Status a)
+ Mcmc: loadStatus :: FromJSON a => (a -> Log Double) -> (a -> Log Double) -> Cycle a -> Monitor a -> Maybe (Cleaner a) -> FilePath -> IO (Status a)
- Mcmc: scale :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: scale :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc: scaleBactrian :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: scaleBactrian :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc: scaleContrarily :: Double -> Double -> String -> Int -> Bool -> Proposal (Double, Double)
+ Mcmc: scaleContrarily :: Double -> Double -> PName -> PWeight -> Tune -> Proposal (Double, Double)
- Mcmc: scaleUnbiased :: Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: scaleUnbiased :: Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc: slide :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: slide :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc: slideBactrian :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: slideBactrian :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc: slideContrarily :: Double -> Double -> String -> Int -> Bool -> Proposal (Double, Double)
+ Mcmc: slideContrarily :: Double -> Double -> PName -> PWeight -> Tune -> Proposal (Double, Double)
- Mcmc: slideSymmetric :: Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc: slideSymmetric :: Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal: Proposal :: String -> Int -> ProposalSimple a -> Maybe (Tuner a) -> Proposal a
+ Mcmc.Proposal: Proposal :: PName -> PDescription -> PWeight -> ProposalSimple a -> Maybe (Tuner a) -> Proposal a
- Mcmc.Proposal: [pName] :: Proposal a -> String
+ Mcmc.Proposal: [pName] :: Proposal a -> PName
- Mcmc.Proposal: [pWeight] :: Proposal a -> Int
+ Mcmc.Proposal: [pWeight] :: Proposal a -> PWeight
- Mcmc.Proposal: createProposal :: (Double -> ProposalSimple a) -> String -> Int -> Bool -> Proposal a
+ Mcmc.Proposal: createProposal :: PDescription -> (Double -> ProposalSimple a) -> PName -> PWeight -> Tune -> Proposal a
- Mcmc.Proposal: type ProposalSimple a = a -> GenIO -> IO (a, Log Double)
+ Mcmc.Proposal: type ProposalSimple a = a -> GenIO -> IO (a, Log Double, Log Double)
- Mcmc.Proposal.Bactrian: scaleBactrian :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Bactrian: scaleBactrian :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal.Bactrian: slideBactrian :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Bactrian: slideBactrian :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal.Generic: genericContinuous :: (ContDistr d, ContGen d) => d -> (a -> Double -> a) -> Maybe (Double -> Double) -> ProposalSimple a
+ Mcmc.Proposal.Generic: genericContinuous :: (ContDistr d, ContGen d) => d -> (a -> Double -> a) -> Maybe (Double -> Double) -> Maybe (a -> Double -> Log Double) -> ProposalSimple a
- Mcmc.Proposal.Scale: scale :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Scale: scale :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal.Scale: scaleContrarily :: Double -> Double -> String -> Int -> Bool -> Proposal (Double, Double)
+ Mcmc.Proposal.Scale: scaleContrarily :: Double -> Double -> PName -> PWeight -> Tune -> Proposal (Double, Double)
- Mcmc.Proposal.Scale: scaleUnbiased :: Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Scale: scaleUnbiased :: Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal.Slide: slide :: Double -> Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Slide: slide :: Double -> Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Proposal.Slide: slideContrarily :: Double -> Double -> String -> Int -> Bool -> Proposal (Double, Double)
+ Mcmc.Proposal.Slide: slideContrarily :: Double -> Double -> PName -> PWeight -> Tune -> Proposal (Double, Double)
- Mcmc.Proposal.Slide: slideSymmetric :: Double -> String -> Int -> Bool -> Proposal Double
+ Mcmc.Proposal.Slide: slideSymmetric :: Double -> PName -> PWeight -> Tune -> Proposal Double
- Mcmc.Save: loadStatus :: FromJSON a => (a -> Log Double) -> (a -> Log Double) -> Cycle a -> Monitor a -> FilePath -> IO (Status a)
+ Mcmc.Save: loadStatus :: FromJSON a => (a -> Log Double) -> (a -> Log Double) -> Cycle a -> Monitor a -> Maybe (Cleaner a) -> FilePath -> IO (Status a)
- Mcmc.Status: Status :: String -> Item a -> Int -> Trace a -> Acceptance (Proposal a) -> Maybe Int -> Maybe Int -> Int -> Bool -> Maybe Int -> Verbosity -> GenIO -> Maybe (Int, UTCTime) -> Maybe Handle -> (a -> Log Double) -> (a -> Log Double) -> Cycle a -> Monitor a -> Status a
+ Mcmc.Status: Status :: String -> Item a -> Int -> Trace a -> Acceptance (Proposal a) -> Maybe Int -> Maybe Int -> Int -> Bool -> Maybe Int -> Verbosity -> GenIO -> Maybe (Int, UTCTime) -> Maybe Handle -> (a -> Log Double) -> (a -> Log Double) -> Maybe (Cleaner a) -> Cycle a -> Monitor a -> Status a

Files

ChangeLog.md view
@@ -5,6 +5,32 @@ ## Unreleased changes  +## 0.3.0++-   New shorter example/test for dating trees.+-   `noData` allows running a chain without likelihood function.+-   Give proposal parameters `PName`, `PDescription`, and `PWeight` newtype+    wrappers.+-   Give `Tune` a data type.+-   Allow periodical cleansing of state (`Cleaner`).+-   Add description string to proposals, so that they can be identified in an+    easier way.+-   Add simplices and proposals on simplices.+-   `slideUniform` renamed to `slideUniformSymmetric`.+-   Merge tools into internal.+-   Do not export internal modules.+++## 0.2.4++-   **Change order of arguments for proposals**.+-   'slideStem' was renamed to 'slideBranch'.+-   Change ProposalSimple from newtype to type.+-   Contravariant instances of parameter and batch monitors. Use `(>$<)` instead+    of `(@.)` and `(@#)`.+-   Add `gammaDirichlet` prior for partitioned dating analyses.++ ## 0.2.3  -   Contrary proposals.
bench/Normal.hs view
@@ -37,7 +37,7 @@ proposals :: Cycle Double proposals =   fromList-    [slideSymmetric 1.0 "medium" 1 True]+    [slideSymmetric 1.0 (PName "Medium") (PWeight 1) Tune]  mons :: [MonitorParameter Double] mons = [monitorDouble "mu"]@@ -45,9 +45,6 @@ monStd :: MonitorStdOut Double monStd = monitorStdOut mons 200 --- monFile :: MonitorFile Double--- monFile = monitorFile "Mu" mons 200- mon :: Monitor Double mon = Monitor monStd [] [] @@ -68,7 +65,7 @@ proposalsBactrian :: Cycle Double proposalsBactrian =   fromList-    [slideBactrian 0.5 1.0 "bactrian" 1 True]+    [slideBactrian 0.5 1.0 (PName "Bactrian") (PWeight 1) Tune]  normalBactrianBench :: GenIO -> IO () normalBactrianBench g = do
bench/Poisson.hs view
@@ -39,19 +39,19 @@     m = sum ys / fromIntegral (length ys)  f :: Int -> Double -> I -> Log Double-f ft yr (alpha, beta) = Exp $ logProbability (poisson l) (fromIntegral ft)+f ft yr (a, b) = Exp $ logProbability (poisson l) (fromIntegral ft)   where-    l = exp $ alpha + beta * yr+    l = exp $ a + b * yr  lh :: I -> Log Double lh x =   product [f ft yr x | (ft, yr) <- zip fatalities normalizedYears]  proposalAlpha :: Proposal I-proposalAlpha = _1 @~ slideSymmetric 0.2 "alpha" 2 False+proposalAlpha = _1 @~ slideSymmetric 0.2 (PName "Alpha") (PWeight 1) NoTune  proposalBeta :: Proposal I-proposalBeta = _2 @~ slideSymmetric 0.2 "beta" 1 False+proposalBeta = _2 @~ slideSymmetric 0.2 (PName "Beta") (PWeight 1) NoTune  proposals :: Cycle I proposals = fromList [proposalAlpha, proposalBeta]
mcmc.cabal view
@@ -1,6 +1,6 @@ cabal-version:  2.2 name:           mcmc-version:        0.2.4+version:        0.3.0 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@@ -23,7 +23,6 @@ library   exposed-modules:       Mcmc-      Mcmc.Internal.ByteString       Mcmc.Item       Mcmc.Mcmc       Mcmc.Metropolis@@ -38,12 +37,14 @@       Mcmc.Proposal.Generic       Mcmc.Proposal.Scale       Mcmc.Proposal.Slide+      Mcmc.Proposal.Simplex       Mcmc.Save       Mcmc.Status-      Mcmc.Tools.Shuffle       Mcmc.Trace       Mcmc.Verbosity   other-modules:+      Mcmc.Internal.ByteString+      Mcmc.Internal.Shuffle       Paths_mcmc   autogen-modules:       Paths_mcmc@@ -57,10 +58,13 @@     , containers     , data-default     , directory+    , dirichlet     , double-conversion     , log-domain+    , math-functions     , microlens     , mwc-random+    , primitive     , statistics     , time     , transformers@@ -77,7 +81,7 @@       Paths_mcmc   hs-source-dirs:       test-  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -Wall   build-depends:       QuickCheck     , base >=4.7 && <5@@ -100,7 +104,7 @@       Paths_mcmc   hs-source-dirs:       bench-  ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N+  ghc-options: -Wall   build-depends:       base >=4.7 && <5     , criterion
src/Mcmc.hs view
@@ -82,17 +82,21 @@     -- B. R., Huelsenbeck, J. P., …, Revbayes: bayesian phylogenetic inference using     -- graphical models and an interactive model-specification language, Systematic     -- Biology, 65(4), 726–736 (2016). http://dx.doi.org/10.1093/sysbio/syw021+    PName (..),+    PWeight (..),     Proposal,     (@~),+    Tune (..),     scale,     scaleUnbiased,     scaleContrarily,     scaleBactrian,     slide,     slideSymmetric,-    slideUniform,+    slideUniformSymmetric,     slideContrarily,     slideBactrian,+    module Mcmc.Proposal.Simplex,     Cycle,     fromList,     Order (..),@@ -113,10 +117,13 @@     -- space (see above) and to monitor the MCMC run, as well as some auxiliary     -- information.     status,+    Cleaner (..),+    cleanWith,     saveWith,     force,     quiet,     debug,+    noData,      -- * Monitor @@ -160,6 +167,7 @@ import Mcmc.Proposal import Mcmc.Proposal.Bactrian import Mcmc.Proposal.Scale+import Mcmc.Proposal.Simplex import Mcmc.Proposal.Slide import Mcmc.Save import Mcmc.Status
+ src/Mcmc/Internal/Shuffle.hs view
@@ -0,0 +1,64 @@+-- |+-- Module      :  Mcmc.Internal.Shuffle+-- Description :  Shuffle a list+-- Copyright   :  (c) Dominik Schrempf 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Wed May 20 14:37:09 2020.+--+-- From https://wiki.haskell.org/Random_shuffle.+module Mcmc.Internal.Shuffle+  ( shuffle,+    shuffleN,+    grabble,+  )+where++import Control.Monad+import Control.Monad.ST+import Data.Vector (Vector)+import qualified Data.Vector as V+import qualified Data.Vector.Mutable as M+import System.Random.MWC+  ( GenIO,+    uniformR,+  )++-- | Shuffle a list.+shuffle :: [a] -> GenIO -> IO [a]+shuffle xs g = head <$> grabble xs 1 (length xs) g++-- | Shuffle a list @n@ times.+shuffleN :: [a] -> Int -> GenIO -> IO [[a]]+shuffleN xs n = grabble xs n (length xs)++-- -- Using System.Random.Shuffle. Speed is the same, so stay without additional dependency.+-- -- | Shuffle a list @n@ times.+-- shuffleN :: [a] -> Int -> GenIO -> IO [[a]]+-- shuffleN xs n g = replicateM n $ fmap (shuffle xs) (rseqM (length xs - 1) g)+--   where+--     rseqM :: Int -> GenIO -> IO [Int]+--     rseqM 0 _ = return []+--     rseqM i gen = liftM2 (:) (uniformR (0, i) gen) (rseqM (i - 1) gen)++-- | @grabble xs m n@ is /O(m*n')/, where @n' = min n (length xs)@. Choose @n'@+-- elements from @xs@, without replacement, and that @m@ times.+grabble :: [a] -> Int -> Int -> GenIO -> IO [[a]]+grabble xs m n gen = do+  swapss <- replicateM m $+    forM [0 .. min (l - 1) n] $ \i -> do+      j <- uniformR (i, l) gen+      return (i, j)+  return $ map (V.toList . V.take n . swapElems (V.fromList xs)) swapss+  where+    l = length xs - 1++swapElems :: Vector a -> [(Int, Int)] -> Vector a+swapElems xs swaps = runST $ do+  mxs <- V.unsafeThaw xs+  mapM_ (uncurry $ M.unsafeSwap mxs) swaps+  V.unsafeFreeze mxs
src/Mcmc/Mcmc.hs view
@@ -15,15 +15,16 @@ -- Functions to work with the 'Mcmc' state transformer. module Mcmc.Mcmc   ( Mcmc,-    mcmcOutT,+    mcmcOutB,     mcmcOutS,-    mcmcWarnT,+    mcmcWarnB,     mcmcWarnS,-    mcmcInfoT,+    mcmcInfoB,     mcmcInfoS,-    mcmcDebugT,+    mcmcDebugB,     mcmcDebugS,     mcmcAutotune,+    mcmcClean,     mcmcResetA,     mcmcSummarizeCycle,     mcmcReport,@@ -40,12 +41,14 @@ import Data.Maybe import Data.Time.Clock import Data.Time.Format+import Mcmc.Item import Mcmc.Monitor import Mcmc.Monitor.Time import Mcmc.Proposal import Mcmc.Save import Mcmc.Status hiding (debug) import Mcmc.Verbosity+import Numeric.Log import System.Directory import System.IO import Prelude hiding (cycle)@@ -58,66 +61,96 @@ msgPrepare c t = BL.cons c $ ": " <> t  -- | Write to standard output and log file.-mcmcOutT :: BL.ByteString -> Mcmc a ()-mcmcOutT msg = do+mcmcOutB :: BL.ByteString -> Mcmc a ()+mcmcOutB msg = do   h <- fromMaybe (error "mcmcOut: Log handle is missing.") <$> gets logHandle   liftIO $ BL.putStrLn msg >> BL.hPutStrLn h msg  -- | Write to standard output and log file. mcmcOutS :: String -> Mcmc a ()-mcmcOutS = mcmcOutT . BL.pack+mcmcOutS = mcmcOutB . BL.pack  -- Perform warning action. mcmcWarnA :: Mcmc a () -> Mcmc a () mcmcWarnA a = gets verbosity >>= \v -> info v a  -- | Print warning message.-mcmcWarnT :: BL.ByteString -> Mcmc a ()-mcmcWarnT = mcmcWarnA . mcmcOutT . msgPrepare 'W'+mcmcWarnB :: BL.ByteString -> Mcmc a ()+mcmcWarnB = mcmcWarnA . mcmcOutB . msgPrepare 'W'  -- | Print warning message. mcmcWarnS :: String -> Mcmc a ()-mcmcWarnS = mcmcWarnT . BL.pack+mcmcWarnS = mcmcWarnB . BL.pack  -- Perform info action. mcmcInfoA :: Mcmc a () -> Mcmc a () mcmcInfoA a = gets verbosity >>= \v -> info v a  -- | Print info message.-mcmcInfoT :: BL.ByteString -> Mcmc a ()-mcmcInfoT = mcmcInfoA . mcmcOutT . msgPrepare 'I'+mcmcInfoB :: BL.ByteString -> Mcmc a ()+mcmcInfoB = mcmcInfoA . mcmcOutB . msgPrepare 'I'  -- | Print info message. mcmcInfoS :: String -> Mcmc a ()-mcmcInfoS = mcmcInfoT . BL.pack+mcmcInfoS = mcmcInfoB . BL.pack  -- Perform debug action. mcmcDebugA :: Mcmc a () -> Mcmc a () mcmcDebugA a = gets verbosity >>= \v -> debug v a  -- | Print debug message.-mcmcDebugT :: BL.ByteString -> Mcmc a ()-mcmcDebugT = mcmcDebugA . mcmcOutT . msgPrepare 'D'+mcmcDebugB :: BL.ByteString -> Mcmc a ()+mcmcDebugB = mcmcDebugA . mcmcOutB . msgPrepare 'D'  -- | Print debug message. mcmcDebugS :: String -> Mcmc a ()-mcmcDebugS = mcmcDebugT . BL.pack+mcmcDebugS = mcmcDebugB . BL.pack  -- | Auto tune the 'Proposal's in the 'Cycle' of the chain. Reset acceptance counts. -- See 'autotuneCycle'. mcmcAutotune :: Mcmc a () mcmcAutotune = do-  mcmcDebugT "Auto tune."+  mcmcDebugB "Auto tune."   s <- get   let a = acceptance s       c = cycle s       c' = autotuneCycle a c   put $ s {cycle = c'} +-- | Clean the state.+mcmcClean :: Mcmc a ()+mcmcClean = do+  s <- get+  let cl = cleaner s+      i = iteration s+  case cl of+    Just (Cleaner n f) | i `mod` n == 0 -> do+      mcmcDebugB "Clean state."+      let (Item st pr lh) = item s+      mcmcDebugS $+        "Old log prior and log likelihood: " ++ show (ln pr) ++ ", " ++ show (ln lh) ++ "."+      let prF = priorF s+          lhF = likelihoodF s+          st' = f st+          pr' = prF st'+          lh' = lhF st'+      mcmcDebugS $+        "New log prior and log likelihood: " ++ show (ln pr') ++ ", " ++ show (ln lh') ++ "."+      let dLogPr = abs $ ln pr - ln pr'+          dLogLh = abs $ ln lh - ln lh'+      when+        (dLogPr > 0.01)+        (mcmcWarnS $ "Log of old and new prior differ by " ++ show dLogPr ++ ".")+      when+        (dLogPr > 0.01)+        (mcmcWarnS $ "Log of old and new likelihood differ by " ++ show dLogLh ++ ".")+      put $ s {item = Item st' pr' lh'}+    _ -> return ()+ -- | Reset acceptance counts. mcmcResetA :: Mcmc a () mcmcResetA = do-  mcmcDebugT "Reset acceptance ratios."+  mcmcDebugB "Reset acceptance ratios."   s <- get   let a = acceptance s   put $ s {acceptance = resetA a}@@ -150,7 +183,7 @@         (True, _, _) -> openFile lfn AppendMode   put s {logHandle = mh}   mcmcDebugS $ "Log file name: " ++ lfn ++ "."-  mcmcDebugT "Log file opened."+  mcmcDebugB "Log file opened."  -- Set the total number of iterations, the current time and open the 'Monitor's -- of the chain. See 'mOpen'.@@ -176,14 +209,18 @@   let b = burnInIterations s       t = autoTuningPeriod s       n = iterations s+      c = cleaner s   case b of     Just b' -> mcmcInfoS $ "Burn in for " <> show b' <> " iterations."     Nothing -> return ()   case t of     Just t' -> mcmcInfoS $ "Auto tune every " <> show t' <> " iterations (during burn in only)."     Nothing -> return ()+  case c of+    Just (Cleaner c' _) -> mcmcInfoS $ "Clean state every " <> show c' <> " iterations."+    Nothing -> return ()   mcmcInfoS $ "Run chain for " <> show n <> " iterations."-  mcmcInfoT "Initial state."+  mcmcInfoB "Initial state."   mcmcMonitorExec  -- Save the status of an MCMC run. See 'saveStatus'.@@ -192,11 +229,11 @@   s <- get   case save s of     Just n -> do-      mcmcInfoT $ "Save Markov chain with trace of length " <> BL.pack (show n) <> "."-      mcmcInfoT "For long traces, or complex objects, this may take a while."+      mcmcInfoB $ "Save Markov chain with trace of length " <> BL.pack (show n) <> "."+      mcmcInfoB "For long traces, or complex objects, this may take a while."       liftIO $ saveStatus (name s <> ".mcmc") s-      mcmcInfoT "Done saving Markov chain."-    Nothing -> mcmcInfoT "Do not save the Markov chain."+      mcmcInfoB "Done saving Markov chain."+    Nothing -> mcmcInfoB "Do not save the Markov chain."  -- | Execute the 'Monitor's of the chain. See 'mExec'. mcmcMonitorExec :: ToJSON a => Mcmc a ()@@ -209,14 +246,14 @@       tr = trace s       vb = verbosity s   mt <- liftIO $ mExec vb i ss st tr j m-  forM_ mt mcmcOutT+  forM_ mt mcmcOutB  -- Close the 'Monitor's of the chain. See 'mClose'. mcmcClose :: ToJSON a => Mcmc a () mcmcClose = do   s <- get-  mcmcSummarizeCycle >>= mcmcInfoT-  mcmcInfoT "Metropolis-Hastings sampler finished."+  mcmcSummarizeCycle >>= mcmcInfoB+  mcmcInfoB "Metropolis-Hastings sampler finished."   let m = monitor s   m' <- liftIO $ mClose m   put $ s {monitor = m'}@@ -225,7 +262,7 @@   let rt = case start s of         Nothing -> error "mcmcClose: Start time not set."         Just (_, st) -> t `diffUTCTime` st-  mcmcInfoT $ "Wall clock run time: " <> renderDuration rt <> "."+  mcmcInfoB $ "Wall clock run time: " <> renderDuration rt <> "."   mcmcInfoS $ "End time: " <> fTime t   case logHandle s of     Just h -> liftIO $ hClose h
src/Mcmc/Metropolis.hs view
@@ -46,9 +46,10 @@ -- Handbook of Markov Chain Monte Carlo), or (b) almost surely reject the -- proposal when either fY or q are zero (Chapter 1). Since I trust the author -- of Chapter 1 (Charles Geyer) I choose to follow option (b).-mhRatio :: Log Double -> Log Double -> Log Double -> Log Double--- q = qYX / qXY-mhRatio fX fY q = fY * q / fX+mhRatio :: Log Double -> Log Double -> Log Double -> Log Double -> Log Double+-- q = qYX / qXY * jXY; see 'ProposalSimple'.+-- j = Jacobian.+mhRatio fX fY q j = fY / fX * q * j {-# INLINE mhRatio #-}  mhPropose :: Proposal a -> Mcmc a ()@@ -61,11 +62,11 @@       a = acceptance s       g = generator s   -- 1. Sample new state.-  (!y, !q) <- liftIO $ p x g+  (!y, !q, !j) <- liftIO $ p x g   -- 2. Calculate Metropolis-Hastings ratio.   let !pY = pF y       !lY = lF y-      !r = mhRatio (pX * lX) (pY * lY) q+      !r = mhRatio (pX * lX) (pY * lY) q j   -- 3. Accept or reject.   if ln r >= 0.0     then put $ s {item = Item y pY lY, acceptance = pushA m True a}@@ -86,6 +87,7 @@       t = trace s       n = iteration s   put $ s {trace = pushT i t, iteration = succ n}+  mcmcClean   mcmcMonitorExec  -- Run N iterations.@@ -104,13 +106,13 @@   | b > t = do     mcmcResetA     mhNIter t-    mcmcSummarizeCycle >>= mcmcDebugT+    mcmcSummarizeCycle >>= mcmcDebugB     mcmcAutotune     mhBurnInN (b - t) (Just t)   | otherwise = do     mcmcResetA     mhNIter b-    mcmcSummarizeCycle >>= mcmcInfoT+    mcmcSummarizeCycle >>= mcmcInfoB     mcmcInfoS $ "Acceptance ratios calculated over the last " <> show b <> " iterations." mhBurnInN b Nothing = mhNIter b @@ -123,7 +125,7 @@     mcmcInfoS $ "Burn in for " <> show b <> " cycles."     mcmcDebugS $ "Auto tuning period is " <> show t <> "."     mhBurnInN b t-    mcmcInfoT "Burn in finished."+    mcmcInfoB "Burn in finished."  -- Run for given number of iterations. mhRun :: ToJSON a => Int -> Mcmc a ()@@ -142,8 +144,8 @@  mhT :: ToJSON a => Mcmc a () mhT = do-  mcmcInfoT "Metropolis-Hastings sampler."-  mcmcSummarizeCycle >>= mcmcInfoT+  mcmcInfoB "Metropolis-Hastings sampler."+  mcmcSummarizeCycle >>= mcmcInfoB   mcmcReport   s <- get   let b = fromMaybe 0 (burnInIterations s)@@ -152,9 +154,9 @@  mhContinueT :: ToJSON a => Int -> Mcmc a () mhContinueT dn = do-  mcmcInfoT "Continuation of Metropolis-Hastings sampler."+  mcmcInfoB "Continuation of Metropolis-Hastings sampler."   mcmcInfoS $ "Run chain for " <> show dn <> " additional iterations."-  mcmcSummarizeCycle >>= mcmcInfoT+  mcmcSummarizeCycle >>= mcmcInfoB   mhRun dn  -- | Continue a Markov chain for a given number of Metropolis-Hastings steps.
src/Mcmc/Monitor/Parameter.hs view
@@ -43,7 +43,7 @@     mpFunc :: a -> BB.Builder   } -instance Contravariant (MonitorParameter) where+instance Contravariant MonitorParameter where   contramap f (MonitorParameter n m) = MonitorParameter n (m . f)  -- | Convert a parameter monitor from one data type to another.
src/Mcmc/Prior.hs view
@@ -13,7 +13,9 @@ -- Creation date: Thu Jul 23 13:26:14 2020. module Mcmc.Prior   ( -- * Continuous priors+    largerThan,     positive,+    lowerThan,     negative,     uniform,     normal,@@ -35,17 +37,25 @@ import qualified Statistics.Distribution.Gamma as S import qualified Statistics.Distribution.Normal as S --- | Improper uniform prior; larger than 0.+-- | Improper uniform prior; strictly larger than a given value.+largerThan :: Double -> Double -> Log Double+largerThan a x+  | x <= a = 0+  | otherwise = 1++-- | Improper uniform prior; strictly larger than zero. positive :: Double -> Log Double-positive x-  | x <= 0 = 0+positive = largerThan 0++-- | Improper uniform prior; strictly lower than a given value.+lowerThan :: Double -> Double -> Log Double+lowerThan b x+  | x >= b = 0   | otherwise = 1 --- | Improper uniform prior; lower than 0.+-- | Improper uniform prior; strictly lower than zero. negative :: Double -> Log Double-negative x-  | x >= 0 = 0-  | otherwise = 1+negative = lowerThan 0  -- | Uniform prior on [a, b]. uniform ::
src/Mcmc/Proposal.hs view
@@ -2,8 +2,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RankNTypes #-} --- TODO: Proposals on simplices: SimplexElementScale (?).- -- | -- Module      :  Mcmc.Proposal -- Description :  Proposals and cycles@@ -17,10 +15,14 @@ -- Creation date: Wed May 20 13:42:53 2020. module Mcmc.Proposal   ( -- * Proposal+    PName (..),+    PDescription (..),+    PWeight (..),     Proposal (..),     (@~),     ProposalSimple,     Tuner (tParam, tFunc),+    Tune (..),     createProposal,     tune, @@ -57,36 +59,54 @@ import Data.Maybe import Lens.Micro import Mcmc.Internal.ByteString-import Mcmc.Tools.Shuffle+import Mcmc.Internal.Shuffle import Numeric.Log hiding (sum) import System.Random.MWC +-- | Proposal name.+newtype PName = PName {fromPName :: String}+  deriving (Show, Eq, Ord)++-- | Proposal description.+newtype PDescription = PDescription {fromPDescription :: String}+  deriving (Show, Eq, Ord)++-- | The weight determines how often a 'Proposal' is executed per iteration of+-- the Markov chain.+newtype PWeight = PWeight {fromPWeight :: Int}+  deriving (Show, Eq, Ord)+ -- | A 'Proposal' is an instruction about how the Markov chain will traverse the -- state space @a@. Essentially, it is a probability mass or probability density -- conditioned on the current state (i.e., a kernel). -- -- A 'Proposal' may be tuneable in that it contains information about how to enlarge -- or shrink the step size to tune the acceptance ratio.+--+-- No proposals with the same name and description are allowed in a 'Cycle'. data Proposal a = Proposal-  { -- | Name (no proposals with the same name are allowed in a 'Cycle').-    pName :: String,+  { -- | Name of the affected variable.+    pName :: PName,+    -- | Description of the proposal type and parameters.+    pDescription :: PDescription,     -- | The weight determines how often a 'Proposal' is executed per iteration of     -- the Markov chain.-    pWeight :: Int,+    pWeight :: PWeight,     -- | Simple proposal without name, weight, and tuning information.     pSimple :: ProposalSimple a,     -- | Tuning is disabled if set to 'Nothing'.     pTuner :: Maybe (Tuner a)   } +-- XXX: This should be removed. instance Show (Proposal a) where-  show m = show $ pName m+  show m = fromPName (pName m) <> " " <> fromPDescription (pDescription m) <> ", weight " <> show (fromPWeight $ pWeight m)  instance Eq (Proposal a) where-  m == n = pName m == pName n+  m == n = pName m == pName n && pDescription m == pDescription n  instance Ord (Proposal a) where-  compare = compare `on` pName+  compare = compare `on` (\p -> (pDescription p, pName p, pWeight p))  -- | Convert a proposal from one data type to another using a lens. --@@ -96,7 +116,7 @@ -- scaleFirstEntryOfTuple = _1 @~ scale -- @ (@~) :: Lens' b a -> Proposal a -> Proposal b-(@~) l (Proposal n w s t) = Proposal n w (convertS l s) (convertT l <$> t)+(@~) l (Proposal n d w s t) = Proposal n d w (convertS l s) (convertT l <$> t)  -- | Simple proposal without tuning information. --@@ -105,16 +125,26 @@ -- -- In order to calculate the Metropolis-Hastings ratio, we need to know the -- ratio of the backward to forward kernels (i.e., the probability masses or--- probability densities). For unbiased proposals, this ratio is 1.0. For biased--- proposals, the ratio is ?.-type ProposalSimple a = a -> GenIO -> IO (a, Log Double)+-- probability densities) and the absolute value of the determinant of the+-- Jacobian matrix.+--+-- For unbiased proposals, these values are 1.0 such that+--+-- @+-- proposalSimpleUnbiased x g = return (x', 1.0, 1.0)+-- @+--+-- For biased proposals, the kernel ratio is qYX / qXY, where qXY is the+-- probability density to move from X to Y, and the absolute value of the+-- determinant of the Jacobian matrix differs from 1.0.+type ProposalSimple a = a -> GenIO -> IO (a, Log Double, Log Double)  convertS :: Lens' b a -> ProposalSimple a -> ProposalSimple b convertS l s = s'   where     s' v g = do-      (x', r) <- s (v ^. l) g-      return (set l x' v, r)+      (x', r, j) <- s (v ^. l) g+      return (set l x' v, r, j)  -- | Tune the acceptance ratio of a 'Proposal'; see 'tune', or 'autotuneCycle'. data Tuner a = Tuner@@ -127,21 +157,27 @@   where     f' x = convertS l $ f x +-- | Tune the proposal?+data Tune = Tune | NoTune+  deriving (Show, Eq)+ -- | Create a possibly tuneable proposal. createProposal ::+  -- | Description of the proposal type and parameters.+  PDescription ->   -- | Function creating a simple proposal for a given tuning parameter. The   -- larger the tuning parameter, the larger the proposal (and the lower the   -- expected acceptance ratio), and vice versa.   (Double -> ProposalSimple a) ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Activate tuning?-  Bool ->+  Tune ->   Proposal a-createProposal f n w True = Proposal n w (f 1.0) (Just $ Tuner 1.0 f)-createProposal f n w False = Proposal n w (f 1.0) Nothing+createProposal d f n w Tune = Proposal n d w (f 1.0) (Just $ Tuner 1.0 f)+createProposal d f n w NoTune = Proposal n d w (f 1.0) Nothing  -- Minimal tuning parameter; subject to change. tuningParamMin :: Double@@ -223,11 +259,9 @@ fromList [] =   error "fromList: Received an empty list but cannot create an empty Cycle." fromList xs =-  if length (nub nms) == length nms+  if length (nub xs) == length xs     then Cycle xs def-    else error "fromList: Proposals don't have unique names."-  where-    nms = map pName xs+    else error "fromList: Proposals are not unique."  -- | Set the order of 'Proposal's in a 'Cycle'. setOrder :: Order -> Cycle a -> Cycle a@@ -243,7 +277,7 @@     return [psR ++ reverse psR | psR <- psRs]   SequentialReversibleO -> return $ replicate n $ ps ++ reverse ps   where-    !ps = concat [replicate (pWeight m) m | m <- xs]+    !ps = concat [replicate (fromPWeight $ pWeight m) m | m <- xs]  -- | Tune 'Proposal's in the 'Cycle'. See 'tune'. tuneCycle :: Map (Proposal a) Double -> Cycle a -> Cycle a@@ -271,10 +305,12 @@   BL.ByteString ->   BL.ByteString ->   BL.ByteString ->+  BL.ByteString ->   BL.ByteString-renderRow name weight nAccept nReject acceptRatio tuneParam manualAdjustment = "   " <> nm <> wt <> na <> nr <> ra <> tp <> mt+renderRow name ptype weight nAccept nReject acceptRatio tuneParam manualAdjustment = "   " <> nm <> pt <> wt <> na <> nr <> ra <> tp <> mt   where     nm = alignLeft 30 name+    pt = alignLeft 50 ptype     wt = alignRight 8 weight     na = alignRight 15 nAccept     nr = alignRight 15 nReject@@ -284,12 +320,13 @@  proposalHeader :: BL.ByteString proposalHeader =-  renderRow "Proposal" "Weight" "Accepted" "Rejected" "Ratio" "Tuning parameter" "Consider manual adjustment"+  renderRow "Name" "Description" "Weight" "Accepted" "Rejected" "Ratio" "Tuning parameter" "Consider manual adjustment"  summarizeProposal :: Proposal a -> Maybe (Int, Int, Double) -> BL.ByteString summarizeProposal m r =   renderRow-    (BL.pack name)+    (BL.pack $ fromPName $ pName m)+    (BL.pack $ fromPDescription $ pDescription m)     weight     nAccept     nReject@@ -297,8 +334,7 @@     tuneParamStr     manualAdjustmentStr   where-    name = pName m-    weight = BB.toLazyByteString $ BB.intDec $ pWeight m+    weight = BB.toLazyByteString $ BB.intDec $ fromPWeight $ 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@@ -324,7 +360,7 @@       ++ [hLine proposalHeader]   where     ps = ccProposals c-    mpi = BB.toLazyByteString $ BB.intDec $ sum $ map pWeight ps+    mpi = BB.toLazyByteString $ BB.intDec $ sum $ map (fromPWeight . pWeight) ps     ar m = acceptanceRatio m a  -- | For each key @k@, store the number of accepted and rejected proposals.
src/Mcmc/Proposal/Bactrian.hs view
@@ -52,10 +52,10 @@   Double ->   Double ->   GenIO ->-  IO (Double, Log Double)+  IO (Double, Log Double, Log Double) bactrianAdditive m s x g = do   dx <- genBactrian m s g-  return (x + dx, 1.0)+  return (x + dx, 1.0, 1.0)  -- bactrianSimple lens spike stdDev tune forwardOp backwardOp bactrianAdditiveSimple ::@@ -75,9 +75,9 @@ -- The [Bactrian -- kernel](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3845170/figure/fig01) is -- a mixture of two symmetrically arranged normal distributions. The spike--- parameter loosely determines the standard deviations of the individual humps--- while the second parameter refers to the standard deviation of the complete--- Bactrian kernel.+-- parameter (0, 1) loosely determines the standard deviations (>0.0) of the+-- individual humps while the second parameter refers to the standard deviation+-- of the complete Bactrian kernel. -- -- See https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3845170/. slideBactrian ::@@ -86,13 +86,15 @@   -- | Standard deviation.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-slideBactrian m s = createProposal (bactrianAdditiveSimple m s)+slideBactrian m s = createProposal description (bactrianAdditiveSimple m s)+  where+    description = PDescription $ "Slide Bactrian; spike: " ++ show m ++ ", sd: " ++ show s  -- We have: -- x  (1+dx ) = x'@@ -108,12 +110,14 @@   Double ->   Double ->   GenIO ->-  IO (Double, Log Double)+  IO (Double, Log Double, Log Double) bactrianMult m s x g = do-  dx <- genBactrian m s g-  let qXY = logDensityBactrian m s dx-      qYX = logDensityBactrian m s (fInv dx)-  return (x * (1 + dx), qYX / qXY)+  du <- genBactrian m s g+  let qXY = logDensityBactrian m s du+      qYX = logDensityBactrian m s (fInv du)+      u = 1.0 + du+      jac = Exp $ log $ recip u+  return (x * u, qYX / qXY, jac)  bactrianMultSimple :: Double -> Double -> Double -> ProposalSimple Double bactrianMultSimple m s t@@ -130,10 +134,12 @@   -- | Standard deviation.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-scaleBactrian m s = createProposal (bactrianMultSimple m s)+scaleBactrian m s = createProposal description (bactrianMultSimple m s)+  where+    description = PDescription $ "Scale Bactrian; spike: " ++ show m <> ", sd: " <> show s
src/Mcmc/Proposal/Generic.hs view
@@ -18,58 +18,54 @@ import Mcmc.Proposal import Numeric.Log import Statistics.Distribution-import System.Random.MWC -sampleCont ::-  (ContDistr d, ContGen d) =>-  d ->-  (a -> Double -> a) ->-  Maybe (Double -> Double) ->-  a ->-  GenIO ->-  IO (a, Log Double)-sampleCont d f mfInv x g = do-  dx <- genContVar d g-  let r = case mfInv of-        Nothing -> 1.0-        Just fInv ->-          let qXY = Exp $ logDensity d dx-              qYX = Exp $ logDensity d (fInv dx)-           in qYX / qXY-  return (x `f` dx, r)-{-# INLINEABLE sampleCont #-}- -- | Generic function to create proposals for continuous parameters ('Double'). genericContinuous ::   (ContDistr d, ContGen d) =>   -- | Probability distribution   d ->-  -- | Forward operator, e.g. (+), so that x + dx = x'.+  -- | Forward operator.+  --+  -- For example, for a multiplicative proposal on one variable the forward+  -- operator is @(*)@, so that @x * u = y@.   (a -> Double -> a) ->-  -- | Inverse operator, e.g., 'negate', so that x' + (negate dx) = x. Only-  -- required for biased proposals.+  -- | Inverse operator.+  --+  -- For example, 'recip' for a multiplicative proposal on one variable, since+  -- @y * (recip u) = x * u * (recip u) = x@.+  --+  -- Required for biased proposals.   Maybe (Double -> Double) ->+  -- | Function to compute the absolute value of the determinant of the Jacobian+  -- matrix. For example, for a multiplicative proposal on one variable, we have+  --+  -- @+  -- detJacobian _ u = Exp $ log $ recip u+  -- @+  --+  -- That is, the determinant of the Jacobian matrix of multiplication is just+  -- the reciprocal value of @u@ (with conversion to log domain).+  --+  -- Required for proposals for which absolute value of the determinant of the+  -- Jacobian differs from 1.0.+  --+  -- Conversion to log domain is necessary, because some determinants of+  -- Jacobians are very small (or large).+  Maybe (a -> Double -> Log Double) ->   ProposalSimple a-genericContinuous d f fInv = sampleCont d f fInv--sampleDiscrete ::-  (DiscreteDistr d, DiscreteGen d) =>-  d ->-  (a -> Int -> a) ->-  Maybe (Int -> Int) ->-  a ->-  GenIO ->-  IO (a, Log Double)-sampleDiscrete d f mfInv x g = do-  dx <- genDiscreteVar d g-  let r = case mfInv of+genericContinuous d f mInv mJac x g = do+  u <- genContVar d g+  let r = case mInv of         Nothing -> 1.0         Just fInv ->-          let qXY = Exp $ logProbability d dx-              qYX = Exp $ logProbability d (fInv dx)+          let qXY = Exp $ logDensity d u+              qYX = Exp $ logDensity d (fInv u)            in qYX / qXY-  return (x `f` dx, r)-{-# INLINEABLE sampleDiscrete #-}+      j = case mJac of+        Nothing -> 1.0+        Just fJac -> fJac x u+  return (x `f` u, r, j)+{-# INLINEABLE genericContinuous #-}  -- | Generic function to create proposals for discrete parameters ('Int'). genericDiscrete ::@@ -82,4 +78,13 @@   -- required for biased proposals.   Maybe (Int -> Int) ->   ProposalSimple a-genericDiscrete fd f fInv = sampleDiscrete fd f fInv+genericDiscrete d f mfInv x g = do+  u <- genDiscreteVar d g+  let r = case mfInv of+        Nothing -> 1.0+        Just fInv ->+          let qXY = Exp $ logProbability d u+              qYX = Exp $ logProbability d (fInv u)+           in qYX / qXY+  return (x `f` u, r, 1.0)+{-# INLINEABLE genericDiscrete #-}
src/Mcmc/Proposal/Scale.hs view
@@ -20,12 +20,20 @@  import Mcmc.Proposal import Mcmc.Proposal.Generic+import Numeric.Log import Statistics.Distribution.Gamma  -- The actual proposal with tuning parameter. The tuning parameter does not -- change the mean. scaleSimple :: Double -> Double -> Double -> ProposalSimple Double-scaleSimple k th t = genericContinuous (gammaDistr (k / t) (th * t)) (*) (Just recip)+scaleSimple k th t =+  genericContinuous+    (gammaDistr (k / t) (th * t))+    (*)+    (Just recip)+    (Just jac)+  where+    jac _ = Exp . log . recip  -- | Multiplicative proposal with Gamma distributed kernel. scale ::@@ -34,13 +42,15 @@   -- | Scale.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-scale k th = createProposal (scaleSimple k th)+scale k th = createProposal description (scaleSimple k th)+  where+    description = PDescription $ "Scale; shape: " ++ show k ++ ", scale: " ++ show th  -- | Multiplicative proposal with Gamma distributed kernel. --@@ -50,20 +60,31 @@   -- | Shape.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-scaleUnbiased k = createProposal (scaleSimple k (1 / k))--contra :: (Double, Double) -> Double -> (Double, Double)-contra (x, y) z = (x * z, y / z)+scaleUnbiased k = createProposal description (scaleSimple k (1 / k))+  where+    description = PDescription $ "Scale unbiased; shape: " ++ show k  scaleContrarilySimple :: Double -> Double -> Double -> ProposalSimple (Double, Double)-scaleContrarilySimple k th t = genericContinuous (gammaDistr (k / t) (th * t)) contra (Just recip)+scaleContrarilySimple k th t =+  genericContinuous+    (gammaDistr (k / t) (th * t))+    contra+    (Just recip)+    (Just jac)+  where+    contra (x, y) u = (x * u, y / u)+    jac _ u = Exp $ log $ recip $ u * u +-- -- Determinant of Jacobian matrix.+-- contraJac :: (Double, Double) -> Double+-- contraJac (x, y) = x * y+ -- | Multiplicative proposal with Gamma distributed kernel. -- -- The two values are scaled contrarily so that their product stays constant.@@ -74,10 +95,12 @@   -- | Scale.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal (Double, Double)-scaleContrarily k th = createProposal (scaleContrarilySimple k th)+scaleContrarily k th = createProposal description (scaleContrarilySimple k th)+  where+    description = PDescription $ "Scale contrariliy; shape: " ++ show k ++ ", scale: " ++ show th
+ src/Mcmc/Proposal/Simplex.hs view
@@ -0,0 +1,203 @@+{-# LANGUAGE TemplateHaskell #-}++-- |+-- Module      :  Mcmc.Proposal.Simplex+-- Description :  Proposals on simplices+-- Copyright   :  (c) Dominik Schrempf, 2020+-- License     :  GPL-3.0-or-later+--+-- Maintainer  :  dominik.schrempf@gmail.com+-- Stability   :  unstable+-- Portability :  portable+--+-- Creation date: Mon Oct 19 15:32:31 2020.+module Mcmc.Proposal.Simplex+  ( -- * Elements of simplices+    Simplex (toVector),+    simplexUniform,+    simplexFromVector,++    -- * Proposals on simplices+    dirichlet,+    beta,+  )+where++import Data.Aeson+import Data.Aeson.TH+import qualified Data.Vector.Unboxed as V+import Mcmc.Proposal+import Numeric.Log+import Statistics.Distribution+import Statistics.Distribution.Beta+import Statistics.Distribution.Dirichlet++-- import Debug.Trace++-- | An element of a simplex.+--+-- A vector of non-negative values summing to one.+--+-- The nomenclature is not very consistent, because a K-dimensional simplex is+-- usually considered to be the set containing all @K@-dimensional vectors with+-- non-negative elements that sum to 1.0. However, I couldn't come up with a+-- better name. Maybe @SimplexElement@, but that was too long.+newtype Simplex = SimplexUnsafe {toVector :: V.Vector Double}+  deriving (Eq, Show)++$(deriveJSON defaultOptions ''Simplex)++-- Tolerance.+eps :: Double+eps = 1e-14++-- Check if vector is normalized with tolerance 'eps'.+isNormalized :: V.Vector Double -> Bool+isNormalized v+  | abs (V.sum v - 1.0) > eps = False+  | otherwise = True++-- Check if vector contains negative elements.+isNegative :: V.Vector Double -> Bool+isNegative = V.any (< 0)++-- | Ensure that the value vector is an element of a simplex.+--+-- Return 'Left' if:+-- - The value vector is empty.+-- - The value vector contains negative elements.+-- - The value vector is not normalized.+simplexFromVector :: V.Vector Double -> Either String Simplex+simplexFromVector v+  | V.null v = Left "simplexFromVector: Vector is empty."+  | isNegative v = Left "simplexFromVector: Vector contains negative elements."+  | not (isNormalized v) = Left "simplexFromVector: Vector is not normalized."+  | otherwise = Right $ SimplexUnsafe v++-- | Create the uniform element of the K-dimensional simplex.+--+-- Set all values to \(1/D\).+simplexUniform :: Int -> Simplex+simplexUniform k = either error id $ simplexFromVector $ V.replicate k (1.0 / fromIntegral k)++-- Tuning function is inverted (high alpha means small steps).+getTuningFunction :: Double -> (Double -> Double)+getTuningFunction t = (/ t'')+  where+    -- Start with small steps.+    t' = t / 10000+    -- Extremely small tuning parameters lead to numeric overflow. The square+    -- root pulls the tuning parameter closer to 1.0. However, overflow may+    -- still occur (the involved Gamma functions grow faster than the+    -- exponential). I did not observe numeric underflow in my tests.+    t'' = sqrt t'++-- The tuning parameter is proportional to the inverted mean of the shape+-- parameter values.+--+-- The values determining the proposal size have been set using an example+-- analysis. They are good values for this analysis, but may fail for other+-- analyses.+dirichletSimple :: Double -> ProposalSimple Simplex+dirichletSimple t (SimplexUnsafe xs) g = do+  -- If @t@ is high and above 1.0, the parameter vector will be low, and the+  -- variance will be high. If @t@ is low and below 1.0, the parameter vector+  -- will be high, and the Dirichlet distribution will be very concentrated with+  -- low variance.+  let ddXs = either error id $ dirichletDistribution $ V.map tf xs+  -- traceShowM $ V.map tf xs+  ys <- dirichletSample ddXs g+  -- traceShowM ys+  -- Have to check if parameters are valid (because zeroes do occur).+  let eitherDdYs = dirichletDistribution $ V.map tf ys+  let r = case eitherDdYs of+        -- Set ratio to 0; so that the proposal will not be accepted.+        Left _ -> 0+        Right ddYs -> dirichletDensity ddYs xs / dirichletDensity ddXs ys+  -- I do not think a Jacobian is necessary in this case. I do know that if a+  -- subset of states is updated a Jacobian would be necessary.+  --+  -- traceShowM mhRatio+  return (SimplexUnsafe ys, r, 1.0)+  where+    tf = getTuningFunction t++-- | Dirichlet proposal on a simplex.+--+-- For a given element of a K-dimensional simplex, propose a new element of the+-- K-dimensional simplex. The new element is sampled from the multivariate+-- Dirichlet distribution with parameter vector being the old element of the+-- simplex.+--+-- The tuning parameter is used to determine the concentration of the Dirichlet+-- distribution: the lower the tuning parameter, the higher the concentration.+--+-- This proposal may have low acceptance ratios. In this case, please see the+-- coordinate wise 'beta' proposal.+dirichlet :: PName -> PWeight -> Tune -> Proposal Simplex+dirichlet = createProposal (PDescription "Dirichlet") dirichletSimple++-- The tuning parameter is the inverted mean of the shape values.+--+-- The values determining the proposal size have been set using an example+-- analysis. They are good values for this analysis, but may fail for other+-- analyses.+--+-- See also the 'dirichlet' proposal.+betaSimple :: Int -> Double -> ProposalSimple Simplex+betaSimple i t (SimplexUnsafe xs) g = do+  -- Shape parameters of beta distribution. Do not assume that the sum of the+  -- elements of 'xs' is 1.0, because then repeated proposals let the sum of the+  -- vector diverge.+  let aX = xI+      bX = xsSum - xI+      bdXI = betaDistr (tf aX) (tf bX)+  -- New value of element i.+  yI <- genContVar bdXI g+  -- Shape parameters of beta distribution.+  let aY = yI+      bY = 1.0 - yI+      eitherBdYI = betaDistrE (tf aY) (tf bY)+  -- See 'dirichlet', which has the same construct.+  let r = case eitherBdYI of+        Nothing -> 0+        Just bdYI -> Exp $ logDensity bdYI xI - logDensity bdXI yI+      -- The absolute value of the determinant of the Jacobian. Derivation takes+      -- a while...+      ja1 = bY / bX+      jac = Exp $ fromIntegral (V.length xs - 2) * log ja1+  -- Construct new vector.+  let -- Normalization function for other elements.+      -- nf x = x * bY / bX+      --+      -- It turns out, that this factor is also needed to compute the determinant+      -- of the Jacobian above.+      nf x = x * ja1+      ys = V.generate (V.length xs) (\j -> if i == j then yI else nf (xs V.! j))+  return (either error id $ simplexFromVector ys, r, jac)+  where+    xI = xs V.! i+    xsSum = V.sum xs+    tf = getTuningFunction t++-- | Beta proposal on a specific coordinate @i@ on a simplex.+--+-- For a given element of a K-dimensional simplex, propose a new element of the+-- K-dimensional simplex. The coordinate @i@ of the new element is sampled from+-- the beta distribution. The other coordinates are normalized such that the+-- values sum to 1.0. The parameters of the beta distribution are chosen such+-- that the expected value of the beta distribution is the value of the old+-- coordinate.+--+-- The tuning parameter is used to determine the concentration of the beta+-- distribution: the lower the tuning parameter, the higher the concentration.+--+-- See also the 'dirichlet' proposal.+--+-- No "out of bounds" checks are performed during compile time. Run time errors+-- can occur if @i@ is negative, or if @i-1@ is larger than the length of the+-- element vector of the simplex.+beta :: Int -> PName -> PWeight -> Tune -> Proposal Simplex+beta i = createProposal description (betaSimple i)+  where+    description = PDescription $ "Beta; coordinate: " ++ show i
src/Mcmc/Proposal/Slide.hs view
@@ -14,7 +14,7 @@ module Mcmc.Proposal.Slide   ( slide,     slideSymmetric,-    slideUniform,+    slideUniformSymmetric,     slideContrarily,   ) where@@ -26,7 +26,8 @@  -- The actual proposal with tuning parameter. slideSimple :: Double -> Double -> Double -> ProposalSimple Double-slideSimple m s t = genericContinuous (normalDistr m (s * t)) (+) (Just negate)+slideSimple m s t =+  genericContinuous (normalDistr m (s * t)) (+) (Just negate) Nothing  -- | Additive proposal with normally distributed kernel. slide ::@@ -35,17 +36,20 @@   -- | Standard deviation.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-slide m s = createProposal (slideSimple m s)+slide m s = createProposal description (slideSimple m s)+  where+    description = PDescription $ "Slide; mean: " ++ show m ++ ", sd: " ++ show s  -- The actual proposal with tuning parameter. slideSymmetricSimple :: Double -> Double -> ProposalSimple Double-slideSymmetricSimple s t = genericContinuous (normalDistr 0.0 (s * t)) (+) Nothing+slideSymmetricSimple s t =+  genericContinuous (normalDistr 0.0 (s * t)) (+) Nothing Nothing  -- | Additive proposal with normally distributed kernel with mean zero. This -- proposal is very fast, because the Metropolis-Hastings ratio does not include@@ -54,39 +58,44 @@   -- | Standard deviation.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-slideSymmetric s = createProposal (slideSymmetricSimple s)+slideSymmetric s = createProposal description (slideSymmetricSimple s)+  where+    description = PDescription $ "Slide symmetric; sd: " ++ show s  -- The actual proposal with tuning parameter. slideUniformSimple :: Double -> Double -> ProposalSimple Double slideUniformSimple d t =-  genericContinuous (uniformDistr (- t * d) (t * d)) (+) Nothing+  genericContinuous (uniformDistr (- t * d) (t * d)) (+) Nothing Nothing --- | Additive proposal with uniformly distributed kernel. This proposal is very fast,--- because the Metropolis-Hastings ratio does not include calculation of the--- forwards and backwards kernels.-slideUniform ::+-- | Additive proposal with uniformly distributed kernel with mean zero. This+-- proposal is very fast, because the Metropolis-Hastings ratio does not include+-- calculation of the forwards and backwards kernels.+slideUniformSymmetric ::   -- | Delta.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal Double-slideUniform d = createProposal (slideUniformSimple d)+slideUniformSymmetric d = createProposal description (slideUniformSimple d)+  where+    description = PDescription $ "Slide uniform symmetric; delta: " ++ show d  contra :: (Double, Double) -> Double -> (Double, Double)-contra (x, y) d = (x + d, y - d)+contra (x, y) u = (x + u, y - u)  slideContrarilySimple :: Double -> Double -> Double -> ProposalSimple (Double, Double)-slideContrarilySimple m s t = genericContinuous (normalDistr m (s * t)) contra (Just negate)+slideContrarilySimple m s t =+  genericContinuous (normalDistr m (s * t)) contra (Just negate) Nothing  -- | Additive proposal with normally distributed kernel. --@@ -98,10 +107,12 @@   -- | Standard deviation.   Double ->   -- | Name.-  String ->-  -- | Weight.-  Int ->+  PName ->+  -- | PWeight.+  PWeight ->   -- | Enable tuning.-  Bool ->+  Tune ->   Proposal (Double, Double)-slideContrarily m s = createProposal (slideContrarilySimple m s)+slideContrarily m s = createProposal description (slideContrarilySimple m s)+  where+    description = PDescription $ "Slide contrarily; mean: " ++ show m ++ ", sd: " ++ show s
src/Mcmc/Save.hs view
@@ -68,7 +68,7 @@ $(deriveJSON defaultOptions ''Save)  toSave :: Status a -> Save a-toSave (Status nm it i tr ac br at is f sv vb g _ _ _ _ c _) =+toSave (Status nm it i tr ac br at is f sv vb g _ _ _ _ _ c _) =   Save     nm     it@@ -104,9 +104,10 @@   (a -> Log Double) ->   Cycle a ->   Monitor a ->+  Maybe (Cleaner a) ->   Save a ->   Status a-fromSave p l c m (Save nm it i tr ac' br at is f sv vb g' ts) =+fromSave pr lh cc m cl (Save nm it i tr ac' br at is f sv vb g' ts) =   Status     nm     it@@ -122,16 +123,17 @@     g     Nothing     Nothing-    p-    l-    c'+    pr+    lh+    cl+    cc'     m   where-    ac = transformKeysA [0 ..] (ccProposals c) ac'+    ac = transformKeysA [0 ..] (ccProposals cc) ac'     -- TODO: Splitmix. Remove as soon as split mix is used and is available with     -- the statistics package.     g = unsafePerformIO $ restore $ toSeed g'-    c' = tuneCycle (M.mapMaybe id $ M.fromList $ zip (ccProposals c) ts) c+    cc' = tuneCycle (M.mapMaybe id $ M.fromList $ zip (ccProposals cc) ts) cc  -- | Load a 'Status' from file. --@@ -139,23 +141,29 @@ -- a chain is restored: -- - prior function -- - likelihood function+-- - cleaning function -- - cycle -- - monitor -- -- To avoid incomplete continued runs, the @.mcmc@ file is removed after load. loadStatus ::   FromJSON a =>+  -- | Prior function.   (a -> Log Double) ->+  -- | Likelihood function.   (a -> Log Double) ->   Cycle a ->   Monitor a ->+  -- | Cleaner, if needed.+  Maybe (Cleaner a) ->+  -- | Path of status to load.   FilePath ->   IO (Status a)-loadStatus p l c m fn = do+loadStatus pr lh cc mn cl fn = do   res <- eitherDecode . decompress <$> BL.readFile fn   let s = case res of         Left err -> error err-        Right sv -> fromSave p l c m sv+        Right sv -> fromSave pr lh cc mn cl sv   -- Check if prior and likelihood matches.   let Item x svp svl = item s   -- Recompute and check the prior and likelihood for the last state because the@@ -163,10 +171,10 @@   -- function, but having the same prior and likelihood at the last state is   -- already a good indicator.   when-    (p x /= svp)+    (pr x /= svp)     (error "loadStatus: Provided prior function does not match the saved prior.")   when-    (l x /= svl)+    (lh x /= svl)     (error "loadStatus: Provided likelihood function does not match the saved likelihood.")   removeFile fn   return s
src/Mcmc/Status.hs view
@@ -21,12 +21,15 @@ -- -- Creation date: Tue May  5 18:01:15 2020. module Mcmc.Status-  ( Status (..),+  ( Cleaner (..),+    Status (..),     status,+    cleanWith,     saveWith,     force,     quiet,     debug,+    noData,   ) where @@ -42,6 +45,28 @@ import System.Random.MWC hiding (save) import Prelude hiding (cycle) +-- | Clean the state periodically.+--+-- The prior and the likelihood will be updated after the cleaning process.+--+-- For long chains, successive numerical errors can accumulate such that the+-- state diverges from honoring specific required constraints. In these cases, a+-- 'Cleaner' can be used to ensure that the required constraints of the state+-- are honored. For example, the branches of an ultrametric phylogeny may+-- diverge slightly after successful many proposals such that the phylogeny is+-- not anymore ultrametric.+--+-- Please be aware that the Markov chain will not converge to the true posterior+-- distribution if the state is changed substantially! Only apply subtle changes+-- that are absolutely necessary to preserve the required properties of the+-- state such as specific numerical constraints.+data Cleaner a = Cleaner+  { -- | Clean every given number of iterations.+    clEvery :: Int,+    -- | Cleaning function. Executed before monitoring the state.+    clFunction :: a -> a+  }+ -- | The 'Status' contains all information to run an MCMC chain. It is -- constructed using the function 'status'. --@@ -101,6 +126,8 @@     -- | The likelihood function. The un-normalized posterior is the product of     -- the prior and the likelihood.     likelihoodF :: a -> Log Double,+    -- | Clean the state periodically.+    cleaner :: Maybe (Cleaner a),     --     -- Variables related to the algorithm; not saved. @@ -118,8 +145,8 @@   (a -> Log Double) ->   -- | The likelihood function.   (a -> Log Double) ->-  -- | A list of 'Proposal's executed in forward order. The-  -- chain will be logged after each cycle.+  -- | A list of 'Proposal's executed in forward order. The chain will be logged+  -- after each cycle.   Cycle a ->   -- | A 'Monitor' observing the chain.   Monitor a ->@@ -127,14 +154,14 @@   a ->   -- | Number of burn in iterations; deactivate burn in with 'Nothing'.   Maybe Int ->-  -- | Auto tuning period (only during burn in); deactivate-  -- auto tuning with 'Nothing'.+  -- | Auto tuning period (only during burn in); deactivate auto tuning with+  -- 'Nothing'.   Maybe Int ->-  -- | Number of normal iterations excluding burn in. Note-  -- that auto tuning only happens during burn in.+  -- | Number of normal iterations excluding burn in. Note that auto tuning only+  -- happens during burn in.   Int ->-  -- | A source of randomness. For reproducible runs, make-  -- sure to use generators with the same, fixed seed.+  -- | A source of randomness. For reproducible runs, make sure to use+  -- generators with the same, fixed seed.   GenIO ->   Status a status n p l c m x mB mT nI g@@ -157,11 +184,17 @@       Nothing       p       l+      Nothing       c       m   where     i = Item x (p x) (l x) +-- | Clean the state every given number of generations using the given function.+-- See 'Cleaner'.+cleanWith :: Cleaner a -> Status a -> Status a+cleanWith c s = s {cleaner = Just c}+ -- | Save the Markov chain with trace of given length. saveWith :: Int -> Status a -> Status a saveWith n s = s {save = Just n}@@ -179,3 +212,7 @@ -- | Be verbose. debug :: Status a -> Status a debug s = s {verbosity = Debug}++-- | Set the likelihood function to 1.0. Useful for debugging and testing.+noData :: Status a -> Status a+noData s = s {likelihoodF = const 1.0}
− src/Mcmc/Tools/Shuffle.hs
@@ -1,64 +0,0 @@--- |--- Module      :  Mcmc.Tools.Shuffle--- Description :  Shuffle a list--- Copyright   :  (c) Dominik Schrempf 2020--- License     :  GPL-3.0-or-later------ Maintainer  :  dominik.schrempf@gmail.com--- Stability   :  unstable--- Portability :  portable------ Creation date: Wed May 20 14:37:09 2020.------ From https://wiki.haskell.org/Random_shuffle.-module Mcmc.Tools.Shuffle-  ( shuffle,-    shuffleN,-    grabble,-  )-where--import Control.Monad-import Control.Monad.ST-import Data.Vector (Vector)-import qualified Data.Vector as V-import qualified Data.Vector.Mutable as M-import System.Random.MWC-  ( GenIO,-    uniformR,-  )---- | Shuffle a list.-shuffle :: [a] -> GenIO -> IO [a]-shuffle xs g = head <$> grabble xs 1 (length xs) g---- | Shuffle a list @n@ times.-shuffleN :: [a] -> Int -> GenIO -> IO [[a]]-shuffleN xs n = grabble xs n (length xs)---- -- Using System.Random.Shuffle. Speed is the same, so stay without additional dependency.--- -- | Shuffle a list @n@ times.--- shuffleN :: [a] -> Int -> GenIO -> IO [[a]]--- shuffleN xs n g = replicateM n $ fmap (shuffle xs) (rseqM (length xs - 1) g)---   where---     rseqM :: Int -> GenIO -> IO [Int]---     rseqM 0 _ = return []---     rseqM i gen = liftM2 (:) (uniformR (0, i) gen) (rseqM (i - 1) gen)---- | @grabble xs m n@ is /O(m*n')/, where @n' = min n (length xs)@. Choose @n'@--- elements from @xs@, without replacement, and that @m@ times.-grabble :: [a] -> Int -> Int -> GenIO -> IO [[a]]-grabble xs m n gen = do-  swapss <- replicateM m $-    forM [0 .. min (l - 1) n] $ \i -> do-      j <- uniformR (i, l) gen-      return (i, j)-  return $ map (V.toList . V.take n . swapElems (V.fromList xs)) swapss-  where-    l = length xs - 1--swapElems :: Vector a -> [(Int, Int)] -> Vector a-swapElems xs swaps = runST $ do-  mxs <- V.unsafeThaw xs-  mapM_ (uncurry $ M.unsafeSwap mxs) swaps-  V.unsafeFreeze mxs
test/Mcmc/ProposalSpec.hs view
@@ -20,10 +20,10 @@ import Test.Hspec  p1 :: Proposal Double-p1 = slideSymmetric 1.0 "test1" 1 True+p1 = slideSymmetric 1.0 (PName "Test 1") (PWeight 1) Tune  p2 :: Proposal Double-p2 = slideSymmetric 1.0 "test2" 3 True+p2 = slideSymmetric 1.0 (PName "Test 2") (PWeight 3) Tune  c :: Cycle Double c = fromList [p1, p2]
test/Mcmc/SaveSpec.hs view
@@ -38,10 +38,10 @@ proposals :: Cycle Double proposals =   fromList-    [ slideSymmetric 0.1 "small" 5 True,-      slideSymmetric 1.0 "medium" 2 True,-      slideSymmetric 5.0 "large" 2 True,-      slide 1.0 4.0 "skewed" 1 True+    [ slideSymmetric 0.1 (PName "Small") (PWeight 5) Tune,+      slideSymmetric 1.0 (PName "Medium") (PWeight 2) Tune,+      slideSymmetric 5.0 (PName "Large") (PWeight 2) Tune,+      slide 1.0 4.0 (PName "Skewed") (PWeight 1) Tune     ]  monStd :: MonitorStdOut Double@@ -71,7 +71,7 @@                   saveWith 100 $                     status "SaveSpec" (const 1) lh proposals mon 0 nBurn nAutoTune nIter gen         saveStatus "SaveSpec.json" s-        s' <- loadStatus (const 1) lh proposals mon "SaveSpec.json"+        s' <- loadStatus (const 1) lh proposals mon Nothing "SaveSpec.json"         r <- mh s         r' <- mh s'         -- Done during 'loadStatus'.