packages feed

monte-carlo-0.6: examples/Pi.lhs

In this example, we compute a Monte Carlo estimate of pi by
generating random points in the unit box, and counting how many
of them fall in the unit circle.

\begin{code}
import Control.Monad( liftM2 )
import Control.Monad.MC( STMC, evalMC, foldMC, mt19937, uniform )
import Data.Monoid( (<>), mempty )
import qualified Data.Summary.Bool as S
import Text.Printf( printf )
\end{code}

First, we need a function to test whether or not a point is in the
unit circle.  We define

\begin{code}
inUnitCircle :: (Double,Double) -> Bool
inUnitCircle (x,y) = x*x + y*y <= 1
\end{code}

Next, we need to generate a random point in the unit box.  In the
Control.Monad.MC module, there is a function for generating uniform
values in an interval, called "uniform".  This function has a
funny-looking type, but you can think of it as:

    uniform :: Double -> Double -> STMC s Double

This type means that the function takes the two endpoints of the
interval as arguments, and returns a Monte-Carlo action which produces
a Double.

You can think of the type "STMC s Double" as a random number generator.
For general types, "STMC s a" is a generator for values of type "a".

The following code generates an x value in the range (-1,1), then a y
value in the range (-1,1), then returns the pair (x,y):

\begin{code}
unitBox :: STMC s (Double,Double)
unitBox = liftM2 (,) (uniform (-1) 1)
                     (uniform (-1) 1)
\end{code}

-- | Compute a Monte Carlo estimate of pi based on @n@ samples.  Return
-- the sample mean and standard error.

\begin{code}
estimatePi :: Int -> STMC s (Double,Double)
estimatePi n = let
    circ = fmap inUnitCircle unitBox
    mc   = foldMC (\s x -> return $! S.insert x s) S.empty n circ
    in fmap (\s -> let (mu,se) = (S.mean s, S.meanSE s)
                   in (4*mu,4*se)) mc
\end{code}

\begin{code}
main =
    let seed    = 0
        n       = 1000000 
        (mu,se) = estimatePi n `evalMC` mt19937 seed
        (l,u)   = (mu - 2.576 * se, mu + 2.576 * se)
    in do
        printf "\nEstimate: %g" mu
        printf "\n99%% Confidence Interval: (%g, %g)" l u
        printf "\n"
\end{code}