dynare/matlab/get_perturbation_params_der...

1537 lines
103 KiB
Matlab

function DERIVS = get_perturbation_params_derivs(M, options, estim_params, oo, indpmodel, indpstderr, indpcorr, d2flag)
% DERIVS = get_perturbation_params_derivs(M, options, estim_params, oo, indpmodel, indpstderr, indpcorr, d2flag)
% previously getH.m in dynare 4.5
% -------------------------------------------------------------------------
% Computes derivatives (with respect to parameters) of
% (1) steady-state (oo_.dr.ys) and covariance matrix of shocks (M_.Sigma_e)
% (2) dynamic model (g1, g2, g3)
% (3) perturbation solution matrices up to third order oo_.dr.(ghx,ghu,ghxx,ghxu,ghuu,ghs2,ghxxx,ghxxu,ghxuu,ghuuu,ghxss,ghuss)
% Note that the order in the parameter Jacobians is the following:
% first stderr parameters, second corr parameters, third model parameters
%
% =========================================================================
% INPUTS
% M: [structure] storing the model information
% options: [structure] storing the options
% estim_params: [structure] storing the estimation information
% oo: [structure] storing the solution results
% indpmodel: [modparam_nbr by 1] index of estimated parameters in M.params;
% corresponds to model parameters (no stderr and no corr) in estimated_params block
% indpstderr: [stderrparam_nbr by 1] index of estimated standard errors,
% i.e. for all exogenous variables where "stderr" is given in the estimated_params block
% indpcorr: [corrparam_nbr by 2] matrix of estimated correlations,
% i.e. for all exogenous variables where "corr" is given in the estimated_params block
% d2flag: [boolean] flag to compute second-order parameter derivatives of steady state and first-order Kalman transition matrices
% -------------------------------------------------------------------------
% OUTPUTS
% DERIVS: Structure with the following fields:
% dYss: [endo_nbr by modparam_nbr] in DR order
% Jacobian (wrt model parameters only) of steady state oo_.dr.ys(oo_.dr.order_var,:)
% dSigma_e: [exo_nbr by exo_nbr by totparam_nbr] in declaration order
% Jacobian (wrt to all paramters) of covariance matrix of shocks M.Sigma_e
% dg1: [endo_nbr by yy0ex0_nbr by modparam_nbr] in DR order
% Parameter Jacobian of first derivative (wrt dynamic model variables) of dynamic model (wrt to model parameters only)
% dg2: [endo_nbr by yy0ex0_nbr^2*modparam_nbr] in DR order
% Parameter Jacobian of second derivative (wrt dynamic model variables) of dynamic model (wrt to model parameters only)
% Note that instead of tensors we use matrix notation with blocks: dg2 = [dg2_dp1 dg2_dp2 ...],
% where dg2_dpj is [endo_nbr by yy0ex0_nbr^2] and represents the derivative of g2 wrt parameter pj
% dg3: [endo_nbr by yy0ex0_nbr^3*modparam_nbr] in DR order
% Parameter Jacobian of third derivative (wrt dynamic model variables) of dynamic model (wrt to model parameters only)
% Note that instead of tensors we use matrix notation with blocks: dg3 = [dg3_dp1 dg3_dp2 ...],
% where dg3_dpj is [endo_nbr by yy0ex0_nbr^3] and represents the derivative of g3 wrt parameter pj
% dghx: [endo_nbr by states_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of first-order perturbation solution matrix oo_.dr.ghx
% dghu: [endo_nbr by exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of first-order perturbation solution matrix oo_.dr.ghu
% dOm: [endo_nbr by endo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all paramters) of Om = oo_.dr.ghu*M.Sigma_e*transpose(oo_.dr.ghu)
% dghxx [endo_nbr by states_nbr*states_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of second-order perturbation solution matrix oo_.dr.ghxx
% dghxu [endo_nbr by states_nbr*exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of second-order perturbation solution matrix oo_.dr.ghxu
% dghuu [endo_nbr by exo_nbr*exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of second-order perturbation solution matrix oo_.dr.ghuu
% dghs2 [endo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of second-order perturbation solution matrix oo_.dr.ghs2
% dghxxx [endo_nbr by states_nbr*states_nbr*states_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghxxx
% dghxxu [endo_nbr by states_nbr*states_nbr*exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghxxu
% dghxuu [endo_nbr by states_nbr*exo_nbr*exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghxuu
% dghuuu [endo_nbr by exo_nbr*exo_nbr*exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghuuu
% dghxss [endo_nbr by states_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghxss
% dghuss [endo_nbr by exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of third-order perturbation solution matrix oo_.dr.ghuss
% If d2flag==true, we additional output:
% d2KalmanA: [endo_nbr*endo_nbr by totparam_nbr*(totparam_nbr+1)/2] in DR order
% Unique entries of Hessian (wrt all parameters) of Kalman transition matrix A
% d2Om: [endo_nbr*(endo_nbr+1)/2 by totparam_nbr*(totparam_nbr+1)/2] in DR order
% Unique entries of Hessian (wrt all parameters) of Om=oo_.dr.ghu*M_.Sigma_e*transpose(oo_.dr.ghu)
% d2Yss: [endo_nbr by modparam_nbr by modparam_nbr] in DR order
% Unique entries of Hessian (wrt model parameters only) of steady state oo_.dr.ys(oo_.dr.order_var,:)
%
% -------------------------------------------------------------------------
% This function is called by
% * dsge_likelihood.m
% * get_identification_jacobians.m (previously getJJ.m in Dynare 4.5)
% -------------------------------------------------------------------------
% This function calls
% * [fname,'.dynamic']
% * [fname,'.dynamic_params_derivs']
% * [fname,'.static']
% * [fname,'.static_params_derivs']
% * commutation
% * dyn_vech
% * dyn_unvech
% * fjaco
% * get_2nd_deriv (embedded)
% * get_2nd_deriv_mat(embedded)
% * get_all_parameters
% * get_all_resid_2nd_derivs (embedded)
% * get_hess_deriv (embedded)
% * hessian_sparse
% * sylvester3
% * sylvester3a
% * get_perturbation_params_derivs_numerical_objective
% =========================================================================
% Copyright (C) 2019-2020 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 <http://www.gnu.org/licenses/>.
% =========================================================================
% Some checks
if M.exo_det_nbr > 0
error('''get_perturbation_params_derivs'': not compatible with deterministic exogenous variables, please declare as endogenous.')
end
if options.order > 1 && options.analytic_derivation_mode == 1
%analytic derivatives using Kronecker products is implemented only at first-order, at higher order we reset to analytic derivatives with sylvester equations
options.analytic_derivation_mode = 0; fprintf('As order > 1, set ''options.analytic_derivation_mode'' to 0\n');
end
% Get options from options structure
order = options.order;
threads_BC = options.threads.kronecker.sparse_hessian_times_B_kronecker_C;
qz_criterium = options.qz_criterium;
analytic_derivation_mode = options.analytic_derivation_mode;
% select method to compute Jacobians, default is 0
% * 0: efficient sylvester equation method to compute analytical derivatives as in Ratto & Iskrev (2012)
% * 1: kronecker products method to compute analytical derivatives as in Iskrev (2010), only for order=1
% * -1: numerical two-sided finite difference method to compute numerical derivatives of all output arguments using function get_perturbation_params_derivs_numerical_objective.m
% * -2: numerical two-sided finite difference method to compute numerically dYss, dg1, dg2, dg3, d2Yss and d2g1, the other output arguments are computed analytically as in kronflag=0
numerical_objective_fname = str2func('get_perturbation_params_derivs_numerical_objective');
idx_states = M.nstatic+(1:M.nspred); %index for state variables, in DR order
modparam_nbr = length(indpmodel); %number of selected model parameters
stderrparam_nbr = length(indpstderr); %number of selected stderr parameters
corrparam_nbr = size(indpcorr,1); %number of selected corr parameters
totparam_nbr = modparam_nbr + stderrparam_nbr + corrparam_nbr; %total number of selected parameters
[I,~] = find(M.lead_lag_incidence'); %I is used to select nonzero columns of the Jacobian of endogenous variables in dynamic model files
yy0_nbr = length(oo.dr.ys(I)); %number of dynamic variables
yy0ex0_nbr = yy0_nbr+M.exo_nbr; %number of dynamic variables + exogenous variables
kyy0 = nonzeros(M.lead_lag_incidence(:,oo.dr.order_var)'); %index for nonzero entries in dynamic files at t-1,t,t+1 in DR order
kyy0ex0 = [kyy0; length(kyy0)+(1:M.exo_nbr)']; %dynamic files include derivatives wrt exogenous variables, note that exo_det is always 0
k2yy0ex0 = transpose(reshape(1:yy0ex0_nbr^2,yy0ex0_nbr,yy0ex0_nbr)); %index for the second dynamic derivatives, i.e. to evaluate the derivative of f wrt to yy0ex0(i) and yy0ex0(j), in DR order
k3yy0ex0 = permute(reshape(transpose(reshape(1:yy0ex0_nbr^3,yy0ex0_nbr,yy0ex0_nbr^2)),yy0ex0_nbr,yy0ex0_nbr,yy0ex0_nbr),[2 1 3]); %index for the third dynamic derivative, i.e. df/(dyyex0_i*dyyex0_j*dyyex0_k)
% Check for purely backward or forward looking models
if size(M.lead_lag_incidence,1)<3
if M.nfwrd == 0 %purely backward models
klag = M.lead_lag_incidence(1,oo.dr.order_var); %indices of lagged (i.e. t-1) variables in dynamic files, columns are in DR order
kcurr = M.lead_lag_incidence(2,oo.dr.order_var); %indices of current (i.e. t) variables in dynamic files, columns are in DR order
klead = zeros(1,size(M.lead_lag_incidence,2)); %indices of lead (i.e. t+1) variables in dynamic files, columns are in DR order
elseif M.npred == 0 %purely forward models
klag = zeros(1,size(M.lead_lag_incidence,2)); %indices of lagged (i.e. t-1) variables in dynamic files, columns are in DR order
kcurr = M.lead_lag_incidence(1,oo.dr.order_var); %indices of current (i.e. t) variables in dynamic files, columns are in DR order
klead = M.lead_lag_incidence(2,oo.dr.order_var); %indices of lead (i.e. t+1) variables in dynamic files, columns are in DR order
end
else %normal models
klag = M.lead_lag_incidence(1,oo.dr.order_var); %indices of lagged (i.e. t-1) variables in dynamic files, columns are in DR order
kcurr = M.lead_lag_incidence(2,oo.dr.order_var); %indices of current (i.e. t) variables in dynamic files, columns are in DR order
klead = M.lead_lag_incidence(3,oo.dr.order_var); %indices of lead (i.e. t+1) variables in dynamic files, columns are in DR order
end
if analytic_derivation_mode < 0
%Create auxiliary estim_params blocks if not available for numerical derivatives, estim_params_model contains only model parameters
estim_params_model.np = length(indpmodel);
estim_params_model.param_vals(:,1) = indpmodel;
estim_params_model.nvx = 0; estim_params_model.ncx = 0; estim_params_model.nvn = 0; estim_params_model.ncn = 0;
modparam1 = get_all_parameters(estim_params_model, M); %get all selected model parameters
if ~isempty(indpstderr) && isempty(estim_params.var_exo) %if there are stderr parameters but no estimated_params_block
%provide temporary necessary information for stderr parameters
estim_params.nvx = length(indpstderr);
estim_params.var_exo(:,1) = indpstderr;
end
if ~isempty(indpcorr) && isempty(estim_params.corrx) %if there are corr parameters but no estimated_params_block
%provide temporary necessary information for stderr parameters
estim_params.ncx = size(indpcorr,1);
estim_params.corrx(:,1:2) = indpcorr;
end
if ~isfield(estim_params,'nvn') %stderr of measurement errors not yet
estim_params.nvn = 0;
estim_params.var_endo = [];
end
if ~isfield(estim_params,'ncn') %corr of measurement errors not yet
estim_params.ncn = 0;
estim_params.corrn = [];
end
if ~isempty(indpmodel) && isempty(estim_params.param_vals) %if there are model parameters but no estimated_params_block
%provide temporary necessary information for model parameters
estim_params.np = length(indpmodel);
estim_params.param_vals(:,1) = indpmodel;
end
xparam1 = get_all_parameters(estim_params, M); %get all selected stderr, corr, and model parameters in estimated_params block, stderr and corr come first, then model parameters
end
if d2flag
modparam_nbr2 = modparam_nbr*(modparam_nbr+1)/2; %number of unique entries of selected model parameters only in second-order derivative matrix
totparam_nbr2 = totparam_nbr*(totparam_nbr+1)/2; %number of unique entries of all selected parameters in second-order derivative matrix
%get indices of elements in second derivatives of parameters
indp2tottot = reshape(1:totparam_nbr^2,totparam_nbr,totparam_nbr);
indp2stderrstderr = indp2tottot(1:stderrparam_nbr , 1:stderrparam_nbr);
indp2stderrcorr = indp2tottot(1:stderrparam_nbr , stderrparam_nbr+1:stderrparam_nbr+corrparam_nbr);
indp2modmod = indp2tottot(stderrparam_nbr+corrparam_nbr+1:stderrparam_nbr+corrparam_nbr+modparam_nbr , stderrparam_nbr+corrparam_nbr+1:stderrparam_nbr+corrparam_nbr+modparam_nbr);
if totparam_nbr ~=1
indp2tottot2 = dyn_vech(indp2tottot); %index of unique second-order derivatives
else
indp2tottot2 = indp2tottot;
end
if modparam_nbr ~= 1
indp2modmod2 = dyn_vech(indp2modmod); %get rid of cross derivatives
else
indp2modmod2 = indp2modmod;
end
%Kalman transition matrices, as in kalman_transition_matrix.m
KalmanA = zeros(M.endo_nbr,M.endo_nbr);
KalmanA(:,idx_states) = oo.dr.ghx;
KalmanB = oo.dr.ghu;
end
if analytic_derivation_mode == -1
%% numerical two-sided finite difference method using function get_perturbation_params_derivs_numerical_objective.m (previously thet2tau.m in Dynare 4.5) for
% Jacobian (wrt selected stderr, corr and model parameters) of
% - dynamic model derivatives: dg1, dg2, dg3
% - steady state: dYss
% - covariance matrix of shocks: dSigma_e
% - perturbation solution matrices: dghx, dghu, dghxx, dghxu, dghuu, dghs2, dghxxx, dghxxu, dghxuu, dghuuu, dghxss, dghuss
%Parameter Jacobian of covariance matrix and solution matrices (wrt selected stderr, corr and model paramters)
dSig_gh = fjaco(numerical_objective_fname, xparam1, 'perturbation_solution', estim_params, M, oo, options);
ind_Sigma_e = (1:M.exo_nbr^2);
ind_ghx = ind_Sigma_e(end) + (1:M.endo_nbr*M.nspred);
ind_ghu = ind_ghx(end) + (1:M.endo_nbr*M.exo_nbr);
DERIVS.dSigma_e = reshape(dSig_gh(ind_Sigma_e,:),[M.exo_nbr M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghx = reshape(dSig_gh(ind_ghx,:),[M.endo_nbr M.nspred totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghu = reshape(dSig_gh(ind_ghu,:),[M.endo_nbr M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
if order > 1
ind_ghxx = ind_ghu(end) + (1:M.endo_nbr*M.nspred^2);
ind_ghxu = ind_ghxx(end) + (1:M.endo_nbr*M.nspred*M.exo_nbr);
ind_ghuu = ind_ghxu(end) + (1:M.endo_nbr*M.exo_nbr*M.exo_nbr);
ind_ghs2 = ind_ghuu(end) + (1:M.endo_nbr);
DERIVS.dghxx = reshape(dSig_gh(ind_ghxx,:), [M.endo_nbr M.nspred^2 totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghxu = reshape(dSig_gh(ind_ghxu,:), [M.endo_nbr M.nspred*M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghuu = reshape(dSig_gh(ind_ghuu,:), [M.endo_nbr M.exo_nbr*M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghs2 = reshape(dSig_gh(ind_ghs2,:), [M.endo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
end
if order > 2
ind_ghxxx = ind_ghs2(end) + (1:M.endo_nbr*M.nspred^3);
ind_ghxxu = ind_ghxxx(end) + (1:M.endo_nbr*M.nspred^2*M.exo_nbr);
ind_ghxuu = ind_ghxxu(end) + (1:M.endo_nbr*M.nspred*M.exo_nbr^2);
ind_ghuuu = ind_ghxuu(end) + (1:M.endo_nbr*M.exo_nbr^3);
ind_ghxss = ind_ghuuu(end) + (1:M.endo_nbr*M.nspred);
ind_ghuss = ind_ghxss(end) + (1:M.endo_nbr*M.exo_nbr);
DERIVS.dghxxx = reshape(dSig_gh(ind_ghxxx,:), [M.endo_nbr M.nspred^3 totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghxxu = reshape(dSig_gh(ind_ghxxu,:), [M.endo_nbr M.nspred^2*M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghxuu = reshape(dSig_gh(ind_ghxuu,:), [M.endo_nbr M.nspred*M.exo_nbr^2 totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghuuu = reshape(dSig_gh(ind_ghuuu,:), [M.endo_nbr M.exo_nbr^3 totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghxss = reshape(dSig_gh(ind_ghxss,:), [M.endo_nbr M.nspred totparam_nbr]); %in tensor notation, wrt selected parameters
DERIVS.dghuss = reshape(dSig_gh(ind_ghuss,:), [M.endo_nbr M.exo_nbr totparam_nbr]); %in tensor notation, wrt selected parameters
end
% Parameter Jacobian of Om=ghu*Sigma_e*ghu' and Correlation_matrix (wrt selected stderr, corr and model paramters)
DERIVS.dOm = zeros(M.endo_nbr,M.endo_nbr,totparam_nbr); %initialize in tensor notation
DERIVS.dCorrelation_matrix = zeros(M.exo_nbr,M.exo_nbr,totparam_nbr); %initialize
if ~isempty(indpstderr) %derivatives of ghu wrt stderr parameters are zero by construction
for jp=1:stderrparam_nbr
DERIVS.dOm(:,:,jp) = oo.dr.ghu*DERIVS.dSigma_e(:,:,jp)*oo.dr.ghu';
end
end
if ~isempty(indpcorr) %derivatives of ghu wrt corr parameters are zero by construction
for jp=1:corrparam_nbr
DERIVS.dOm(:,:,stderrparam_nbr+jp) = oo.dr.ghu*DERIVS.dSigma_e(:,:,stderrparam_nbr+jp)*oo.dr.ghu';
DERIVS.dCorrelation_matrix(indpcorr(jp,1),indpcorr(jp,2),stderrparam_nbr+jp) = 1;
DERIVS.dCorrelation_matrix(indpcorr(jp,2),indpcorr(jp,1),stderrparam_nbr+jp) = 1;%symmetry
end
end
if ~isempty(indpmodel) %derivatives of Sigma_e wrt model parameters are zero by construction
for jp=1:modparam_nbr
DERIVS.dOm(:,:,stderrparam_nbr+corrparam_nbr+jp) = DERIVS.dghu(:,:,stderrparam_nbr+corrparam_nbr+jp)*M.Sigma_e*oo.dr.ghu' + oo.dr.ghu*M.Sigma_e*DERIVS.dghu(:,:,stderrparam_nbr+corrparam_nbr+jp)';
end
end
%Parameter Jacobian of dynamic model derivatives (wrt selected model parameters only)
dYss_g = fjaco(numerical_objective_fname, modparam1, 'dynamic_model', estim_params_model, M, oo, options);
ind_Yss = 1:M.endo_nbr;
ind_g1 = ind_Yss(end) + (1:M.endo_nbr*yy0ex0_nbr);
DERIVS.dYss = dYss_g(ind_Yss, :); %in tensor notation, wrt selected model parameters only
DERIVS.dg1 = reshape(dYss_g(ind_g1,:),[M.endo_nbr, yy0ex0_nbr, modparam_nbr]); %in tensor notation
if order > 1
ind_g2 = ind_g1(end) + (1:M.endo_nbr*yy0ex0_nbr^2);
DERIVS.dg2 = reshape(sparse(dYss_g(ind_g2,:)),[M.endo_nbr, yy0ex0_nbr^2*modparam_nbr]); %blockwise in matrix notation, i.e. [dg2_dp1 dg2_dp2 ...], where dg2_dpj has dimension M.endo_nbr by yy0ex0_nbr^2
end
if order > 2
ind_g3 = ind_g2(end) + (1:M.endo_nbr*yy0ex0_nbr^3);
DERIVS.dg3 = reshape(sparse(dYss_g(ind_g3,:)),[M.endo_nbr, yy0ex0_nbr^3*modparam_nbr]); %blockwise in matrix notation, i.e. [dg3_dp1 dg3_dp2 ...], where dg3_dpj has dimension M.endo_nbr by yy0ex0_nbr^3
end
if d2flag
% Hessian (wrt paramters) of steady state and first-order solution matrices ghx and Om
% note that hessian_sparse.m (contrary to hessian.m) does not take symmetry into account, but focuses already on unique values
options.order = 1; %make sure only first order
d2Yss_KalmanA_Om = hessian_sparse(numerical_objective_fname, xparam1, options.gstep, 'Kalman_Transition', estim_params, M, oo, options);
options.order = order; %make sure to set back
ind_KalmanA = ind_Yss(end) + (1:M.endo_nbr^2);
DERIVS.d2KalmanA = d2Yss_KalmanA_Om(ind_KalmanA, indp2tottot2); %only unique elements
DERIVS.d2Om = d2Yss_KalmanA_Om(ind_KalmanA(end)+1:end , indp2tottot2); %only unique elements
DERIVS.d2Yss = zeros(M.endo_nbr,modparam_nbr,modparam_nbr); %initialize
for j = 1:M.endo_nbr
DERIVS.d2Yss(j,:,:) = dyn_unvech(full(d2Yss_KalmanA_Om(j,indp2modmod2))); %Hessian for d2Yss, but without cross derivatives
end
end
return %[END OF MAIN FUNCTION]!!!!!
end
if analytic_derivation_mode == -2
%% Numerical two-sided finite difference method to compute parameter derivatives of steady state and dynamic model,
% i.e. dYss, dg1, dg2, dg3 as well as d2Yss, d2g1 numerically.
% The parameter derivatives of perturbation solution matrices are computed analytically below (analytic_derivation_mode=0)
if order == 3
[~, g1, g2, g3] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
g3 = unfold_g3(g3, yy0ex0_nbr);
elseif order == 2
[~, g1, g2] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
elseif order == 1
[~, g1] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
end
if d2flag
% computation of d2Yss and d2g1
% note that hessian_sparse does not take symmetry into account, i.e. compare hessian_sparse.m to hessian.m, but focuses already on unique values, which are duplicated below
options.order = 1; %d2flag requires only first order
d2Yss_g1 = hessian_sparse(numerical_objective_fname, modparam1, options.gstep, 'dynamic_model', estim_params_model, M, oo, options); % d2flag requires only first-order
options.order = order;%make sure to set back the order
d2Yss = reshape(full(d2Yss_g1(1:M.endo_nbr,:)), [M.endo_nbr modparam_nbr modparam_nbr]); %put into tensor notation
for j=1:M.endo_nbr
d2Yss(j,:,:) = dyn_unvech(dyn_vech(d2Yss(j,:,:))); %add duplicate values to full hessian
end
d2g1_full = d2Yss_g1(M.endo_nbr+1:end,:);
%store only nonzero unique entries and the corresponding indices of d2g1:
% rows: respective derivative term
% 1st column: equation number of the term appearing
% 2nd column: column number of variable in Jacobian of the dynamic model
% 3rd column: number of the first parameter in derivative
% 4th column: number of the second parameter in derivative
% 5th column: value of the Hessian term
ind_d2g1 = find(d2g1_full);
d2g1 = zeros(length(ind_d2g1),5);
for j=1:length(ind_d2g1)
[i1, i2] = ind2sub(size(d2g1_full),ind_d2g1(j));
[ig1, ig2] = ind2sub(size(g1),i1);
[ip1, ip2] = ind2sub([modparam_nbr modparam_nbr],i2);
d2g1(j,:) = [ig1 ig2 ip1 ip2 d2g1_full(ind_d2g1(j))];
end
clear d2g1_full d2Yss_g1;
end
%Parameter Jacobian of dynamic model derivatives (wrt selected model parameters only)
dYss_g = fjaco(numerical_objective_fname, modparam1, 'dynamic_model', estim_params_model, M, oo, options);
ind_Yss = 1:M.endo_nbr;
ind_g1 = ind_Yss(end) + (1:M.endo_nbr*yy0ex0_nbr);
dYss = dYss_g(ind_Yss,:); %in tensor notation, wrt selected model parameters only
dg1 = reshape(dYss_g(ind_g1,:),[M.endo_nbr,yy0ex0_nbr,modparam_nbr]); %in tensor notation
if order > 1
ind_g2 = ind_g1(end) + (1:M.endo_nbr*yy0ex0_nbr^2);
dg2 = reshape(sparse(dYss_g(ind_g2,:)),[M.endo_nbr, yy0ex0_nbr^2*modparam_nbr]); %blockwise in matrix notation, i.e. [dg2_dp1 dg2_dp2 ...], where dg2_dpj has dimension M.endo_nbr by yy0ex0_nbr^2
end
if order > 2
ind_g3 = ind_g2(end) + (1:M.endo_nbr*yy0ex0_nbr^3);
dg3 = reshape(sparse(dYss_g(ind_g3,:)), [M.endo_nbr, yy0ex0_nbr^3*modparam_nbr]); %blockwise in matrix notation, i.e. [dg3_dp1 dg3_dp2 ...], where dg3_dpj has dimension M.endo_nbr by yy0ex0_nbr^3
end
clear dYss_g
elseif (analytic_derivation_mode == 0 || analytic_derivation_mode == 1)
%% Analytical computation of Jacobian and Hessian (wrt selected model parameters) of steady state, i.e. dYss and d2Yss
[~, g1_static] = feval([M.fname,'.static'], oo.dr.ys, oo.exo_steady_state', M.params); %g1_static is [M.endo_nbr by M.endo_nbr] first-derivative (wrt all endogenous variables) of static model equations f, i.e. df/dys, in declaration order
try
rp_static = feval([M.fname,'.static_params_derivs'], oo.dr.ys, oo.exo_steady_state', M.params); %rp_static is [M.endo_nbr by M.param_nbr] first-derivative (wrt all model parameters) of static model equations f, i.e. df/dparams, in declaration order
catch
error('For analytical parameter derivatives ''static_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
dys = -g1_static\rp_static; %use implicit function theorem (equation 5 of Ratto and Iskrev (2012) to compute [M.endo_nbr by M.param_nbr] first-derivative (wrt all model parameters) of steady state for all endogenous variables analytically, note that dys is in declaration order
d2ys = zeros(M.endo_nbr, M.param_nbr, M.param_nbr); %initialize in tensor notation, note that d2ys is only needed for d2flag, i.e. for g1pp
if d2flag
[~, ~, g2_static] = feval([M.fname,'.static'], oo.dr.ys, oo.exo_steady_state', M.params); %g2_static is [M.endo_nbr by M.endo_nbr^2] second derivative (wrt all endogenous variables) of static model equations f, i.e. d(df/dys)/dys, in declaration order
if order < 3
[~, g1, g2, g3] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1); %note that g3 does not contain symmetric elements
g3 = unfold_g3(g3, yy0ex0_nbr); %add symmetric elements to g3
else
T = NaN(sum(M.dynamic_tmp_nbr(1:5)));
T = feval([M.fname, '.dynamic_g4_tt'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
g1 = feval([M.fname, '.dynamic_g1'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %g1 is [M.endo_nbr by yy0ex0_nbr first derivative (wrt all dynamic variables) of dynamic model equations, i.e. df/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g2 = feval([M.fname, '.dynamic_g2'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %g2 is [M.endo_nbr by yy0ex0_nbr^2] second derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g3 = feval([M.fname, '.dynamic_g3'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %note that g3 does not contain symmetric elements
g4 = feval([M.fname, '.dynamic_g4'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %note that g4 does not contain symmetric elements
g3 = unfold_g3(g3, yy0ex0_nbr); %add symmetric elements to g3, %g3 is [M.endo_nbr by yy0ex0_nbr^3] third-derivative (wrt all dynamic variables) of dynamic model equations, i.e. (d(df/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g4 = unfold_g4(g4, yy0ex0_nbr); %add symmetric elements to g4, %g4 is [M.endo_nbr by yy0ex0_nbr^4] fourth-derivative (wrt all dynamic variables) of dynamic model equations, i.e. ((d(df/dyy0ex0)/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
end
%g1 is [M.endo_nbr by yy0ex0_nbr first derivative (wrt all dynamic variables) of dynamic model equations, i.e. df/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
%g2 is [M.endo_nbr by yy0ex0_nbr^2] second derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
%g3 is [M.endo_nbr by yy0ex0_nbr^3] third-derivative (wrt all dynamic variables) of dynamic model equations, i.e. (d(df/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
try
[~, g1p_static, rpp_static] = feval([M.fname,'.static_params_derivs'], oo.dr.ys, oo.exo_steady_state', M.params);
%g1p_static is [M.endo_nbr by M.endo_nbr by M.param_nbr] first derivative (wrt all model parameters) of first-derivative (wrt all endogenous variables) of static model equations f, i.e. (df/dys)/dparams, in declaration order
%rpp_static is [#second_order_residual_terms by 4] and contains nonzero values and corresponding indices of second derivatives (wrt all model parameters) of static model equations f, i.e. d(df/dparams)/dparams, in declaration order, where
% column 1 contains equation number; column 2 contains first parameter; column 3 contains second parameter; column 4 contains value of derivative
catch
error('For analytical parameter derivatives ''static_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
rpp_static = get_all_resid_2nd_derivs(rpp_static, M.endo_nbr, M.param_nbr); %make full matrix out of nonzero values and corresponding indices
%rpp_static is [M.endo_nbr by M.param_nbr by M.param_nbr] second derivatives (wrt all model parameters) of static model equations, i.e. d(df/dparams)/dparams, in declaration order
if isempty(find(g2_static))
%auxiliary expression on page 8 of Ratto and Iskrev (2012) is zero, i.e. gam = 0
for j = 1:M.param_nbr
%using the implicit function theorem, equation 15 on page 7 of Ratto and Iskrev (2012)
d2ys(:,:,j) = -g1_static\rpp_static(:,:,j);
%d2ys is [M.endo_nbr by M.param_nbr by M.param_nbr] second-derivative (wrt all model parameters) of steady state of all endogenous variables, i.e. d(dys/dparams)/dparams, in declaration order
end
else
gam = zeros(M.endo_nbr,M.param_nbr,M.param_nbr); %initialize auxiliary expression on page 8 of Ratto and Iskrev (2012)
for j = 1:M.endo_nbr
tmp_g1p_static_dys = (squeeze(g1p_static(j,:,:))'*dys);
gam(j,:,:) = transpose(reshape(g2_static(j,:),[M.endo_nbr M.endo_nbr])*dys)*dys + tmp_g1p_static_dys + tmp_g1p_static_dys';
end
for j = 1:M.param_nbr
%using the implicit function theorem, equation 15 on page 7 of Ratto and Iskrev (2012)
d2ys(:,:,j) = -g1_static\(rpp_static(:,:,j)+gam(:,:,j));
%d2ys is [M.endo_nbr by M.param_nbr by M.param_nbr] second-derivative (wrt all model parameters) of steady state of all endogenous variables, i.e. d(dys/dparams)/dparams, in declaration order
end
clear g1p_static g2_static tmp_g1p_static_dys gam
end
end
%handling of steady state for nonstationary variables
if any(any(isnan(dys)))
[U,T] = schur(g1_static);
e1 = abs(ordeig(T)) < qz_criterium-1;
k = sum(e1); % Number of non stationary variables.
% Number of stationary variables: n = length(e1)-k
[U,T] = ordschur(U,T,e1);
T = T(k+1:end,k+1:end);
%using implicit function theorem, equation 5 of Ratto and Iskrev (2012), in declaration order
dys = -U(:,k+1:end)*(T\U(:,k+1:end)')*rp_static;
if d2flag
disp('Computation of d2ys for nonstationary variables is not yet correctly handled if g2_static is nonempty, but continue anyways...')
for j = 1:M.param_nbr
%using implicit function theorem, equation 15 of Ratto and Iskrev (2012), in declaration order
d2ys(:,:,j) = -U(:,k+1:end)*(T\U(:,k+1:end)')*rpp_static(:,:,j); %THIS IS NOT CORRECT, IF g2_static IS NONEMPTY. WE NEED TO ADD GAM [willi]
end
end
end
if d2flag
try
if order < 3
[~, g1p, ~, g1pp, g2p] = feval([M.fname,'.dynamic_params_derivs'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, dys, d2ys);
else
[~, g1p, ~, g1pp, g2p, g3p] = feval([M.fname,'.dynamic_params_derivs'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, dys, d2ys);
end
catch
error('For analytical parameter derivatives ''dynamic_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
%g1pp are nonzero values and corresponding indices of second-derivatives (wrt all model parameters) of first-derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(d(df/dyy0ex0)/dparam)/dparam, rows are in declaration order, first column in declaration order
d2Yss = d2ys(oo.dr.order_var,indpmodel,indpmodel); %[M.endo_nbr by mod_param_nbr by mod_param_nbr], put into DR order and focus only on selected model parameters
else
if order == 1
try
[~, g1p] = feval([M.fname,'.dynamic_params_derivs'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, dys, d2ys);
%g1p is [M.endo_nbr by yy0ex0_nbr by M.param_nbr] first-derivative (wrt all model parameters) of first-derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dparam, rows are in declaration order, column in lead_lag_incidence order
catch
error('For analytical parameter derivatives ''dynamic_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
[~, g1, g2 ] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
%g1 is [M.endo_nbr by yy0ex0_nbr first derivative (wrt all dynamic variables) of dynamic model equations, i.e. df/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
%g2 is [M.endo_nbr by yy0ex0_nbr^2] second derivatives (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
elseif order == 2
try
[~, g1p, ~, ~, g2p] = feval([M.fname,'.dynamic_params_derivs'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, dys, d2ys);
%g1p is [M.endo_nbr by yy0ex0_nbr by M.param_nbr] first-derivative (wrt all model parameters) of first-derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dparam, rows are in declaration order, column in lead_lag_incidence order
%g2p are nonzero values and corresponding indices of first-derivative (wrt all model parameters) of second-derivatives (wrt all dynamic variables) of dynamic model equations, i.e. d(d(df/dyy0ex0)/dyy0ex0)/dparam, rows are in declaration order, first and second column in declaration order
catch
error('For analytical parameter derivatives ''dynamic_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
[~, g1, g2, g3] = feval([M.fname,'.dynamic'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1); %note that g3 does not contain symmetric elements
g3 = unfold_g3(g3, yy0ex0_nbr); %add symmetric elements to g3
%g1 is [M.endo_nbr by yy0ex0_nbr first derivative (wrt all dynamic variables) of dynamic model equations, i.e. df/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
%g2 is [M.endo_nbr by yy0ex0_nbr^2] second derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
%g3 is [M.endo_nbr by yy0ex0_nbr^3] third-derivative (wrt all dynamic variables) of dynamic model equations, i.e. (d(df/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
elseif order == 3
try
[~, g1p, ~, ~, g2p, g3p] = feval([M.fname,'.dynamic_params_derivs'], oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, dys, d2ys);
%g1p is [M.endo_nbr by yy0ex0_nbr by M.param_nbr] first-derivative (wrt all model parameters) of first-derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dparam, rows are in declaration order, column in lead_lag_incidence order
%g2p are nonzero values and corresponding indices of first-derivative (wrt all model parameters) of second-derivatives (wrt all dynamic variables) of dynamic model equations, i.e. d(d(df/dyy0ex0)/dyy0ex0)/dparam, rows are in declaration order, first and second column in declaration order
%g3p are nonzero values and corresponding indices of first-derivative (wrt all model parameters) of third-derivatives (wrt all dynamic variables) of dynamic model equations, i.e. d(d(d(df/dyy0ex0)/dyy0ex0)/dyy0ex0)/dparam, rows are in declaration order, first, second and third column in declaration order
catch
error('For analytical parameter derivatives ''dynamic_params_derivs.m'' file is needed, this can be created by putting identification(order=%d) into your mod file.',order)
end
T = NaN(sum(M.dynamic_tmp_nbr(1:5)));
T = feval([M.fname, '.dynamic_g4_tt'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1);
g1 = feval([M.fname, '.dynamic_g1'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %g1 is [M.endo_nbr by yy0ex0_nbr first derivative (wrt all dynamic variables) of dynamic model equations, i.e. df/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g2 = feval([M.fname, '.dynamic_g2'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %g2 is [M.endo_nbr by yy0ex0_nbr^2] second derivative (wrt all dynamic variables) of dynamic model equations, i.e. d(df/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g3 = feval([M.fname, '.dynamic_g3'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %note that g3 does not contain symmetric elements
g4 = feval([M.fname, '.dynamic_g4'], T, oo.dr.ys(I), oo.exo_steady_state', M.params, oo.dr.ys, 1, false); %note that g4 does not contain symmetric elements
g3 = unfold_g3(g3, yy0ex0_nbr); %add symmetric elements to g3, %g3 is [M.endo_nbr by yy0ex0_nbr^3] third-derivative (wrt all dynamic variables) of dynamic model equations, i.e. (d(df/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
g4 = unfold_g4(g4, yy0ex0_nbr); %add symmetric elements to g4, %g4 is [M.endo_nbr by yy0ex0_nbr^4] fourth-derivative (wrt all dynamic variables) of dynamic model equations, i.e. ((d(df/dyy0ex0)/dyy0ex0)/dyy0ex0)/dyy0ex0, rows are in declaration order, columns in lead_lag_incidence order
end
end
% Parameter Jacobian of steady state in different orderings, note dys is in declaration order
dYss = dys(oo.dr.order_var, indpmodel); %in DR-order, focus only on selected model parameters
dyy0 = dys(I,:); %in lead_lag_incidence order, Jacobian of dynamic (without exogenous) variables, focus on all model parameters
dyy0ex0 = sparse([dyy0; zeros(M.exo_nbr,M.param_nbr)]); %in lead_lag_incidence order, Jacobian of dynamic (with exogenous) variables, focus on all model parameters
%% Analytical computation of Jacobian (wrt selected model parameters) of first-derivative of dynamic model, i.e. dg1
% Note that we use the implicit function theorem (see Ratto and Iskrev (2012) formula 7):
% Let g1 = df/dyy0ex0 be the first derivative (wrt all dynamic variables) of the dynamic model, then
% dg1 denotes the first-derivative (wrt model parameters) of g1 evaluated at the steady state.
% Note that g1 is a function of both the model parameters p and of the steady state of all dynamic variables, which also depend on the model parameters.
% Hence, implicitly g1=g1(p,yy0ex0(p)) and dg1 consists of two parts:
% (1) g1p: direct derivative (wrt to all model parameters) given by the preprocessor
% (2) g2*dyy0ex0: contribution of derivative of steady state of dynamic variables (wrt all model parameters)
% Note that in a stochastic context ex0 and dex0 is always zero and hence can be skipped in the computations
dg1 = zeros(M.endo_nbr,yy0ex0_nbr,M.param_nbr); %initialize part (2)
for j = 1:M.endo_nbr
[II, JJ] = ind2sub([yy0ex0_nbr yy0ex0_nbr], find(g2(j,:))); %g2 is [M.endo_nbr by yy0ex0_nbr^2]
for i = 1:yy0ex0_nbr
is = find(II==i);
is = is(find(JJ(is)<=yy0_nbr)); %focus only on oo.dr.ys(I) derivatives as exogenous variables are 0 in a stochastic context
if ~isempty(is)
tmp_g2 = full(g2(j,find(g2(j,:))));
dg1(j,i,:) = tmp_g2(is)*dyy0(JJ(is),:); %put into tensor notation
end
end
end
dg1 = g1p + dg1; %add part (1)
dg1 = dg1(:,:,indpmodel); %focus only on selected model parameters
if order>1
%% Analytical computation of Jacobian (wrt selected model parameters) of second derivative of dynamic model, i.e. dg2
% We use the implicit function theorem:
% Let g2 = d2f/(dyy0ex0*dyy0ex0) denote the second derivative (wrt all dynamic variables) of the dynamic model, then
% dg2 denotes the first-derivative (wrt all model parameters) of g2 evaluated at the steady state.
% Note that g2 is a function of both the model parameters p and of the steady state of all dynamic variables, which also depend on the parameters.
% Hence, implicitly g2=g2(p,yy0ex0(p)) and dg2 consists of two parts:
% (1) g2p: direct derivative wrt to all model parameters given by the preprocessor
% and
% (2) g3*dyy0ex0: contribution of derivative of steady state of dynamic variables (wrt all model parameters)
% Note that we focus on selected model parameters only, i.e. indpmodel
% Also note that we stack the parameter derivatives blockwise instead of in tensors
dg2 = reshape(g3,[M.endo_nbr*yy0ex0_nbr^2 yy0ex0_nbr])*dyy0ex0(:,indpmodel); %part (2)
dg2 = reshape(dg2, [M.endo_nbr, yy0ex0_nbr^2*modparam_nbr]);
k2yy0ex0 = transpose(reshape(1:yy0ex0_nbr^2,yy0ex0_nbr,yy0ex0_nbr)); %index for the second dynamic derivatives, i.e. to evaluate the derivative of f wrt to yy0ex0(i) and yy0ex0(j), in DR order
for jj = 1:size(g2p,1)
jpos = find(indpmodel==g2p(jj,4));
if jpos~=0
dg2(g2p(jj,1), k2yy0ex0(g2p(jj,2),g2p(jj,3))+(jpos-1)*yy0ex0_nbr^2) = dg2(g2p(jj,1), k2yy0ex0(g2p(jj,2),g2p(jj,3))+(jpos-1)*yy0ex0_nbr^2) + g2p(jj,5); %add part (1)
end
end
end
if order>2
%% Analytical computation of Jacobian (wrt selected model parameters) of third derivative of dynamic model, i.e. dg3
% We use the implicit function theorem:
% Let g3 = d3f/(dyy0ex0*dyy0ex0*dyy0ex0) denote the third derivative (wrt all dynamic variables) of the dynamic model, then
% dg3 denotes the first-derivative (wrt all model parameters) of g3 evaluated at the steady state.
% Note that g3 is a function of both the model parameters p and of the steady state of all dynamic variables, which also depend on the parameters.
% Hence, implicitly g3=g3(p,yy0ex0(p)) and dg3 consists of two parts:
% (1) g3p: direct derivative wrt to all model parameters given by the preprocessor
% and
% (2) g4*dyy0ex0: contribution of derivative of steady state of dynamic variables (wrt all model parameters)
% Note that we focus on selected model parameters only, i.e. indpmodel
% Also note that we stack the parameter derivatives blockwise instead of in tensors
dg3 = reshape(g4,[M.endo_nbr*yy0ex0_nbr^3 yy0ex0_nbr])*dyy0ex0(:,indpmodel); %part (2)
dg3 = reshape(dg3, [M.endo_nbr, yy0ex0_nbr^3*modparam_nbr]);
k3yy0ex0 = permute(reshape(transpose(reshape(1:yy0ex0_nbr^3,yy0ex0_nbr,yy0ex0_nbr^2)),yy0ex0_nbr,yy0ex0_nbr,yy0ex0_nbr),[2 1 3]); %index for the third dynamic derivative, i.e. df/(dyyex0_i*dyyex0_j*dyyex0_k)
for jj = 1:size(g3p,1)
jpos = find(indpmodel==g3p(jj,5));
if jpos~=0
idyyy = unique(perms([g3p(jj,2) g3p(jj,3) g3p(jj,4)]),'rows'); %note that g3p does not contain symmetric terms, so we use the perms and unique functions
for k = 1:size(idyyy,1)
dg3(g3p(jj,1), k3yy0ex0(idyyy(k,1),idyyy(k,2),idyyy(k,3))+(jpos-1)*yy0ex0_nbr^3) = dg3(g3p(jj,1), k3yy0ex0(idyyy(k,1),idyyy(k,2),idyyy(k,3))+(jpos-1)*yy0ex0_nbr^3) + g3p(jj,6); %add part (1)
end
end
end
end
if d2flag
%% Analytical computation of Hessian (wrt selected model parameters) of first-derivative of dynamic model, i.e. d2g1
% We use the implicit function theorem (above we already computed: dg1 = g1p + g2*dyy0ex0):
% Accordingly, d2g1, the second-derivative (wrt model parameters), consists of five parts (ignoring transposes, see Ratto and Iskrev (2012) formula 16)
% (1) d(g1p)/dp = g1pp
% (2) d(g1p)/dyy0ex0*d(yy0ex0)/dp = g2p * dyy0ex0
% (3) d(g2)/dp * dyy0ex0 = g2p * dyy0ex0
% (4) d(g2)/dyy0ex0*d(dyy0ex0)/dp * dyy0ex0 = g3 * dyy0ex0 * dyy0ex0
% (5) g2 * d(dyy0ex0)/dp = g2 * d2yy0ex0
% Note that part 2 and 3 are equivalent besides the use of transpose (see Ratto and Iskrev (2012) formula 16)
d2g1_full = sparse(M.endo_nbr*yy0ex0_nbr, M.param_nbr*M.param_nbr); %initialize
g3_tmp = reshape(g3,[M.endo_nbr*yy0ex0_nbr*yy0ex0_nbr yy0ex0_nbr]);
d2g1_part4_left = sparse(M.endo_nbr*yy0ex0_nbr*yy0ex0_nbr,M.param_nbr);
for j = 1:M.param_nbr
%compute first two terms of part 4
d2g1_part4_left(:,j) = g3_tmp*dyy0ex0(:,j);
end
for j=1:M.endo_nbr
%Note that in the following we skip exogenous variables as these are 0 by construction in a stochastic setting
d2g1_part5 = reshape(g2(j,:), [yy0ex0_nbr yy0ex0_nbr]);
d2g1_part5 = d2g1_part5(:,1:yy0_nbr)*reshape(d2ys(I,:,:),[yy0_nbr,M.param_nbr*M.param_nbr]);
for i=1:yy0ex0_nbr
ind_part4 = sub2ind([M.endo_nbr yy0ex0_nbr yy0ex0_nbr], ones(yy0ex0_nbr,1)*j ,ones(yy0ex0_nbr,1)*i, (1:yy0ex0_nbr)');
d2g1_part4 = (d2g1_part4_left(ind_part4,:))'*dyy0ex0;
d2g1_part2_and_part3 = (get_hess_deriv(g2p,j,i,yy0ex0_nbr,M.param_nbr))'*dyy0ex0;
d2g1_part1 = get_2nd_deriv_mat(g1pp,j,i,M.param_nbr);
d2g1_tmp = d2g1_part1 + d2g1_part2_and_part3 + d2g1_part2_and_part3' + d2g1_part4 + reshape(d2g1_part5(i,:,:),[M.param_nbr M.param_nbr]);
d2g1_tmp = d2g1_tmp(indpmodel,indpmodel); %focus only on model parameters
if any(any(d2g1_tmp))
ind_d2g1_tmp = find(triu(d2g1_tmp));
d2g1_full(sub2ind([M.endo_nbr yy0ex0_nbr],j,i), ind_d2g1_tmp) = transpose(d2g1_tmp(ind_d2g1_tmp));
end
end
end
clear d2g1_tmp d2g1_part1 d2g1_part2_and_part3 d2g1_part4 d2g1_part4_left d2g1_part5
%store only nonzero entries and the corresponding indices of d2g1:
% 1st column: equation number of the term appearing
% 2nd column: column number of variable in Jacobian of the dynamic model
% 3rd column: number of the first parameter in derivative
% 4th column: number of the second parameter in derivative
% 5th column: value of the Hessian term
ind_d2g1 = find(d2g1_full);
d2g1 = zeros(length(ind_d2g1),5);
for j=1:length(ind_d2g1)
[i1, i2] = ind2sub(size(d2g1_full),ind_d2g1(j));
[ig1, ig2] = ind2sub(size(g1),i1);
[ip1, ip2] = ind2sub([modparam_nbr modparam_nbr],i2);
d2g1(j,:) = [ig1 ig2 ip1 ip2 d2g1_full(ind_d2g1(j))];
end
clear d2g1_full;
end
end
%% clear variables that are not used any more
clear dys dyy0 dyy0ex0 d2ys
clear rp_static rpp_static
clear g1_static g1p_static g1p g1pp
clear g2_static g2p tmp_g2 g3_tmp
clear ind_d2g1 ind_d2g1_tmp ind_part4 i j i1 i2 ig1 ig2 I II JJ ip1 ip2 is
if order == 1
clear g2 g3
elseif order == 2
clear g3
end
%% Construct Jacobian (wrt all selected parameters) of Sigma_e and Corr_e for Gaussian innovations
dSigma_e = zeros(M.exo_nbr,M.exo_nbr,totparam_nbr); %initialize
dCorrelation_matrix = zeros(M.exo_nbr,M.exo_nbr,totparam_nbr); %initialize
% Compute Jacobians wrt stderr parameters (these come first)
% note that derivatives wrt stderr parameters are zero by construction for Corr_e
if ~isempty(indpstderr)
for jp = 1:stderrparam_nbr
dSigma_e(indpstderr(jp),indpstderr(jp),jp) = 2*sqrt(M.Sigma_e(indpstderr(jp),indpstderr(jp)));
if isdiag(M.Sigma_e) == 0 % if there are correlated errors add cross derivatives
indotherex0 = 1:M.exo_nbr;
indotherex0(indpstderr(jp)) = [];
for kk = indotherex0
dSigma_e(indpstderr(jp), kk, jp) = M.Correlation_matrix(indpstderr(jp),kk)*sqrt(M.Sigma_e(kk,kk));
dSigma_e(kk, indpstderr(jp), jp) = dSigma_e(indpstderr(jp), kk, jp); %symmetry
end
end
end
end
% Compute Jacobians wrt corr parameters (these come second)
if ~isempty(indpcorr)
for jp = 1:corrparam_nbr
dSigma_e(indpcorr(jp,1),indpcorr(jp,2),stderrparam_nbr+jp) = sqrt(M.Sigma_e(indpcorr(jp,1),indpcorr(jp,1)))*sqrt(M.Sigma_e(indpcorr(jp,2),indpcorr(jp,2)));
dSigma_e(indpcorr(jp,2),indpcorr(jp,1),stderrparam_nbr+jp) = dSigma_e(indpcorr(jp,1),indpcorr(jp,2),stderrparam_nbr+jp); %symmetry
dCorrelation_matrix(indpcorr(jp,1),indpcorr(jp,2),stderrparam_nbr+jp) = 1;
dCorrelation_matrix(indpcorr(jp,2),indpcorr(jp,1),stderrparam_nbr+jp) = 1;%symmetry
end
end
% note that derivatives wrt model parameters (these come third) are zero by construction for Sigma_e and Corr_e
%% Analytical computation of Jacobian (wrt selected model parameters) of first-order solution matrices ghx, ghu, and of Om=ghu*Sigma_e*ghu'
%Notation:
% fy_ = g1(:,nonzeros(klag)) in DR order
% fy0 = g1(:,nonzeros(kcurr)) in DR order
% fyp = g1(:,nonzeros(klead)) in DR order
if analytic_derivation_mode == 1
% The following derivations are based on Iskrev (2010) and its online appendix A.
% Basic idea is to make use of the implicit function theorem.
% Define Kalman transition matrix KalmanA = [0 ghx 0], where the first zero spans M.nstatic columns, and the second zero M.nfwrd columns
% At first order we have: F = GAM0*KalmanA - GAM1*KalmanA*KalmanA - GAM2 = 0, where GAM0=fy0, GAM1=-fyp, GAM2 = -fy_
% Note that F is a function of parameters p and KalmanA, which is also a function of p,therefore, F = F(p,KalmanA(p))=0, and hence,
% dF = Fp + dF_dKalmanA*dKalmanA = 0 or dKalmanA = - Fp/dF_dKalmanA
% Some auxiliary matrices
I_endo = speye(M.endo_nbr);
KalmanA = [zeros(M.endo_nbr,M.nstatic) oo.dr.ghx zeros(M.endo_nbr,M.nfwrd)];
% Reshape to write first dynamic derivatives in the Magnus and Neudecker style, i.e. dvec(X)/dp
GAM0 = zeros(M.endo_nbr,M.endo_nbr);
GAM0(:,kcurr~=0,:) = g1(:,nonzeros(kcurr));
dGAM0 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dGAM0(:,kcurr~=0,:) = dg1(:,nonzeros(kcurr),:);
dGAM0 = reshape(dGAM0, M.endo_nbr*M.endo_nbr, modparam_nbr);
GAM1 = zeros(M.endo_nbr,M.endo_nbr);
GAM1(:,klead~=0,:) = -g1(:,nonzeros(klead));
dGAM1 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dGAM1(:,klead~=0,:) = -dg1(:,nonzeros(klead),:);
dGAM1 = reshape(dGAM1, M.endo_nbr*M.endo_nbr, modparam_nbr);
dGAM2 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dGAM2(:,klag~=0,:) = -dg1(:,nonzeros(klag),:);
dGAM2 = reshape(dGAM2, M.endo_nbr*M.endo_nbr, modparam_nbr);
GAM3 = -g1(:,yy0_nbr+1:end);
dGAM3 = reshape(-dg1(:,yy0_nbr+1:end,:), M.endo_nbr*M.exo_nbr, modparam_nbr);
% Compute dKalmanA via implicit function
dF_dKalmanAghx = kron(I_endo,GAM0) - kron(KalmanA',GAM1) - kron(I_endo,GAM1*KalmanA); %equation 31 in Appendix A of Iskrev (2010)
Fp = kron(KalmanA',I_endo)*dGAM0 - kron( (KalmanA')^2,I_endo)*dGAM1 - dGAM2; %equation 32 in Appendix A of Iskrev (2010)
dKalmanA = -dF_dKalmanAghx\Fp;
% Compute dBB from expressions 33 in Iskrev (2010) Appendix A
MM = GAM0-GAM1*KalmanA; %this corresponds to matrix M in Ratto and Iskrev (2012, page 6)
invMM = MM\eye(M.endo_nbr);
dghu = - kron( (invMM*GAM3)' , invMM ) * ( dGAM0 - kron( KalmanA' , I_endo ) * dGAM1 - kron( I_endo , GAM1 ) * dKalmanA ) + kron( speye(M.exo_nbr), invMM ) * dGAM3 ;
% Add derivatives for stderr and corr parameters, which are zero by construction
dKalmanA = [zeros(M.endo_nbr^2, stderrparam_nbr+corrparam_nbr) dKalmanA];
dghu = [zeros(M.endo_nbr*M.exo_nbr, stderrparam_nbr+corrparam_nbr) dghu];
% Compute dOm = dvec(ghu*Sigma_e*ghu') from expressions 34 in Iskrev (2010) Appendix A
dOm = kron(I_endo,oo.dr.ghu*M.Sigma_e)*(commutation(M.endo_nbr, M.exo_nbr)*dghu)...
+ kron(oo.dr.ghu,oo.dr.ghu)*reshape(dSigma_e, M.exo_nbr^2, totparam_nbr) + kron(oo.dr.ghu*M.Sigma_e,I_endo)*dghu;
% Put into tensor notation
dKalmanA = reshape(dKalmanA, M.endo_nbr, M.endo_nbr, totparam_nbr);
dghx = dKalmanA(:, M.nstatic+(1:M.nspred), stderrparam_nbr+corrparam_nbr+1:end); %get rid of zeros and focus on modparams only
dghu = reshape(dghu, M.endo_nbr, M.exo_nbr, totparam_nbr);
dghu = dghu(:,:,stderrparam_nbr+corrparam_nbr+1:end); %focus only on modparams
dOm = reshape(dOm, M.endo_nbr, M.endo_nbr, totparam_nbr);
clear dF_dKalmanAghx Fp dGAM0 dGAM1 dGAM2 dGAM3 MM invMM I_endo
elseif (analytic_derivation_mode == 0 || analytic_derivation_mode == -2)
% Here we make use of more efficient generalized sylvester equations
% Notation: ghx_ = oo.dr.ghx(idx_states,:), ghx0 = oo.dr.ghx(kcurr~=0,:), ghxp = oo.dr.ghx(klead~=0,:)
% Note that at first-order we have the following expressions, which are (numerically) zero:
% * for ghx: g1*zx = fyp*ghxp*ghx_ + fy0*ghx0 + fy_ = A*ghx + fy_ = 0
% Taking the differential yields a generalized sylvester equation to get dghx: A*dghx + B*dghx*ghx_ = -dg1*zx
% * for ghu: g1*zu = A*ghu + fu = 0
% Taking the differential yields an invertible equation to get dghu: A*dghu = -(dfu + dA*ghu)
% INITIALIZATIONS
% Note that A and B are the perturbation matrices (NOT the Kalman transition matrices)!
A = zeros(M.endo_nbr,M.endo_nbr);
A(:,kcurr~=0) = g1(:,nonzeros(kcurr));
A(:,idx_states) = A(:,idx_states) + g1(:,nonzeros(klead))*oo.dr.ghx(klead~=0,:);
B = zeros(M.endo_nbr,M.endo_nbr);
B(:,M.nstatic+M.npred+1:end) = g1(:,nonzeros(klead));
zx = [eye(M.nspred);
oo.dr.ghx(kcurr~=0,:);
oo.dr.ghx(klead~=0,:)*oo.dr.ghx(idx_states,:);
zeros(M.exo_nbr,M.nspred)];
dRHSx = zeros(M.endo_nbr,M.nspred,modparam_nbr);
for jp=1:modparam_nbr
dRHSx(:,:,jp) = -dg1(:,kyy0,jp)*zx(1:yy0_nbr,:);
end
%use iterated generalized sylvester equation to compute dghx
dghx = sylvester3(A,B,oo.dr.ghx(idx_states,:),dRHSx);
flag = 1; icount = 0;
while flag && icount < 4
[dghx, flag] = sylvester3a(dghx,A,B,oo.dr.ghx(idx_states,:),dRHSx);
icount = icount+1;
end
%Compute dOm, dghu, dA, dB
dOm = zeros(M.endo_nbr,M.endo_nbr,totparam_nbr); %as Om=ghu*Sigma_e*ghu', we need to use totparam_nbr, because there is also a contribution from stderr and corr parameters, which we compute after modparams
dghu = zeros(M.endo_nbr,M.exo_nbr,modparam_nbr);
dA = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr); %dA is also needed at higher orders
dA(:,kcurr~=0,:) = dg1(:,nonzeros(kcurr),:);
invA = inv(A); %also needed at higher orders
for jp=1:modparam_nbr
dA(:,idx_states,jp) = dA(:,idx_states,jp) + dg1(:,nonzeros(klead),jp)*oo.dr.ghx(klead~=0,:) + g1(:,nonzeros(klead))*dghx(klead~=0,:,jp);
dghu(:,:,jp) = -invA*( dg1(:,yy0_nbr+1:end,jp) + dA(:,:,jp)*oo.dr.ghu);
dOm(:,:,stderrparam_nbr+corrparam_nbr+jp) = dghu(:,:,jp)*M.Sigma_e*oo.dr.ghu' + oo.dr.ghu*M.Sigma_e*dghu(:,:,jp)';
end
%add stderr and corr derivatives to Om=ghu*Sigma_e*ghu'
if ~isempty(indpstderr)
for jp = 1:stderrparam_nbr
dOm(:,:,jp) = oo.dr.ghu*dSigma_e(:,:,jp)*oo.dr.ghu';
end
end
if ~isempty(indpcorr)
for jp = 1:corrparam_nbr
dOm(:,:,stderrparam_nbr+jp) = oo.dr.ghu*dSigma_e(:,:,stderrparam_nbr+jp)*oo.dr.ghu';
end
end
end
%% Analytical computation of Jacobian (wrt selected model parameters) of second-order solution matrices ghxx,ghxu,ghuu and ghs2
if order > 1
% Note that at second-order we have the following expressions, which are (numerically) zero:
% * for ghxx: A*ghxx + B*ghxx*kron(ghx_,ghx_) + g2*kron(zx,zx) = 0
% Taking the differential yields a generalized sylvester equation to get dghxx: A*dghxx + B*dghxx*kron(ghx_,ghx_) = RHSxx
% * for ghxu: A*ghxu + B*ghxx*kron(ghx_,ghu_) + g2*kron(zx,zu) = 0
% Taking the differential yields an invertible equation to get dghxu: A*dghxu = RHSxu
% * for ghuu: A*ghuu + B*ghxx*kron(ghu_,ghu_) + g2*kron(zu,zu) = 0
% Taking the differential yields an invertible equation to get dghuu: A*dghuu = RHSuu
% * for ghs2: Ahs2*ghs2 + (gg2_{++}*kron(ghup,ghup) + fyp*ghuup)*vec(Sigma_e) = 0
% Taking the differential yields an invertible equation to get dghs2: S*dghs2 = RHSs2
% * due to certainty equivalence and zero mean shocks, we note that ghxs and ghus are zero, and thus not computed
dB = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr); %this matrix is also needed at higher orders
dB(:,M.nstatic+M.npred+1:end,:) = dg1(:,nonzeros(klead),:);
S = A + B; %needed for dghs2, but also at higher orders
dS = dA + dB;
invS = inv(S);
G_x_x = kron(oo.dr.ghx(idx_states,:),oo.dr.ghx(idx_states,:));
dG_x_x = zeros(size(G_x_x,1),size(G_x_x,2),modparam_nbr);
dzx = zeros(size(zx,1),size(zx,2),modparam_nbr);
dRHSghxx = zeros(M.endo_nbr,M.nspred^2,modparam_nbr);
for jp=1:modparam_nbr
dzx(:,:,jp) = [zeros(M.nspred,M.nspred);
dghx(kcurr~=0,:,jp);
dghx(klead~=0,:,jp)*oo.dr.ghx(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghx(idx_states,:,jp);
zeros(M.exo_nbr,M.nspred)];
dRHS_1 = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0,kyy0)+(jp-1)*yy0ex0_nbr^2),zx(1:yy0_nbr,:),threads_BC);
dRHS_2 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0,kyy0)),dzx(1:yy0_nbr,:,jp),zx(1:yy0_nbr,:),threads_BC);
dRHS_3 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0,kyy0)),zx(1:yy0_nbr,:),dzx(1:yy0_nbr,:,jp),threads_BC);
dG_x_x(:,:,jp) = kron(dghx(idx_states,:,jp),oo.dr.ghx(idx_states,:)) + kron(oo.dr.ghx(idx_states,:),dghx(idx_states,:,jp));
dRHSghxx(:,:,jp) = -( (dRHS_1+dRHS_2+dRHS_3) + dA(:,:,jp)*oo.dr.ghxx + dB(:,:,jp)*oo.dr.ghxx*G_x_x + B*oo.dr.ghxx*dG_x_x(:,:,jp) );
end
%use iterated generalized sylvester equation to compute dghxx
dghxx = sylvester3(A,B,G_x_x,dRHSghxx);
flag = 1; icount = 0;
while flag && icount < 4
[dghxx, flag] = sylvester3a(dghxx,A,B,G_x_x,dRHSghxx);
icount = icount+1;
end
zu = [zeros(M.nspred,M.exo_nbr);
oo.dr.ghu(kcurr~=0,:);
oo.dr.ghx(klead~=0,:)*oo.dr.ghu(idx_states,:);
eye(M.exo_nbr)];
abcOutxu = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghx(idx_states,:),oo.dr.ghu(idx_states,:)); %auxiliary expressions for dghxu
abcOutuu = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghu(idx_states,:)); %auxiliary expressions for dghuu
RHSs2 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), oo.dr.ghu(klead~=0,:),threads_BC);
RHSs2 = RHSs2 + g1(:,nonzeros(klead))*oo.dr.ghuu(klead~=0,:);
dzu = zeros(size(zu,1),size(zu,2),modparam_nbr);
dghxu = zeros(M.endo_nbr,M.nspred*M.exo_nbr,modparam_nbr);
dghuu = zeros(M.endo_nbr,M.exo_nbr*M.exo_nbr,modparam_nbr);
dghs2 = zeros(M.endo_nbr,totparam_nbr); %note that for modparam we ignore the contribution by dSigma_e and add it after the computations for stderr and corr
for jp=1:modparam_nbr
dzu(:,:,jp) = [zeros(M.nspred,M.exo_nbr);
dghu(kcurr~=0,:,jp);
dghx(klead~=0,:,jp)*oo.dr.ghu(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghu(idx_states,:,jp);
zeros(M.exo_nbr,M.exo_nbr)];
%compute dghxu
dRHS_1 = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2),zx,zu,threads_BC);
dRHS_2 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),dzx(:,:,jp),zu,threads_BC);
dRHS_3 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),zx,dzu(:,:,jp),threads_BC);
dabcOut_1 = A_times_B_kronecker_C(dghxx(:,:,jp),oo.dr.ghx(idx_states,:),oo.dr.ghu(idx_states,:));
dabcOut_2 = A_times_B_kronecker_C(oo.dr.ghxx,dghx(idx_states,:,jp),oo.dr.ghu(idx_states,:));
dabcOut_3 = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghx(idx_states,:),dghu(idx_states,:,jp));
dghxu(:,:,jp) = -invA * ( dA(:,:,jp)*oo.dr.ghxu + (dRHS_1+dRHS_2+dRHS_3) + dB(:,:,jp)*abcOutxu + B*(dabcOut_1+dabcOut_2+dabcOut_3) );
%compute dghuu
dRHS_1 = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2),zu,threads_BC);
dRHS_2 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),dzu(:,:,jp),zu,threads_BC);
dRHS_3 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),zu,dzu(:,:,jp),threads_BC);
dabcOut_1 = A_times_B_kronecker_C(dghxx(:,:,jp),oo.dr.ghu(idx_states,:));
dabcOut_2 = A_times_B_kronecker_C(oo.dr.ghxx,dghu(idx_states,:,jp),oo.dr.ghu(idx_states,:));
dabcOut_3 = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghu(idx_states,:),dghu(idx_states,:,jp));
dghuu(:,:,jp) = -invA * ( dA(:,:,jp)*oo.dr.ghuu + (dRHS_1+dRHS_2+dRHS_3) + dB(:,:,jp)*abcOutuu + B*(dabcOut_1+dabcOut_2+dabcOut_3) );
%compute dghs2
dRHS_1 = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))+(jp-1)*yy0ex0_nbr^2), oo.dr.ghu(klead~=0,:),threads_BC);
dRHS_2 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), dghu(klead~=0,:,jp), oo.dr.ghu(klead~=0,:),threads_BC);
dRHS_3 = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), oo.dr.ghu(klead~=0,:), dghu(klead~=0,:,jp),threads_BC);
dghs2(:,stderrparam_nbr+corrparam_nbr+jp) = -invS * ( dS(:,:,jp)*oo.dr.ghs2 + ( (dRHS_1+dRHS_2+dRHS_3) + dg1(:,nonzeros(klead),jp)*oo.dr.ghuu(klead~=0,:) + g1(:,nonzeros(klead))*dghuu(klead~=0,:,jp) )*M.Sigma_e(:) );
end
%add contributions by dSigma_e to dghs2
if ~isempty(indpstderr)
for jp = 1:stderrparam_nbr
dghs2(:,jp) = -invS * RHSs2*vec(dSigma_e(:,:,jp));
end
end
if ~isempty(indpcorr)
for jp = 1:corrparam_nbr
dghs2(:,stderrparam_nbr+jp) = -invS * RHSs2*vec(dSigma_e(:,:,stderrparam_nbr+jp));
end
end
end
if order > 2
% Note that at third-order we have the following expressions, which are (numerically) zero, given suitable tensor-unfolding permuation matrices P:
% * for ghxxx: A*ghxxx + B*ghxxx*kron(ghx_,kron(ghx_,ghx_)) + g3*kron(kron(zx,zx),zx) + g2*kron(zx,zxx)*P_x_xx + fyp*ghxxp*kron(ghx_,ghxx_)*P_x_xx = 0
% Taking the differential yields a generalized sylvester equation to get dghxxx: A*dghxxx + B*dghxxx*kron(ghx_,kron(ghx_,ghx_)) = RHSxxx
% * for ghxxu: A*ghxxu + B*ghxxx*kron(ghx_,kron(ghx_,ghu_)) + gg3*kron(zx,kron(zx,zu)) + gg2*(kron(zx,zxu)*P_x_xu + kron(zxx,zu)) + fyp*ghxxp*(kron(ghx_,ghxu_)*P_x_xu + kron(ghxx_,ghu_)) = 0
% Taking the differential yields an invertible equation to get dghxxu: A*dghxxu = RHSxxu
% * for ghxuu: A*ghxuu + B*ghxxx*kron(ghx_,kron(ghu_,ghu_)) + gg3*kron(zx,kron(zu,zu)) + gg2*(kron(zxu,zu)*P_xu_u + kron(zx,zuu)) + fyp*ghxxp*(kron(ghxu_,ghu_)*Pxu_u + kron(ghx_,ghuu_)) = 0
% Taking the differential yields an invertible equation to get dghxuu: A*dghxuu = RHSxuu
% * for ghuuu: A*ghuuu + B*ghxxx*kron(ghu_,kron(ghu_,ghu_)) + gg3*kron(kron(zu,zu),zu) + gg2*kron(zu,zuu)*P_u_uu + fyp*ghxxp*kron(ghu_,ghuu_)*P_u_uu = 0
% Taking the differential yields an invertible equation to get dghuuu: A*dghuuu = RHSuuu
% * for ghxss: A*ghxss + B*ghxss*ghx_ + fyp*ghxxp*kron(ghx_,ghss_) + gg2*kron(zx,zss) + Fxupup*kron(Ix,Sigma_e(:)) = 0
% Taking the differential yields a generalized sylvester equation to get dghxss: A*dghxss + B*dghxss*ghx_ = RHSxss
% * for ghuss: A*ghuss + B*ghxss*ghu_ + gg2*kron(zu,zss) + fyp*ghxxp*kron(ghu_,ghss_) + Fuupup*kron(Iu,Sigma_e(:)) = 0
% Taking the differential yields an invertible equation to get dghuss: A*dghuss = RHSuss
% * due to certainty equivalence and Gaussian shocks, we note that ghxxs, ghxus, ghuus, and ghsss are zero and thus not computed
% permutation matrices
id_xxx = reshape(1:M.nspred^3,1,M.nspred,M.nspred,M.nspred);
id_uux = reshape(1:M.nspred*M.exo_nbr^2,1,M.exo_nbr,M.exo_nbr,M.nspred);
id_uxx = reshape(1:M.nspred^2*M.exo_nbr,1,M.exo_nbr,M.nspred,M.nspred);
id_uuu = reshape(1:M.exo_nbr^3,1,M.exo_nbr,M.exo_nbr,M.exo_nbr);
I_xxx = speye(M.nspred^3);
I_xxu = speye(M.nspred^2*M.exo_nbr);
I_xuu = speye(M.nspred*M.exo_nbr^2);
I_uuu = speye(M.exo_nbr^3);
P_x_xx = I_xxx(:,ipermute(id_xxx,[1,3,4,2])) + I_xxx(:,ipermute(id_xxx,[1,2,4,3])) + I_xxx(:,ipermute(id_xxx,[1,2,3,4]));
P_x_xu = I_xxu(:,ipermute(id_uxx,[1,2,3,4])) + I_xxu(:,ipermute(id_uxx,[1,2,4,3]));
P_xu_u = I_xuu(:,ipermute(id_uux,[1,2,3,4])) + I_xuu(:,ipermute(id_uux,[1,3,2,4]));
P_u_uu = I_uuu(:,ipermute(id_uuu,[1,3,4,2])) + I_uuu(:,ipermute(id_uuu,[1,2,4,3])) + I_uuu(:,ipermute(id_uuu,[1,2,3,4]));
P_uu_u = I_uuu(:,ipermute(id_uuu,[1,2,3,4])) + I_uuu(:,ipermute(id_uuu,[1,3,4,2]));
zxx = [spalloc(M.nspred,M.nspred^2,0);
oo.dr.ghxx(kcurr~=0,:);
oo.dr.ghxx(klead~=0,:)*G_x_x + oo.dr.ghx(klead~=0,:)*oo.dr.ghxx(idx_states,:);
spalloc(M.exo_nbr,M.nspred^2,0)];
G_x_x_x = kron(oo.dr.ghx(idx_states,:), G_x_x);
G_x_xx = kron(oo.dr.ghx(idx_states,:),oo.dr.ghxx(idx_states,:));
Z_x_x = kron(zx,zx);
Z_x_x_x = kron(zx,Z_x_x);
Z_x_xx = kron(zx,zxx);
fyp_ghxxp = sparse(g1(:,nonzeros(klead))*oo.dr.ghxx(klead~=0,:));
B_ghxxx = B*oo.dr.ghxxx;
dzxx = zeros(size(zxx,1),size(zxx,2),modparam_nbr);
dfyp_ghxxp = zeros(size(fyp_ghxxp,1),size(fyp_ghxxp,2),modparam_nbr);
dRHSghxxx = zeros(M.endo_nbr,M.nspred^3,modparam_nbr);
for jp=1:modparam_nbr
dzxx(:,:,jp) = [zeros(M.nspred,M.nspred^2);
dghxx(kcurr~=0,:,jp);
dghxx(klead~=0,:,jp)*G_x_x + oo.dr.ghxx(klead~=0,:)*dG_x_x(:,:,jp) + dghx(klead~=0,:,jp)*oo.dr.ghxx(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghxx(idx_states,:,jp);
zeros(M.exo_nbr,M.nspred^2)];
dG_x_x_x = kron(dghx(idx_states,:,jp),G_x_x) + kron(oo.dr.ghx(idx_states,:),dG_x_x(:,:,jp));
dG_x_xx = kron(dghx(idx_states,:,jp),oo.dr.ghxx(idx_states,:)) + kron(oo.dr.ghx(idx_states,:),dghxx(idx_states,:,jp));
dZ_x_x = kron(dzx(:,:,jp), zx) + kron(zx, dzx(:,:,jp));
dZ_x_x_x = kron(dzx(:,:,jp), Z_x_x) + kron(zx, dZ_x_x);
dZ_x_xx = kron(dzx(:,:,jp), zxx) + kron(zx, dzxx(:,:,jp));
dfyp_ghxxp(:,:,jp) = dg1(:,nonzeros(klead),jp)*oo.dr.ghxx(klead~=0,:) + g1(:,nonzeros(klead))*dghxx(klead~=0,:,jp);
dRHSghxxx(:,:,jp) = dA(:,:,jp)*oo.dr.ghxxx + dB(:,:,jp)*oo.dr.ghxxx*G_x_x_x + B_ghxxx*dG_x_x_x;
dRHSghxxx(:,:,jp) = dRHSghxxx(:,:,jp) + dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_x_x_x + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_x_x_x;
dRHSghxxx(:,:,jp) = dRHSghxxx(:,:,jp) + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*Z_x_xx*P_x_xx + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_x_xx*P_x_xx;
dRHSghxxx(:,:,jp) = dRHSghxxx(:,:,jp) + dfyp_ghxxp(:,:,jp)*G_x_xx*P_x_xx + fyp_ghxxp*dG_x_xx*P_x_xx;
end
dRHSghxxx = -dRHSghxxx;
%use iterated generalized sylvester equation to compute dghxxx
dghxxx = sylvester3(A,B,G_x_x_x,dRHSghxxx);
flag = 1; icount = 0;
while flag && icount < 4
[dghxxx, flag] = sylvester3a(dghxxx,A,B,G_x_x_x,dRHSghxxx);
icount = icount+1;
end
%Auxiliary expressions for dghxxu, dghxuu, dghuuu, dghxss, dghuss
G_x_u = kron(oo.dr.ghx(idx_states,:),oo.dr.ghu(idx_states,:));
G_u_u = kron(oo.dr.ghu(idx_states,:),oo.dr.ghu(idx_states,:));
zxu = [zeros(M.nspred,M.nspred*M.exo_nbr);
oo.dr.ghxu(kcurr~=0,:);
oo.dr.ghxx(klead~=0,:)*G_x_u + oo.dr.ghx(klead~=0,:)*oo.dr.ghxu(idx_states,:);
zeros(M.exo_nbr,M.exo_nbr*M.nspred)];
zuu = [zeros(M.nspred,M.exo_nbr^2);
oo.dr.ghuu(kcurr~=0,:);
oo.dr.ghxx(klead~=0,:)*G_u_u + oo.dr.ghx(klead~=0,:)*oo.dr.ghuu(idx_states,:);
zeros(M.exo_nbr,M.exo_nbr^2)];
Z_x_u = kron(zx,zu);
Z_u_u = kron(zu,zu);
Z_x_xu = kron(zx,zxu);
Z_xx_u = kron(zxx,zu);
Z_xu_u = kron(zxu,zu);
Z_x_uu = kron(zx,zuu);
Z_u_uu = kron(zu,zuu);
Z_x_x_u = kron(Z_x_x,zu);
Z_x_u_u = kron(Z_x_u,zu);
Z_u_u_u = kron(Z_u_u,zu);
G_x_xu = kron(oo.dr.ghx(idx_states,:),oo.dr.ghxu(idx_states,:));
G_xx_u = kron(oo.dr.ghxx(idx_states,:),oo.dr.ghu(idx_states,:));
G_xu_u = kron(oo.dr.ghxu(idx_states,:),oo.dr.ghu(idx_states,:));
G_x_uu = kron(oo.dr.ghx(idx_states,:),oo.dr.ghuu(idx_states,:));
G_u_uu = kron(oo.dr.ghu(idx_states,:),oo.dr.ghuu(idx_states,:));
G_x_x_u = kron(G_x_x,oo.dr.ghu(idx_states,:));
G_x_u_u = kron(G_x_u,oo.dr.ghu(idx_states,:));
G_u_u_u = kron(G_u_u,oo.dr.ghu(idx_states,:));
aux_ZP_x_xu_Z_xx_u = Z_x_xu*P_x_xu + Z_xx_u;
aux_ZP_xu_u_Z_x_uu = Z_xu_u*P_xu_u + Z_x_uu;
aux_GP_x_xu_G_xx_u = G_x_xu*P_x_xu + G_xx_u;
aux_GP_xu_u_G_x_uu = G_xu_u*P_xu_u + G_x_uu;
dghxxu = zeros(M.endo_nbr,M.nspred^2*M.exo_nbr,modparam_nbr);
dghxuu = zeros(M.endo_nbr,M.nspred*M.exo_nbr^2,modparam_nbr);
dghuuu = zeros(M.endo_nbr,M.exo_nbr^3,modparam_nbr);
%stuff for ghxss
zup = [zeros(M.nspred,M.exo_nbr);
zeros(length(nonzeros(kcurr)),M.exo_nbr);
oo.dr.ghu(klead~=0,:);
zeros(M.exo_nbr,M.exo_nbr)];
zss = [zeros(M.nspred,1);
oo.dr.ghs2(kcurr~=0,:);
oo.dr.ghs2(klead~=0,:) + oo.dr.ghx(klead~=0,:)*oo.dr.ghs2(idx_states,:);
zeros(M.exo_nbr,1)];
zxup = [zeros(M.nspred,M.nspred*M.exo_nbr);
zeros(length(nonzeros(kcurr)),M.nspred*M.exo_nbr);
oo.dr.ghxu(klead~=0,:)*kron(oo.dr.ghx(idx_states,:),eye(M.exo_nbr));
zeros(M.exo_nbr,M.nspred*M.exo_nbr)];
zupup = [zeros(M.nspred,M.exo_nbr^2);
zeros(length(nonzeros(kcurr)),M.exo_nbr^2);
oo.dr.ghuu(klead~=0,:);
zeros(M.exo_nbr,M.exo_nbr^2)];
G_x_ss = kron(oo.dr.ghx(idx_states,:),oo.dr.ghs2(idx_states,:));
Z_x_ss = kron(zx,zss);
Z_up_up = kron(zup,zup);
Z_xup_up = kron(zxup,zup);
Z_x_upup = kron(zx,zupup);
Z_x_up_up = kron(zx,Z_up_up);
aux_ZP_xup_up_Z_x_upup = Z_xup_up*P_xu_u + Z_x_upup;
Fxupup = g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*Z_x_up_up + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*aux_ZP_xup_up_Z_x_upup + g1(:,nonzeros(klead))*oo.dr.ghxuu(klead~=0,:)*kron(oo.dr.ghx(idx_states,:),eye(M.exo_nbr^2));
Ix_vecSig_e = kron(speye(M.nspred),M.Sigma_e(:));
dRHSxss = zeros(M.endo_nbr,M.nspred,totparam_nbr);
%stuff for ghuss
zuup = [zeros(M.nspred,M.exo_nbr^2);
zeros(length(nonzeros(kcurr)),M.exo_nbr^2);
oo.dr.ghxu(klead~=0,:)*kron(oo.dr.ghu(idx_states,:),eye(M.exo_nbr));
zeros(M.exo_nbr,M.exo_nbr^2)];
G_u_ss = kron(oo.dr.ghu(idx_states,:),oo.dr.ghs2(idx_states,:));
Z_u_ss = kron(zu,zss);
Z_u_upup = kron(zu,zupup);
Z_uup_up = kron(zuup,zup);
Z_u_up_up = kron(zu,Z_up_up);
aux_ZP_uup_up_Z_u_upup = Z_uup_up*P_uu_u + Z_u_upup;
Fuupup = g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*Z_u_up_up + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*aux_ZP_uup_up_Z_u_upup + g1(:,nonzeros(klead))*oo.dr.ghxuu(klead~=0,:)*kron(oo.dr.ghu(idx_states,:),eye(M.exo_nbr^2));
Iu_vecSig_e = kron(speye(M.exo_nbr),M.Sigma_e(:));
dRHSuss = zeros(M.endo_nbr,M.exo_nbr,totparam_nbr);
for jp=1:modparam_nbr
dG_x_u = kron(dghx(idx_states,:,jp), oo.dr.ghu(idx_states,:)) + kron(oo.dr.ghx(idx_states,:), dghu(idx_states,:,jp));
dG_u_u = kron(dghu(idx_states,:,jp), oo.dr.ghu(idx_states,:)) + kron(oo.dr.ghu(idx_states,:), dghu(idx_states,:,jp));
dzxu = [zeros(M.nspred,M.nspred*M.exo_nbr);
dghxu(kcurr~=0,:,jp);
dghxx(klead~=0,:,jp)*G_x_u + oo.dr.ghxx(klead~=0,:)*dG_x_u + dghx(klead~=0,:,jp)*oo.dr.ghxu(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghxu(idx_states,:,jp);
zeros(M.exo_nbr,M.nspred*M.exo_nbr)];
dzuu = [zeros(M.nspred,M.exo_nbr^2);
dghuu(kcurr~=0,:,jp);
dghxx(klead~=0,:,jp)*G_u_u + oo.dr.ghxx(klead~=0,:)*dG_u_u + dghx(klead~=0,:,jp)*oo.dr.ghuu(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghuu(idx_states,:,jp);
zeros(M.exo_nbr,M.exo_nbr^2)];
dG_x_xu = kron(dghx(idx_states,:,jp),oo.dr.ghxu(idx_states,:)) + kron(oo.dr.ghx(idx_states,:),dghxu(idx_states,:,jp));
dG_x_uu = kron(dghx(idx_states,:,jp),oo.dr.ghuu(idx_states,:)) + kron(oo.dr.ghx(idx_states,:),dghuu(idx_states,:,jp));
dG_u_uu = kron(dghu(idx_states,:,jp),oo.dr.ghuu(idx_states,:)) + kron(oo.dr.ghu(idx_states,:),dghuu(idx_states,:,jp));
dG_xx_u = kron(dghxx(idx_states,:,jp),oo.dr.ghu(idx_states,:)) + kron(oo.dr.ghxx(idx_states,:),dghu(idx_states,:,jp));
dG_xu_u = kron(dghxu(idx_states,:,jp),oo.dr.ghu(idx_states,:)) + kron(oo.dr.ghxu(idx_states,:),dghu(idx_states,:,jp));
dG_x_x_u = kron(G_x_x,dghu(idx_states,:,jp)) + kron(dG_x_x(:,:,jp),oo.dr.ghu(idx_states,:));
dG_x_u_u = kron(G_x_u,dghu(idx_states,:,jp)) + kron(dG_x_u,oo.dr.ghu(idx_states,:));
dG_u_u_u = kron(G_u_u,dghu(idx_states,:,jp)) + kron(dG_u_u,oo.dr.ghu(idx_states,:));
dZ_x_u = kron(dzx(:,:,jp),zu) + kron(zx,dzu(:,:,jp));
dZ_u_u = kron(dzu(:,:,jp),zu) + kron(zu,dzu(:,:,jp));
dZ_x_x_u = kron(dzx(:,:,jp), Z_x_u) + kron(zx, dZ_x_u);
dZ_x_u_u = kron(dZ_x_u, zu) + kron(Z_x_u, dzu(:,:,jp));
dZ_u_u_u = kron(dZ_u_u, zu) + kron(Z_u_u, dzu(:,:,jp));
dZ_xx_u = kron(dzxx(:,:,jp), zu) + kron(zxx, dzu(:,:,jp));
dZ_xu_u = kron(dzxu, zu) + kron(zxu, dzu(:,:,jp));
dZ_x_xu = kron(dzx(:,:,jp), zxu) + kron(zx, dzxu);
dZ_x_uu = kron(dzx(:,:,jp), zuu) + kron(zx, dzuu);
dZ_u_uu = kron(dzu(:,:,jp), zuu) + kron(zu, dzuu);
dB_ghxxx = dB(:,:,jp)*oo.dr.ghxxx + B*dghxxx(:,:,jp);
%Compute dghxxu
dRHS = dA(:,:,jp)*oo.dr.ghxxu + dB_ghxxx*G_x_x_u + B_ghxxx*dG_x_x_u;
dRHS = dRHS + dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_x_x_u + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_x_x_u;
dRHS = dRHS + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*aux_ZP_x_xu_Z_xx_u + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*( dZ_x_xu*P_x_xu + dZ_xx_u );
dRHS = dRHS + dfyp_ghxxp(:,:,jp)*aux_GP_x_xu_G_xx_u + fyp_ghxxp*( dG_x_xu*P_x_xu + dG_xx_u );
dghxxu(:,:,jp) = invA* (-dRHS);
%Compute dghxuu
dRHS = dA(:,:,jp)*oo.dr.ghxuu + dB_ghxxx*G_x_u_u + B_ghxxx*dG_x_u_u;
dRHS = dRHS + dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_x_u_u + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_x_u_u;
dRHS = dRHS + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*aux_ZP_xu_u_Z_x_uu + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*( dZ_xu_u*P_xu_u + dZ_x_uu );
dRHS = dRHS + dfyp_ghxxp(:,:,jp)*aux_GP_xu_u_G_x_uu + fyp_ghxxp*( dG_xu_u*P_xu_u + dG_x_uu );
dghxuu(:,:,jp) = invA* (-dRHS);
%Compute dghuuu
dRHS = dA(:,:,jp)*oo.dr.ghuuu + dB_ghxxx*G_u_u_u + B_ghxxx*dG_u_u_u;
dRHS = dRHS + dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_u_u_u + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_u_u_u;
dRHS = dRHS + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*Z_u_uu*P_u_uu + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_u_uu*P_u_uu;
dRHS = dRHS + dfyp_ghxxp(:,:,jp)*G_u_uu*P_u_uu + fyp_ghxxp*dG_u_uu*P_u_uu;
dghuuu(:,:,jp) = invA* (-dRHS);
%Compute dRHSxss
dzup = [zeros(M.nspred,M.exo_nbr);
zeros(length(nonzeros(kcurr)),M.exo_nbr);
dghu(klead~=0,:,jp);
zeros(M.exo_nbr,M.exo_nbr)];
dzss = [zeros(M.nspred,1);
dghs2(kcurr~=0,stderrparam_nbr+corrparam_nbr+jp);
dghs2(klead~=0,stderrparam_nbr+corrparam_nbr+jp) + dghx(klead~=0,:,jp)*oo.dr.ghs2(idx_states,:) + oo.dr.ghx(klead~=0,:)*dghs2(idx_states,stderrparam_nbr+corrparam_nbr+jp);
zeros(M.exo_nbr,1)];
dzxup = [zeros(M.nspred,M.nspred*M.exo_nbr);
zeros(length(nonzeros(kcurr)),M.nspred*M.exo_nbr);
dghxu(klead~=0,:,jp)*kron(oo.dr.ghx(idx_states,:),eye(M.exo_nbr)) + oo.dr.ghxu(klead~=0,:)*kron(dghx(idx_states,:,jp),eye(M.exo_nbr));
zeros(M.exo_nbr,M.nspred*M.exo_nbr)];
dzupup = [zeros(M.nspred,M.exo_nbr^2);
zeros(length(nonzeros(kcurr)),M.exo_nbr^2);
dghuu(klead~=0,:,jp);
zeros(M.exo_nbr,M.exo_nbr^2)];
dG_x_ss = kron(dghx(idx_states,:,jp),oo.dr.ghs2(idx_states,:)) + kron(oo.dr.ghx(idx_states,:),dghs2(idx_states,stderrparam_nbr+corrparam_nbr+jp));
dZ_x_ss = kron(dzx(:,:,jp),zss) + kron(zx,dzss);
dZ_up_up = kron(dzup,zup) + kron(zup,dzup);
dZ_xup_up = kron(dzxup,zup) + kron(zxup,dzup);
dZ_x_upup = kron(dzx(:,:,jp),zupup) + kron(zx,dzupup);
dZ_x_up_up = kron(dzx(:,:,jp),Z_up_up) + kron(zx,dZ_up_up);
daux_ZP_xup_up_Z_x_upup = dZ_xup_up*P_xu_u + dZ_x_upup;
dFxupup = dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_x_up_up + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_x_up_up...
+ dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*aux_ZP_xup_up_Z_x_upup + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*daux_ZP_xup_up_Z_x_upup...
+ dg1(:,nonzeros(klead),jp)*oo.dr.ghxuu(klead~=0,:)*kron(oo.dr.ghx(idx_states,:),eye(M.exo_nbr^2)) + g1(:,nonzeros(klead))*dghxuu(klead~=0,:,jp)*kron(oo.dr.ghx(idx_states,:),eye(M.exo_nbr^2)) + g1(:,nonzeros(klead))*oo.dr.ghxuu(klead~=0,:)*kron(dghx(idx_states,:,jp),eye(M.exo_nbr^2));
dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dA(:,:,jp)*oo.dr.ghxss + dB(:,:,jp)*oo.dr.ghxss*oo.dr.ghx(idx_states,:) + B*oo.dr.ghxss*dghx(idx_states,:,jp);
dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dfyp_ghxxp(:,:,jp)*G_x_ss + fyp_ghxxp*dG_x_ss; %m
dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*Z_x_ss + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_x_ss;
dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSxss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dFxupup*Ix_vecSig_e; %missing contribution by dSigma_e
%Compute dRHSuss
dzuup = [zeros(M.nspred,M.exo_nbr^2);
zeros(length(nonzeros(kcurr)),M.exo_nbr^2);
dghxu(klead~=0,:,jp)*kron(oo.dr.ghu(idx_states,:),eye(M.exo_nbr)) + oo.dr.ghxu(klead~=0,:)*kron(dghu(idx_states,:,jp),eye(M.exo_nbr));
zeros(M.exo_nbr,M.exo_nbr^2)];
dG_u_ss = kron(dghu(idx_states,:,jp),oo.dr.ghs2(idx_states,:)) + kron(oo.dr.ghu(idx_states,:),dghs2(idx_states,stderrparam_nbr+corrparam_nbr+jp));
dZ_u_ss = kron(dzu(:,:,jp),zss) + kron(zu,dzss);
dZ_u_upup = kron(dzu(:,:,jp),zupup) + kron(zu,dzupup);
dZ_uup_up = kron(dzuup,zup) + kron(zuup,dzup);
dZ_u_up_up = kron(dzu(:,:,jp),Z_up_up) + kron(zu,dZ_up_up);
daux_ZP_uup_up_Z_u_upup = dZ_uup_up*P_uu_u + dZ_u_upup;
dFuupup = dg3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^3)*Z_u_up_up + g3(:,k3yy0ex0(kyy0ex0,kyy0ex0,kyy0ex0))*dZ_u_up_up...
+ dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*aux_ZP_uup_up_Z_u_upup + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*daux_ZP_uup_up_Z_u_upup...
+ dg1(:,nonzeros(klead),jp)*oo.dr.ghxuu(klead~=0,:)*kron(oo.dr.ghu(idx_states,:),eye(M.exo_nbr^2)) + g1(:,nonzeros(klead))*dghxuu(klead~=0,:,jp)*kron(oo.dr.ghu(idx_states,:),eye(M.exo_nbr^2)) + g1(:,nonzeros(klead))*oo.dr.ghxuu(klead~=0,:)*kron(dghu(idx_states,:,jp),eye(M.exo_nbr^2));
dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dA(:,:,jp)*oo.dr.ghuss + dB(:,:,jp)*oo.dr.ghxss*oo.dr.ghu(idx_states,:) + B*oo.dr.ghxss*dghu(idx_states,:,jp); %missing dghxss
dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dfyp_ghxxp(:,:,jp)*G_u_ss + fyp_ghxxp*dG_u_ss;
dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2)*Z_u_ss + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_u_ss;
dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) = dRHSuss(:,:,stderrparam_nbr+corrparam_nbr+jp) + dFuupup*Iu_vecSig_e; %contribution by dSigma_e only for stderr and corr params
end
%Add contribution for stderr and corr params to dRHSxss and dRHSuss
if ~isempty(indpstderr)
for jp = 1:stderrparam_nbr
dzss = [zeros(M.nspred,1);
dghs2(kcurr~=0,jp);
dghs2(klead~=0,jp) + oo.dr.ghx(klead~=0,:)*dghs2(idx_states,jp);
zeros(M.exo_nbr,1)];
dG_x_ss = kron(oo.dr.ghx(idx_states,:),dghs2(idx_states,jp));
dZ_x_ss = kron(zx,dzss);
dRHSxss(:,:,jp) = Fxupup*kron(speye(M.nspred),vec(dSigma_e(:,:,jp)));
dRHSxss(:,:,jp) = dRHSxss(:,:,jp) + fyp_ghxxp*dG_x_ss;
dRHSxss(:,:,jp) = dRHSxss(:,:,jp) + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_x_ss;
dG_u_ss = kron(oo.dr.ghu(idx_states,:),dghs2(idx_states,jp));
dZ_u_ss = kron(zu,dzss);
dRHSuss(:,:,jp) = Fuupup*kron(speye(M.exo_nbr),vec(dSigma_e(:,:,jp)));
dRHSuss(:,:,jp) = dRHSuss(:,:,jp) + fyp_ghxxp*dG_u_ss;
dRHSuss(:,:,jp) = dRHSuss(:,:,jp) + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_u_ss;
end
end
if ~isempty(indpcorr)
for jp = (stderrparam_nbr+1):(stderrparam_nbr+corrparam_nbr)
dzss = [zeros(M.nspred,1);
dghs2(kcurr~=0,jp);
dghs2(klead~=0,jp) + oo.dr.ghx(klead~=0,:)*dghs2(idx_states,jp);
zeros(M.exo_nbr,1)];
dG_x_ss = kron(oo.dr.ghx(idx_states,:),dghs2(idx_states,jp));
dZ_x_ss = kron(zx,dzss);
dRHSxss(:,:,jp) = Fxupup*kron(speye(M.nspred),vec(dSigma_e(:,:,jp)));
dRHSxss(:,:,jp) = dRHSxss(:,:,jp) + fyp_ghxxp*dG_x_ss;
dRHSxss(:,:,jp) = dRHSxss(:,:,jp) + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_x_ss;
dG_u_ss = kron(oo.dr.ghu(idx_states,:),dghs2(idx_states,jp));
dZ_u_ss = kron(zu,dzss);
dRHSuss(:,:,jp) = Fuupup*kron(speye(M.exo_nbr),vec(dSigma_e(:,:,jp)));
dRHSuss(:,:,jp) = dRHSuss(:,:,jp) + fyp_ghxxp*dG_u_ss;
dRHSuss(:,:,jp) = dRHSuss(:,:,jp) + g2(:,k2yy0ex0(kyy0ex0,kyy0ex0))*dZ_u_ss;
end
end
dRHSxss = -dRHSxss;
%use iterated generalized sylvester equation to compute dghxss
dghxss = sylvester3(A,B,oo.dr.ghx(idx_states,:),dRHSxss);
flag = 1; icount = 0;
while flag && icount < 4
[dghxss, flag] = sylvester3a(dghxss,A,B,oo.dr.ghx(idx_states,:),dRHSxss);
icount = icount+1;
end
%Add contribution by dghxss to dRHSuss and compute it
dghuss = zeros(M.endo_nbr,M.exo_nbr,totparam_nbr);
for jp = 1:totparam_nbr
dRHS = dRHSuss(:,:,jp) + B*dghxss(:,:,jp)*oo.dr.ghu(idx_states,:);
dghuss(:,:,jp) = invA* (-dRHS);
end
end
%% Store into structure
DERIVS.dg1 = dg1;
DERIVS.dSigma_e = dSigma_e;
DERIVS.dCorrelation_matrix = dCorrelation_matrix;
DERIVS.dYss = dYss;
DERIVS.dghx = cat(3,zeros(M.endo_nbr,M.nspred,stderrparam_nbr+corrparam_nbr), dghx);
DERIVS.dghu = cat(3,zeros(M.endo_nbr,M.exo_nbr,stderrparam_nbr+corrparam_nbr), dghu);
DERIVS.dOm = dOm;
if order > 1
DERIVS.dg2 = dg2;
DERIVS.dghxx = cat(3,zeros(M.endo_nbr,M.nspred^2,stderrparam_nbr+corrparam_nbr), dghxx);
DERIVS.dghxu = cat(3,zeros(M.endo_nbr,M.nspred*M.exo_nbr,stderrparam_nbr+corrparam_nbr), dghxu);
DERIVS.dghuu = cat(3,zeros(M.endo_nbr,M.exo_nbr^2,stderrparam_nbr+corrparam_nbr), dghuu);
DERIVS.dghs2 = dghs2;
end
if order > 2
DERIVS.dg3 = dg3;
DERIVS.dghxxx = cat(3,zeros(M.endo_nbr,M.nspred^3,stderrparam_nbr+corrparam_nbr), dghxxx);
DERIVS.dghxxu = cat(3,zeros(M.endo_nbr,M.nspred^2*M.exo_nbr,stderrparam_nbr+corrparam_nbr), dghxxu);
DERIVS.dghxuu = cat(3,zeros(M.endo_nbr,M.nspred*M.exo_nbr^2,stderrparam_nbr+corrparam_nbr), dghxuu);
DERIVS.dghuuu = cat(3,zeros(M.endo_nbr,M.exo_nbr^3,stderrparam_nbr+corrparam_nbr), dghuuu);
DERIVS.dghxss = dghxss;
DERIVS.dghuss = dghuss;
end
%% Construct Hessian (wrt all selected parameters) of ghx, and Om=ghu*Sigma_e*ghu'
if d2flag
% Construct Hessian (wrt all selected parameters) of Sigma_e
% note that we only need to focus on (stderr x stderr), (stderr x corr), (corr x stderr) parameters, because derivatives wrt all other second-cross parameters are zero by construction
d2Sigma_e = zeros(M.exo_nbr,M.exo_nbr,totparam_nbr^2); %initialize full matrix, even though we'll reduce it later to unique upper triangular values
% Compute Hessian of Sigma_e wrt (stderr x stderr) parameters
if ~isempty(indp2stderrstderr)
for jp = 1:stderrparam_nbr
for ip = 1:jp
if jp == ip %same stderr parameters
d2Sigma_e(indpstderr(jp),indpstderr(jp),indp2stderrstderr(ip,jp)) = 2;
else %different stderr parameters
if isdiag(M.Sigma_e) == 0 % if there are correlated errors
d2Sigma_e(indpstderr(jp),indpstderr(ip),indp2stderrstderr(ip,jp)) = M.Correlation_matrix(indpstderr(jp),indpstderr(ip));
d2Sigma_e(indpstderr(ip),indpstderr(jp),indp2stderrstderr(ip,jp)) = M.Correlation_matrix(indpstderr(jp),indpstderr(ip)); %symmetry
end
end
end
end
end
% Compute Hessian of Sigma_e wrt (stderr x corr) parameters
if ~isempty(indp2stderrcorr)
for jp = 1:stderrparam_nbr
for ip = 1:corrparam_nbr
if indpstderr(jp) == indpcorr(ip,1) %if stderr is equal to first index of corr parameter, then derivative is equal to stderr of second index
d2Sigma_e(indpstderr(jp),indpcorr(ip,2),indp2stderrcorr(jp,ip)) = sqrt(M.Sigma_e(indpcorr(ip,2),indpcorr(ip,2)));
d2Sigma_e(indpcorr(ip,2),indpstderr(jp),indp2stderrcorr(jp,ip)) = sqrt(M.Sigma_e(indpcorr(ip,2),indpcorr(ip,2))); % symmetry
end
if indpstderr(jp) == indpcorr(ip,2) %if stderr is equal to second index of corr parameter, then derivative is equal to stderr of first index
d2Sigma_e(indpstderr(jp),indpcorr(ip,1),indp2stderrcorr(jp,ip)) = sqrt(M.Sigma_e(indpcorr(ip,1),indpcorr(ip,1)));
d2Sigma_e(indpcorr(ip,1),indpstderr(jp),indp2stderrcorr(jp,ip)) = sqrt(M.Sigma_e(indpcorr(ip,1),indpcorr(ip,1))); % symmetry
end
end
end
end
d2Sigma_e = d2Sigma_e(:,:,indp2tottot2); %focus on upper triangular hessian values only
% Construct nonzero derivatives wrt to t+1, i.e. GAM1=-f_{y^+} in Villemot (2011)
GAM1 = zeros(M.endo_nbr,M.endo_nbr);
GAM1(:,klead~=0,:) = -g1(:,nonzeros(klead));
dGAM1 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dGAM1(:,klead~=0,:) = -dg1(:,nonzeros(klead),:);
indind = ismember(d2g1(:,2),nonzeros(klead));
tmp = d2g1(indind,:);
tmp(:,end)=-tmp(:,end);
d2GAM1 = tmp;
indklead = find(klead~=0);
for j = 1:size(tmp,1)
inxinx = (nonzeros(klead)==tmp(j,2));
d2GAM1(j,2) = indklead(inxinx);
end
% Construct nonzero derivatives wrt to t, i.e. GAM0=f_{y^0} in Villemot (2011)
GAM0 = zeros(M.endo_nbr,M.endo_nbr);
GAM0(:,kcurr~=0,:) = g1(:,nonzeros(kcurr));
dGAM0 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dGAM0(:,kcurr~=0,:) = dg1(:,nonzeros(kcurr),:);
indind = ismember(d2g1(:,2),nonzeros(kcurr));
tmp = d2g1(indind,:);
d2GAM0 = tmp;
indkcurr = find(kcurr~=0);
for j = 1:size(tmp,1)
inxinx = (nonzeros(kcurr)==tmp(j,2));
d2GAM0(j,2) = indkcurr(inxinx);
end
% Construct nonzero derivatives wrt to t-1, i.e. GAM2=-f_{y^-} in Villemot (2011)
% GAM2 = zeros(M.endo_nbr,M.endo_nbr);
% GAM2(:,klag~=0) = -g1(:,nonzeros(klag));
% dGAM2 = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
% dGAM2(:,klag~=0) = -dg1(:,nonzeros(klag),:);
indind = ismember(d2g1(:,2),nonzeros(klag));
tmp = d2g1(indind,:);
tmp(:,end) = -tmp(:,end);
d2GAM2 = tmp;
indklag = find(klag~=0);
for j = 1:size(tmp,1)
inxinx = (nonzeros(klag)==tmp(j,2));
d2GAM2(j,2) = indklag(inxinx);
end
% Construct nonzero derivatives wrt to u_t, i.e. GAM3=-f_{u} in Villemot (2011)
% GAM3 = -g1(:,yy0_nbr+1:end);
% dGAM3 = -dg1(:,yy0_nbr+1:end,:);
cols_ex = yy0_nbr+(1:yy0ex0_nbr);
indind = ismember(d2g1(:,2),cols_ex);
tmp = d2g1(indind,:);
tmp(:,end) = -tmp(:,end);
d2GAM3 = tmp;
for j = 1:size(tmp,1)
inxinx = find(cols_ex==tmp(j,2));
d2GAM3(j,2) = inxinx;
end
clear d2g1 tmp
% Compute Hessian (wrt selected params) of ghx using generalized sylvester equations, see equations 17 and 18 in Ratto and Iskrev (2012)
% solves MM*d2KalmanA+N*d2KalmanA*P = QQ where d2KalmanA are second order derivatives (wrt model parameters) of KalmanA
QQ = zeros(M.endo_nbr,M.endo_nbr,floor(sqrt(modparam_nbr2)));
jcount=0;
cumjcount=0;
jinx = [];
x2x=sparse(M.endo_nbr*M.endo_nbr,modparam_nbr2);
dKalmanA = zeros(M.endo_nbr,M.endo_nbr,modparam_nbr);
dKalmanA(:,idx_states,:) = dghx;
MM = (GAM0-GAM1*KalmanA);
invMM = inv(MM);
for i=1:modparam_nbr
for j=1:i
elem1 = (get_2nd_deriv(d2GAM0,M.endo_nbr,M.endo_nbr,j,i)-get_2nd_deriv(d2GAM1,M.endo_nbr,M.endo_nbr,j,i)*KalmanA);
elem1 = get_2nd_deriv(d2GAM2,M.endo_nbr,M.endo_nbr,j,i)-elem1*KalmanA;
elemj0 = dGAM0(:,:,j)-dGAM1(:,:,j)*KalmanA;
elemi0 = dGAM0(:,:,i)-dGAM1(:,:,i)*KalmanA;
elem2 = -elemj0*dKalmanA(:,:,i)-elemi0*dKalmanA(:,:,j);
elem2 = elem2 + ( dGAM1(:,:,j)*dKalmanA(:,:,i) + dGAM1(:,:,i)*dKalmanA(:,:,j) )*KalmanA;
elem2 = elem2 + GAM1*( dKalmanA(:,:,i)*dKalmanA(:,:,j) + dKalmanA(:,:,j)*dKalmanA(:,:,i));
jcount=jcount+1;
jinx = [jinx; [j i]];
QQ(:,:,jcount) = elem1+elem2;
if jcount==floor(sqrt(modparam_nbr2)) || (j*i)==modparam_nbr^2
if (j*i)==modparam_nbr^2
QQ = QQ(:,:,1:jcount);
end
xx2=sylvester3(MM,-GAM1,KalmanA,QQ);
flag=1;
icount=0;
while flag && icount<4
[xx2, flag]=sylvester3a(xx2,MM,-GAM1,KalmanA,QQ);
icount = icount + 1;
end
x2x(:,cumjcount+1:cumjcount+jcount)=reshape(xx2,[M.endo_nbr*M.endo_nbr jcount]);
cumjcount=cumjcount+jcount;
jcount = 0;
jinx = [];
end
end
end
clear xx2;
jcount = 0;
icount = 0;
cumjcount = 0;
MAX_DIM_MAT = 100000000;
ncol = max(1,floor(MAX_DIM_MAT/(8*M.endo_nbr*(M.endo_nbr+1)/2)));
ncol = min(ncol, totparam_nbr2);
d2KalmanA = sparse(M.endo_nbr*M.endo_nbr,totparam_nbr2);
d2Om = sparse(M.endo_nbr*(M.endo_nbr+1)/2,totparam_nbr2);
d2KalmanA_tmp = zeros(M.endo_nbr*M.endo_nbr,ncol);
d2Om_tmp = zeros(M.endo_nbr*(M.endo_nbr+1)/2,ncol);
tmpDir = CheckPath('tmp_derivs',M.dname);
offset = stderrparam_nbr+corrparam_nbr;
% d2B = zeros(m,n,tot_param_nbr,tot_param_nbr);
for j=1:totparam_nbr
for i=1:j
jcount=jcount+1;
if j<=offset %stderr and corr parameters
y = KalmanB*d2Sigma_e(:,:,jcount)*KalmanB';
d2Om_tmp(:,jcount) = dyn_vech(y);
else %model parameters
jind = j-offset;
iind = i-offset;
if i<=offset
y = dghu(:,:,jind)*dSigma_e(:,:,i)*KalmanB'+KalmanB*dSigma_e(:,:,i)*dghu(:,:,jind)';
% y(abs(y)<1.e-8)=0;
d2Om_tmp(:,jcount) = dyn_vech(y);
else
icount=icount+1;
dKalmanAj = reshape(x2x(:,icount),[M.endo_nbr M.endo_nbr]);
% x = get_2nd_deriv(x2x,m,m,iind,jind);%xx2(:,:,jcount);
elem1 = (get_2nd_deriv(d2GAM0,M.endo_nbr,M.endo_nbr,iind,jind)-get_2nd_deriv(d2GAM1,M.endo_nbr,M.endo_nbr,iind,jind)*KalmanA);
elem1 = elem1 -( dGAM1(:,:,jind)*dKalmanA(:,:,iind) + dGAM1(:,:,iind)*dKalmanA(:,:,jind) );
elemj0 = dGAM0(:,:,jind)-dGAM1(:,:,jind)*KalmanA-GAM1*dKalmanA(:,:,jind);
elemi0 = dGAM0(:,:,iind)-dGAM1(:,:,iind)*KalmanA-GAM1*dKalmanA(:,:,iind);
elem0 = elemj0*dghu(:,:,iind)+elemi0*dghu(:,:,jind);
y = invMM * (get_2nd_deriv(d2GAM3,M.endo_nbr,M.exo_nbr,iind,jind)-elem0-(elem1-GAM1*dKalmanAj)*KalmanB);
% d2B(:,:,j+length(indexo),i+length(indexo)) = y;
% d2B(:,:,i+length(indexo),j+length(indexo)) = y;
y = y*M.Sigma_e*KalmanB'+KalmanB*M.Sigma_e*y'+ ...
dghu(:,:,jind)*M.Sigma_e*dghu(:,:,iind)'+dghu(:,:,iind)*M.Sigma_e*dghu(:,:,jind)';
% x(abs(x)<1.e-8)=0;
d2KalmanA_tmp(:,jcount) = vec(dKalmanAj);
% y(abs(y)<1.e-8)=0;
d2Om_tmp(:,jcount) = dyn_vech(y);
end
end
if jcount==ncol || i*j==totparam_nbr^2
d2KalmanA(:,cumjcount+1:cumjcount+jcount) = d2KalmanA_tmp(:,1:jcount);
% d2KalmanA(:,:,j+length(indexo),i+length(indexo)) = x;
% d2KalmanA(:,:,i+length(indexo),j+length(indexo)) = x;
d2Om(:,cumjcount+1:cumjcount+jcount) = d2Om_tmp(:,1:jcount);
% d2Om(:,:,j+length(indexo),i+length(indexo)) = y;
% d2Om(:,:,i+length(indexo),j+length(indexo)) = y;
save([tmpDir filesep 'd2KalmanA_' int2str(cumjcount+1) '_' int2str(cumjcount+jcount) '.mat'],'d2KalmanA')
save([tmpDir filesep 'd2Om_' int2str(cumjcount+1) '_' int2str(cumjcount+jcount) '.mat'],'d2Om')
cumjcount = cumjcount+jcount;
jcount=0;
% d2KalmanA = sparse(m1*m1,tot_param_nbr*(tot_param_nbr+1)/2);
% d2Om = sparse(m1*(m1+1)/2,tot_param_nbr*(tot_param_nbr+1)/2);
d2KalmanA_tmp = zeros(M.endo_nbr*M.endo_nbr,ncol);
d2Om_tmp = zeros(M.endo_nbr*(M.endo_nbr+1)/2,ncol);
end
end
end
%Store into structure
DERIVS.d2Yss = d2Yss;
DERIVS.d2KalmanA = d2KalmanA;
DERIVS.d2Om = d2Om;
end
return
%% AUXILIARY FUNCTIONS %%
%%%%%%%%%%%%%%%%%%%%%%%%%
function g22 = get_2nd_deriv(gpp,m,n,i,j)
% inputs:
% - gpp: [#second_order_Jacobian_terms by 5] double Hessian matrix (wrt parameters) of a matrix
% rows: respective derivative term
% 1st column: equation number of the term appearing
% 2nd column: column number of variable in Jacobian
% 3rd column: number of the first parameter in derivative
% 4th column: number of the second parameter in derivative
% 5th column: value of the Hessian term
% - m: scalar number of equations
% - n: scalar number of variables
% - i: scalar number for which first parameter
% - j: scalar number for which second parameter
g22=zeros(m,n);
is=find(gpp(:,3)==i);
is=is(find(gpp(is,4)==j));
if ~isempty(is)
g22(sub2ind([m,n],gpp(is,1),gpp(is,2)))=gpp(is,5)';
end
return
function g22 = get_2nd_deriv_mat(gpp,i,j,npar)
% inputs:
% - gpp: [#second_order_Jacobian_terms by 5] double Hessian matrix of (wrt parameters) of dynamic Jacobian
% rows: respective derivative term
% 1st column: equation number of the term appearing
% 2nd column: column number of variable in Jacobian of the dynamic model
% 3rd column: number of the first parameter in derivative
% 4th column: number of the second parameter in derivative
% 5th column: value of the Hessian term
% - i: scalar number for which model equation
% - j: scalar number for which variable in Jacobian of dynamic model
% - npar: scalar Number of model parameters, i.e. equals M.param_nbr
%
% output:
% g22: [npar by npar] Hessian matrix (wrt parameters) of Jacobian of dynamic model for equation i
% rows: first parameter in Hessian
% columns: second paramater in Hessian
g22=zeros(npar,npar);
is=find(gpp(:,1)==i);
is=is(find(gpp(is,2)==j));
if ~isempty(is)
g22(sub2ind([npar,npar],gpp(is,3),gpp(is,4)))=gpp(is,5)';
end
return
function r22 = get_all_resid_2nd_derivs(rpp,m,npar)
% inputs:
% - rpp: [#second_order_residual_terms by 4] double Hessian matrix (wrt paramters) of model equations
% rows: respective derivative term
% 1st column: equation number of the term appearing
% 2nd column: number of the first parameter in derivative
% 3rd column: number of the second parameter in derivative
% 4th column: value of the Hessian term
% - m: scalar Number of residuals (or model equations), i.e. equals M.endo_nbr
% - npar: scalar Number of model parameters, i.e. equals M.param_nbr
%
% output:
% r22: [M.endo_nbr by M.param_nbr by M.param_nbr] Hessian matrix of model equations with respect to parameters
% rows: equations in order of declaration
% 1st columns: first parameter number in derivative
% 2nd columns: second parameter in derivative
r22=zeros(m,npar,npar);
for is=1:size(rpp,1)
% Keep symmetry in hessian, hence 2 and 3 as well as 3 and 2, i.e. d2f/(dp1 dp2) = d2f/(dp2 dp1)
r22(rpp(is,1),rpp(is,2),rpp(is,3))=rpp(is,4);
r22(rpp(is,1),rpp(is,3),rpp(is,2))=rpp(is,4);
end
return
function h2 = get_hess_deriv(hp,i,j,m,npar)
% inputs:
% - hp: [#first_order_Hessian_terms by 5] double Jacobian matrix (wrt paramters) of dynamic Hessian
% rows: respective derivative term
% 1st column: equation number of the term appearing
% 2nd column: column number of first variable in Hessian of the dynamic model
% 3rd column: column number of second variable in Hessian of the dynamic model
% 4th column: number of the parameter in derivative
% 5th column: value of the Hessian term
% - i: scalar number for which model equation
% - j: scalar number for which first variable in Hessian of dynamic model variable
% - m: scalar Number of dynamic model variables + exogenous vars, i.e. yy0_nbr + M.exo_nbr
% - npar: scalar Number of model parameters, i.e. equals M.param_nbr
%
% output:
% h2: [(yy0_nbr + M.exo_nbr) by M.param_nbr] Jacobian matrix (wrt parameters) of dynamic Hessian
% rows: second dynamic or exogenous variables in Hessian of specific model equation of the dynamic model
% columns: parameters
h2=zeros(m,npar);
is1=find(hp(:,1)==i);
is=is1(find(hp(is1,2)==j));
if ~isempty(is)
h2(sub2ind([m,npar],hp(is,3),hp(is,4)))=hp(is,5)';
end
return