Source code for pints._mcmc._rao_blackwell_ac

#
# Rao-Blackwell Adaptive MCMC method
#
# This file is part of PINTS (https://github.com/pints-team/pints/) which is
# released under the BSD 3-clause license. See accompanying LICENSE.md for
# copyright notice and full license details.
#
import pints
import numpy as np


[docs] class RaoBlackwellACMC(pints.AdaptiveCovarianceMC): """ Rao-Blackwell adaptive MCMC, as described by Algorithm 3 in [1]_. After initialising mu0 and sigma0, in each iteration after initial phase (t), the following steps occur:: theta* ~ N(theta_t, lambda * sigma0) alpha(theta_t, theta*) = min(1, p(theta*|data) / p(theta_t|data)) u ~ uniform(0, 1) if alpha(theta_t, theta*) > u: theta_t+1 = theta* else: theta_t+1 = theta_t mu_t+1 = mu_t + gamma_t+1 * (theta_t+1 - mu_t) sigma_t+1 = sigma_t + gamma_t+1 * (bar((theta_t+1 - mu_t)(theta_t+1 - mu_t)') - sigma_t) where:: bar(theta_t+1) = alpha(theta_t, theta*) theta* + (1 - alpha(theta_t, theta*)) theta_t Note that we deviate from the paper in two places:: gamma_t = t^-eta Y_t+1 ~ N(theta_t, lambda * sigma0) rather than Y_t+1 ~ N(theta_t, sigma0) Extends :class:`AdaptiveCovarianceMC`. References ---------- .. [1] A tutorial on adaptive MCMC Christophe Andrieu and Johannes Thoms, Statistical Computing, 2008, 18: 343-373. https://doi.org/10.1007/s11222-008-9110-y """ def __init__(self, x0, sigma0=None): super(RaoBlackwellACMC, self).__init__(x0, sigma0) # heuristic based on normal approximation self._lambda = (2.38**2) / self._n_parameters self._X = None self._Y = None def _adapt_sigma(self, log_ratio): """ Updates sigma using Rao-Blackwellised formula:: sigma_t+1 = sigma_t + gamma_t+1 * (bar((theta_t+1 - mu_t)(theta_t+1 - mu_t)') - sigma_t) where:: bar(X_t+1) = alpha(X_t, Y_t+1) * Y_t+1 + (1 - alpha(X_t, Y_t+1)) * X_t """ acceptance_prob = np.exp(log_ratio) if log_ratio < 0 else 1 X_bar = acceptance_prob * self._Y + (1 - acceptance_prob) * self._X dsigm = np.reshape(X_bar - self._mu, (self._n_parameters, 1)) self._sigma = ((1 - self._gamma) * self._sigma + self._gamma * np.dot(dsigm, dsigm.T)) def _generate_proposal(self): """ See :meth:`AdaptiveCovarianceMC._generate_proposal()`. """ return np.random.multivariate_normal( self._current, self._lambda * self._sigma)
[docs] def name(self): """ See :meth:`pints.MCMCSampler.name()`. """ return 'Rao-Blackwell adaptive covariance MCMC'
[docs] def tell(self, fx): """ See :meth:`pints.AdaptiveCovarianceMC.tell()`. """ self._Y = np.copy(self._proposed) self._X = np.copy(self._current) return super(RaoBlackwellACMC, self).tell(fx)