dynare/matlab/estimation/smc/hssmc.m

137 lines
6.0 KiB
Matlab
Raw Normal View History

2023-04-10 20:59:05 +02:00
function mdd = hssmc(TargetFun, mh_bounds, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, oo_)
% Sequential Monte-Carlo sampler, Herbst and Schorfheide (JAE, 2014).
%
% INPUTS
% - TargetFun [char] string specifying the name of the objective function (posterior kernel).
% - xparam1 [double] p×1 vector of parameters to be estimated (initial values).
% - mh_bounds [double] p×2 matrix defining lower and upper bounds for the parameters.
% - dataset_ [dseries] sample
% - dataset_info [struct] informations about the dataset
% - options_ [struct] dynare's options
% - M_ [struct] model description
% - estim_params_ [struct] estimated parameters
% - bayestopt_ [struct] estimated parameters
% - oo_ [struct] outputs
%
% SPECIAL REQUIREMENTS
% None.
% Copyright © 2022-2023 Dynare Team
%
% This file is part of Dynare.
%
% Dynare is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% Dynare is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with Dynare. If not, see <https://www.gnu.org/licenses/>.
smcopt = options_.posterior_sampler_options.current_options;
% Set location for the simulated particles.
SimulationFolder = CheckPath('hssmc', M_.dname);
% Define prior distribution
Prior = dprior(bayestopt_, options_.prior_trunc);
% Set function handle for the objective
eval(sprintf('%s = @(x) %s(x, dataset_, dataset_info, options_, M_, estim_params_, bayestopt_, mh_bounds, oo_.dr , oo_.steady_state, oo_.exo_steady_state, oo_.exo_det_steady_state, []);', 'funobj', func2str(TargetFun)));
mlogit = @(x) .95 + .1/(1 + exp(-16*x)); % Update of the scale parameter
% Create the tempering schedule
phi = ((0:smcopt.steps-1)/(smcopt.steps-1)).^smcopt.lambda;
% Initialise the estimate of the marginal density of the data
mdd = .0;
% tuning for MH algorithms matrices
scl = zeros(smcopt.steps, 1); % scale parameter
ESS = zeros(smcopt.steps, 1); % ESS
acpt = zeros(smcopt.steps, 1); % average acceptance rate
% Initialization of the sampler (draws from the prior distribution with finite logged likelihood)
t0 = tic;
[particles, tlogpostkernel, loglikelihood] = ...
smc_samplers_initialization(funobj, 'hssmc', smcopt.particles, Prior, SimulationFolder, smcopt.steps);
tt = toc(t0);
dprintf('#Iter. lambda ESS Acceptance rate scale resample seconds')
dprintf('%3u %5.4f %9.5E %5.4f %4.3f %3s %5.2f', 1, 0, 0, 0, 0, 'no', tt)
weights = ones(smcopt.particles, 1)/smcopt.particles;
resampled_particle_swarm = false;
for i=2:smcopt.steps % Loop over the weight on the liklihood (phi)
weights = weights.*exp((phi(i)-phi(i-1))*loglikelihood);
sweight = sum(weights);
weights = weights/sweight;
mdd = mdd + log(sweight);
ESS(i) = 1.0/sum(weights.^2);
if (2*ESS(i) < smcopt.particles) % Resampling
resampled_particle_swarm = true;
iresample = kitagawa(weights);
particles = particles(:,iresample);
loglikelihood = loglikelihood(iresample);
tlogpostkernel = tlogpostkernel(iresample);
weights = ones(smcopt.particles, 1)/smcopt.particles;
end
smcopt.scale = smcopt.scale*mlogit(smcopt.acpt-smcopt.target); % Adjust the scale parameter
scl(i) = smcopt.scale; % Scale parameter (for the jumping distribution in MH mutation step).
mu = particles*weights; % Weighted average of the particles.
z = particles-mu;
R = z*(z'.*weights); % Weighted covariance matrix of the particles.
t0 = tic;
acpt_ = false(smcopt.particles, 1);
tlogpostkernel = tlogpostkernel + (phi(i)-phi(i-1))*loglikelihood;
[acpt_, particles, loglikelihood, tlogpostkernel] = ...
randomwalk(funobj, chol(R, 'lower'), mu, scl(i), phi(i), acpt_, Prior, particles, loglikelihood, tlogpostkernel);
smcopt.acpt = sum(acpt_)/smcopt.particles; % Acceptance rate.
tt = toc(t0);
acpt(i) = smcopt.acpt;
if resampled_particle_swarm
dprintf('%3u %5.4f %9.5E %5.4f %4.3f %3s %5.2f', i, phi(i), ESS(i), acpt(i), scl(i), 'yes', tt)
else
dprintf('%3u %5.4f %9.5E %5.4f %4.3f %3s %5.2f', i, phi(i), ESS(i), acpt(i), scl(i), 'no', tt)
end
if i==smcopt.steps
iresample = kitagawa(weights);
particles = particles(:,iresample);
end
save(sprintf('%s%sparticles-%u-%u.mat', SimulationFolder, filesep(), i, smcopt.steps), 'particles', 'tlogpostkernel', 'loglikelihood')
resampled_particle_swarm = false;
end
end
function [accept, particles, loglikelihood, tlogpostkernel] = randomwalk(funobj, RR, mu, scale, phi, accept, Prior, particles, loglikelihood, tlogpostkernel)
parfor j=1:size(particles, 2)
notvalid= true;
while notvalid
candidate = particles(:,j) + scale*(RR*randn(size(mu)));
if Prior.admissible(candidate)
[tlogpost, loglik] = tempered_likelihood(funobj, candidate, phi, Prior);
if isfinite(loglik)
notvalid = false;
if rand<exp(tlogpost-tlogpostkernel(j))
accept(j) = true ;
particles(:,j) = candidate;
loglikelihood(j) = loglik;
tlogpostkernel(j) = tlogpost;
end
end
end
end
end
end