Monte Carlo Methods#
Monte carlo methods are a class of methods that use randomness to make it easier to solve deterministic problems. Specifally, we wish to compute integrals of the form
$
The idea of Monte-Carlo, is to observe that, if
A classical example of this, is to compute the area of the unit circle (
import numpy as np
import matplotlib.pyplot as plt
import scipy
n = 1000;
xs = 2*np.random.rand(2,n)-1
plt.scatter(xs[0,:],xs[1,:])
ids = np.linalg.norm(xs,axis=0)<1
plt.scatter(xs[0,ids],xs[1,ids])
fn = 4*sum(ids)/n
'estimate = {}'.format(fn)
'error = {}'.format(fn-np.pi)
'error = -0.013592653589793002'

Let’s look at how this converges with
ns = np.int32(np.logspace(0,6,100))
errs = []
for n in ns:
xs = 2*np.random.rand(2,n)-1
ids = np.linalg.norm(xs,axis=0)<1
errs.append((4*sum(ids)/n)-np.pi)
plt.loglog(ns,np.abs(errs),'o-')
plt.loglog(ns,1/np.sqrt(ns),'-')
plt.xlabel('n')
plt.ylabel('Error')
plt.show()

Let’s look at why the error is decaying like
If we take square root
$
This one over square root
Suppose we are trying to compute an integral in
Importance sampling#
Suppose we want to compute the integral of a highly concentrated function
$
f = lambda x: np.exp(-1e4*x*x)
xs = np.linspace(-1,1,1000)
plt.plot(xs,f(xs))
plt.show()
true_int = np.sqrt(np.pi)/100
ns = np.int32(np.logspace(0,5,20))
ntrial = 10
errs = []
for n in ns:
errs_samp = np.zeros(ntrial)
for k in range(ntrial):
xs = 2*np.random.rand(1,n)-1
errs_samp[k] = ((2*np.sum(f(xs))/n)-true_int)/true_int
errs.append(np.mean(errs_samp))
plt.loglog(ns,np.abs(errs),'o-')
plt.loglog(ns,1/np.sqrt(ns),'-')
plt.xlabel('n')
plt.ylabel('Relative error')
plt.show()


We can increase the accuracy, we should use Monte Carlo samples where
We shall choose
for sigma in [1e-2,1e-1, 1]:
p = lambda x: np.exp(-x*x/2/sigma/sigma)/np.sqrt(2*np.pi*sigma**2)
errs_import = []
for n in ns:
errs_samp = np.zeros(ntrial)
for k in range(ntrial):
xs = sigma * np.random.randn(1,n)
est = np.sum(f(xs)/p(xs)) / n
errs_samp[k] = (est-true_int)/true_int
errs_import.append(np.mean(errs_samp))
plt.loglog(ns,np.abs(errs_import),'o-',label='sigma={}'.format(sigma))
plt.loglog(ns,np.abs(errs),'*--',label='uniform')
plt.loglog(ns,1/np.sqrt(ns),':')
plt.xlabel('n')
plt.legend()
plt.ylabel('Relative error')
plt.show()

We see that concentrating the samples at the peak of the function significantly decreases the error. This method is called “importance sampling”.
Markov Chain Monte Carlo (MCMC)#
Sometimes we wish to compute
$
Our task is therefore to design a Markov chain whose stationary distribution is
Metropolis-Hastings#
We shall generate a sample
Then we set
You can check that the stationary probability is
Note that we don’t need the value of
Let’s use this to compute
$
Note that the samples are no longer independent. The covariance between samples will lower the effective number of samples, but the estimator will still converge.
def MC_step(x,p):
delta = 0.1
y = x + delta*np.random.randn()
prob = min(p(y)/p(x),1)
if np.random.rand() < prob:
x = y
return x
V = lambda x: x**4-x**2
p = lambda x: np.exp(-V(x))
nburn_in = 1000
x = 0
for i in range(nburn_in):
x = MC_step(x,p)
nsample = 10000
xs = [x]
for i in range(nsample):
x = MC_step(x,p)
xs.append(x)
xs = np.array(xs)
sum(xs*xs)/nsample
plt.hist(xs,bins=50)
plt.show()

xx = np.linspace(-1.5,1.5,200)
plt.plot(xx,p(xx),'.')
kde = scipy.stats.gaussian_kde(xs)
plt.plot(xx,kde(xx))
[<matplotlib.lines.Line2D at 0x7f338761cf50>]

Such examples occur in statistical physics.
Cell In[8], line 1
Such examples occur in statistical physics.
^
SyntaxError: invalid syntax