File: hssmc.m

package info (click to toggle)
dynare 6.4-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 67,648 kB
  • sloc: cpp: 79,109; ansic: 28,917; objc: 12,430; yacc: 4,528; pascal: 1,993; lex: 1,441; sh: 1,129; python: 634; makefile: 626; lisp: 163; xml: 18
file content (138 lines) | stat: -rw-r--r-- 6,313 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
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);
    %delete old stale files before creating new ones
    delete_stale_file(sprintf('%s%sparticles-*.mat', SimulationFolder,filesep))

    % 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)

    for 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