import numpy as np
import scipy.stats as st
import matplotlib.pyplot as plt
def f_0(x):
"""
Target distribution: \propto N(-5, 2)
"""
return np.exp(-(x+5)**2/2/2)
def f_j(x, beta):
"""
Intermediate distribution: interpolation between f_0 and f_n
"""
return f_0(x)**beta * f_n(x)**(1-beta)
p_n = st.norm(0, 1)
def T(x, f, n_steps=10):
"""
Transition distribution: T(x'|x) using n-steps Metropolis sampler
"""
for t in range(n_steps):
x_prime = x + np.random.randn()
a = f(x_prime) / f(x)
if np.random.rand() < a:
x = x_prime
return x
x = np.arange(-10, 5, 0.1)
n_inter = 50
betas = np.linspace(0, 1, n_inter)
n_samples = 100
samples = np.zeros(n_samples)
weights = np.zeros(n_samples)
for t in range(n_samples):
x = p_n.rvs()
w = 1
for n in range(1, len(betas)):
x = T(x, lambda x: f_j(x, betas[n]), n_steps=5)
w += np.log(f_j(x, betas[n])) - np.log(f_j(x, betas[n-1]))
samples[t] = x
weights[t] = np.exp(w)
a = 1/np.sum(weights) * np.sum(weights * samples)