Table of Contents

Monte Carlo Methods

Tasks

Introduction - The goal of this assignment is to better understand the concepts taught in class, such as Monte Carlo methods and Monte-Carlo integration.

Using a random-number generator

The goal of this problem is to familiarize yourself with the use of a random number generator and routines to automatically seed the generator. As described in class we will rely on the facilities provided by the C++ standard library to generate random numbers and seeding the generator.

In the provided file random_numbers.cpp, write a program that generates an increasing number of uniformly distributed random numbers in the interval \([0, 1]\) and compute the averages of those. A maximum of \(10^N\) with \(N_{\max}=6\) should be enough. Use the C++ random number generator type std::mt19937 and seed it using the an instance of std::random_device. You can use the type std::uniform_real_distribution to generated the desired statistic distribution.

The exact value for the average should be close to the value of 0.5, you can stop generating random numbers once the average becomes close to the expected value. Study how the average changes when N is increased.

Generate a plot using the facilities provided in matplotlibcpp.h that shows the average of the generated numbers for an increasing \(N\). Save the generated plot as results/random_number.png and commit the generated plot as part of your overall submission.

The generated seed for the random number generator is different for each invocation. Therefore, every time you run the code, it should produce a (slightly) different output.

Estimating \(\pi\) using simple-sampling Monte Carlo

The goal of this problem is to illustrate how \(\pi = 3.1415...\) can be computed by random sampling of the unit disk. Starting from the code presented in class, write a program that calculates \(\pi\). Use the file estimate_pi.cpp for your work.

In your simulation run the code multiple times for \(N=10^{i}, i = 1, 2, 3, \cdots\) random numbers. See how the estimate for \(\pi\) improves with increasing N and compute the deviation from the exact result: \(error = \lvert \pi - \pi_{estimate} \rvert\).

Perform a log-log plot (using plt::loglog) of the error as a function of \(N\) and show that the data can be fit to a straight line of slope \(\frac {-1}{2}\).

Save the generated plot as results/estimate_pi.png and commit the generated plot as part of your overall submission.

A Random Walk in the Plane

Code a random walk in the plane where, in addition to a random angle, the step size is variable and follows an exponential distribution. I.e.,

\[P(s) = e^{-s}\]

where \(s\) is the step size to be specified on the command line and

\[P(\theta) = \frac{1}{2\pi}\]

where \(\theta\) is the angle. Use the file random_walk.cpp for your work.

Make a distribution of the distance from the origin by making a histogram and summing the weights in the bins after \(10^5\) steps. Select a reasonable bin-size to be able to plot a smooth distribution curve. You can use the class histogram that is implemented in the file histogram.hpp for generating it.

You will need to generate many random walks each of which takes \(10^5\) steps, extract the distance of the respective endpoint from the origin for each, and plot the resulting distribution that you collected using the histogram class. Study the implementation in histogram.hpp to see how to use the type for your purposes.

You can use the C++ type std::exponential_distribution from the standard library to generate the desired distribution of the generated random step sizes. Use the type std::uniform_real_distribution to generate the next random angle.

Start your random walk at the coordinate origin \([0.0, 0.0]\) and calculate the distance of the endpoint for each walk relative to it.

Experiment with different step sizes \(s\) and plot the distributions for those. Explain your results. Save the generated plot as results/random_walk.png and commit the generated plot as part of your overall submission.

Simple-sampling Monte Carlo estimate of the integral \(f(x) = x^n\)

The goal of the exercise is to apply the concepts learned in the previous problem and apply these to the real function \(f(x) = x^n\) where the integral is known analytically, namely

\[I[f(x)] =\int f(x) dx = \frac{1}{(n+1)}\]

in the interval \([0, 1]\). For now, set \(n = 3\), you can change the value of the exponent \(n\) later. Start from the following pseudo-code:

algorithm simple_integrate
    initialize integral 0
    initialize num_trials 10000
    initialize counter 0
    while(counter < num_trials) do
        x = rand(0, 1)
        integral += x**n
        ++counter
    done
    return integral / num_trials

As in the previous tasks, run the code multiple times for \(N=10^i\), \(i=1,2,3, ...\) random numbers. See how the estimate for \(I[f(x)]\) in the interval \([0, 1]\) improves with increasing \(N\) and compute and plot the deviation from the exact result:

\[error = \lvert I - I_{estimate} \rvert\]

Again, the error should scale \(~N^{\frac {-1}{2}}\).

Use the file simple_integral.cpp for your work. Submit your plot as results/simple_integral.png

Bonus: Probability of two or more People having the same Birthday

This part is optional and is worth 5 points of extra credit on this assignment.

Please keep in mind that the value of the extra credit may not be proportionate to the time it takes to complete it.

Find out the probability that, out of a group of thirty people, at least two people share a birthday. Implement your code in the file birthdays.cpp.

  • If you like, analytically derive the exact answer (which is ~70.55094192102…%, assume 365 days/year)
  • Use the Monte-Carlo method to estimate this probability.
  • Show that with increasing number of attempts, the estimation error is reduced, create a plot showing the relative estimation error for varying numbers of attempts.
  • Submit your plot as results/birthdays.png
  • How many attempts did you need to get an estimate that has a relative error of less than 0.0001?