packages feed

monte-carlo-0.6: examples/Binomial.hs

module Main
    where

import Control.Monad
import Control.Monad.Primitive( PrimMonad )
import Data.List( foldl' )
import Text.Printf( printf )

import Control.Monad.MC
import qualified Data.Summary.Double as S

-- | Sample from a binomial distribution with the given parameters.
binomial :: (PrimMonad m) => Int -> Double -> MC m Int
binomial n p = let
    q     = 1 - p
    probs = map (\i -> (fromIntegral $ n `choose` i) * p^^i * q^^(n-i)) [0..n]
    in sampleIntWithWeights probs (n+1)

-- | Get a sample confidence interval for the mean after @reps@ replications of
-- a binomial with the given parameters.
binomialMean :: (PrimMonad m) => Int -> Double -> Int -> MC m (Double,Double)
binomialMean n p reps =
    liftM (S.meanCI 0.95) $
        foldMC (\s x -> return $! S.insertWith fromIntegral x s) S.empty
               reps (binomial n p)

-- | Compute @reps@ 95% confidence intervals for the mean of an @(n,p)@
-- binormal based on samples of the given size, and record the number
-- of intervals that contain the true mean.
coverage :: (PrimMonad m) => Int -> Double -> Int -> Int -> MC m Int
coverage n p size reps =
    foldMC (\tot ci -> return $! update tot (mu `inInterval` ci)) 0
           reps (binomialMean n p size)
  where
    mu = fromIntegral n * p
    x `inInterval` (a,b) = x > a && x < b
    update tot b = tot + (if b then 1 else 0)

main =
    let seed = 0
        reps = 10000
        n    = 10
        p    = 0.2
        size = 500
        c    = (coverage n p size reps) `evalMC` (mt19937 seed)
    in
        printf "\nOf %d 95%%-intervals, %d contain the true value.\n" reps c


---------------------------   Utility functions -----------------------------

factorial :: Int -> Int
factorial n | n <= 0    = 1
            | otherwise = n * factorial (n-1)

choose :: Int -> Int -> Int
choose n k = factorial n `div` (factorial (n-k) * factorial k)