import qualified Control.Monad.Bayes.Sampler.Lazy as Lazy
import qualified Control.Monad.Bayes.Inference.Lazy.MH as Lazy
import qualified Control.Monad.Bayes.Inference.Lazy.WIS as Lazy
import qualified Control.Monad.Bayes.Sampler.Strict as Strict
import Control.Monad.Bayes.Class
import qualified Data.Text as T
import Numeric.Log
import Control.Arrow (first, second)
import Statistics.Distribution
import qualified Statistics.Distribution.Poisson as S
import Control.Monad.Bayes.Enumerator
:l ../plotting.hs
The sampler defined in Control.Monad.Bayes.Sampler.Strict
fares poorly with infinite data structures. For example, finiteList
defined below is a distribution over a small finite set, but because it is defined as the marginal of an infinite list, running it with a strict sampling monad will not terminate.
finiteList :: MonadDistribution m => m [Double]
finiteList = do
infiniteList <- sequence $ repeat random
return (take 3 infiniteList)
-- Code below will not terminate:
-- Strict.sampler finiteList
One solution is to use a streaming library, such as pipes
, and indeed this proves useful in many situations. But another is to define a lazy sampler, which is the approach taken by LazyPPL.
Lazy.sampler finiteList
[0.8503508027827793,0.21861861054454101,0.975152268854938]
Control.Monad.Bayes.Sampler.Lazy
is simply a port of LazyPPL, with some refactoring. In particular, what LazyPPL calls the Prob
monad, we now call Sampler
, and Meas
is built modularly as Weighted Sampler
.
LazyPPL also comes with a number of inference algorithms that make special use of the sampler's laziness, including weighted importance sampling and Metropolis-Hastings. Monad-Bayes has these also, as shown below:
model :: MonadMeasure m => m Bool
model = do
-- Prior belief: it is Sunday with prob. 1/7
sunday <- bernoulli (1/7)
-- I know the rates of buses on the different days:
let rate = if sunday then 3 else 10
-- observe 4 buses
factor $ Exp $ logProbability (S.poisson rate) 4
-- score $ poissonPdf rate 4
return sunday
xws <- Lazy.lwis 10000 model
plot $ first (T.pack . show) <$> toEmpirical (take 10000 xws)
xws <- Lazy.mh 0.5 model
plot $ first (T.pack . show) <$> toEmpirical (take 10000 xws)