dynare/matlab/get_first_order_solution_pa...

959 lines
54 KiB
Matlab
Raw Normal View History

Improvement of Identification Toolbox # Improvements * heavily commented (also auxiliary functions) and changed notation to make all the functions (hopefully) more readable and understandable, and hence, easier to debug * added identification criteria of Komunjer and Ng (2011, Econometrica) and Qu and Tkachenko (2012, Quantitative Economics) * tests can be turned of, i.e. nostrength disables identification strenght, noreducedform disables reduced form criteria, nomoments disables moment criteria, nospectrum disables spectrum criteria, nominimal disables minimal system criteria * all kronflags (analytic_derivation_mode) actually work in all functions * added functionality when there is correlation in Sigma_e and when one wants to consider corr parameters of exogenous shocks. Previously, (1) corr parameters were not allowed when calling identification and (2) when Sigma_e was not diagonal then the toolbox relied on numerical derviatives only (kronflag=-1). Now it is possible to handle both identification of corr parameters as well as correct analytical derivatives when Sigma_e is not diagonal with all possible kronflag values (-1|-2|0|1) * all plots and results are stored in the same folder named identification (previously there was another one with a capital I (Identification)) # Needed changes to preprocessor * add as field to options_ident: - tex (same as in options_) - nostrength (to turn off identification strength) - noreducedform (to turn off reduced form criteria) - nomoments (to turn off Iskrev's moment criteria) - nominimal (to turn off Komunjer and Ng's minimal system criteria) - nospectrum (to turn off Qu and Tkachenko's spectrum criteria) * add to options_ident: - normalize_jacobians (whether to normalize Jacobians or not) - grid_nbr (integer used to discretize the interval [-pi;pi] - tol_rank (tolerance level to compute ranks) - tol_deriv (tolerance level to select nonzero columns in derivatives) - tol_sv (tolerance level to select nonzero singular values) - ChecksViaSubsets (for debugging purposes, uses different function to find problematic parameter sets) - max_dim_subsets_groups (for debugging purposes, used for ChecksViaSubsets) # Further Suggestions * Rename getH.m into getParamsDerivReducedForm.m to make the purpose of this function evident * Rename getJJ.m into getIdentificationJacobians.m to make the purpose of this function evident * Rename thet2tau.m into IdentificationNumericalObjectiveFunction.m to make the purpose of this function evident * dYss, d2Yss, dg1 should also include derivatives wrt to stderr and corr parameters (even though these are just 0), as in other functions (getJJ, dynare_estimation) we always add these manually * I am pretty sure the current handling in getH.m of dYss and d2Yss is not correct in the case of nonstationary variables (if g2static is nonempty), I added a warning message, as I am not sure whether this is ever used * It would be straigthforward to also include stderr and corr parameters of measurement errors (these is not possible right now). Should I do this? * Computations of d2A and d2Om need to be checked, as the differences between computing these with analytically (kronflag=0|1) or numerically kronflag=-1|-2 is really large for the example model of AnSchorfheide. * I am not sure how to best normalize Qu and Tkachenko's G matrix. It looks (and in the Gaussian case actually is) very similar to the Ahess matrix. So I used the same normalization rule as for the Ahess matrix. See comments in identification_checks.m. Anyone has a better idea? Please also check the models in test/identification/cgg for differences. * parts that are unclear to me are marked by a [@wmutschl] tag * the run time of tests/identification/as2007.mod increases from 0h01m27s to 0h03m46s (as Qu and Tkachenko's G matrix takes a little while to compute). One could decrease prior_mc=250 to prior_mc=150. # New functions * commutation: Returns Magnus and Neudecker's commutation matrix that solves k*vec(X)=vec(X') * DerivABCD: Derivative of X(p)=A(p)*B(p)*C(p)*D(p) w.r.t to p as in Magnus and Neudecker (1999), p. 175 * DeriveMinimalState: Derives minimal state space system by checking observability and controllability of all possible combinations of variables * duplication: Duplication Matrix (and its Moore Penrose Inverse) as defined by Magnus and Neudecker (2002), p.49, Dp*vec(X) = X * identification_checks_via_subsets: finds problematic parameters in a bruteforce fashion: It computes the rank of the Jacobians for all possible parameter combinations, if the rank condition is not fullfilled, these parameter sets are flagged as non-identifiable. For debugging purposes only, as the current identification_checks.m (based on nullspace and multicorrelation coefficients) is much faster # Detailed changes in getH.m * functionality improvements - heavily commented (also auxiliary functions) and changed notation of several variables to make this function (hopefully) more readable and understandable, and hence, easier to debug - added functionality when Sigma_e is not diagonal and/or when one wants to consider corr parameters of exogenous shocks independent of the value of kronflag - fixed function for all values of kronflag, i.e. kronflag=-2|-1|0|1. Previosuly, only kronflag=-2|0 were working, all other kronflags ran into errors (-1 was actually never called , but was dealt with in getJJ.m). I assume kronflag=-1|1 was used only for debugging issues, but still was not working. I fixed this now, the function now works out-of-the-box for all kronflag values. - I also outlined and documented what each kronflag does and point to the corresponding equations in Ratto and Iskrev (2012) or Iskrev (2010,Appendix A) - the function additionally outputs the Jacobians of B and Sig, which are needed for Qu and Tkachenko (2012) and Komunjer and Ng (2011)'s criteria - Moved computation of Jacobian of tau=[ys;vec(A);vech(B * M_.Sigma_e * B')] into getJJ.m to have all Jacobians which are needed for identification in one place. That is, getH.m computes first and second parameter derivatives of (1) reduced-form solution, (2) steady state and (3) Jacobian of dynamic model, whereas getJJ computes and sets up all Jacobians which are used for identification purposes. Therefore, getH might be useful more generally for other purposes than identification. For instance, when doing a GMM estimation, we could use this function to compute analytically the gradient of the moments and provide this to the optimizer used in a GMM context. * output arguments - renamed `H` (Jacobian wrt parameters of tau=[ys;vec(A);vech(B * M_.Sigma_e * B')] into dTAU, (as H is very confusing, e.g. in other functions it is a Hessian, or Hss and H2ss is also just the steady state. Morevoer, tau is used in Iskrev(2010) for the steady state and reduced-form solution) - renamed `Hss` (Jacobian of steady state wrt model parameters only) into `dYss` (as H is very confusing here, see above) - renamed `H2ss` (Hessian wrt model parameters only of ys) into d2Yss (as H is very confusing, see above) - renamed `gp` into `dg1`, where g1 corresponds to the same variable as in dynamic model files. Note that in params_deriv files gp lacks the contribution of Jacobian wrt steady state and dg1 includes this using the implicit function theorem as outlined in Ratto and Iskrev (2012). Hence, dg1 denotes Jacobian wrt to parameters. It is useful and important to distinguish gp and dg1. - added `dB` (Jacobian wrt parameters of solution matrix B) needed for Qu and Tkachenko (2012) as well as Komunjer and Ng (2011) - added `dSig` (Jacobian wrt parameters of M_.Sigma_e) needed for Qu and Tkachenko (2012) as well as Komunjer and Ng (2011) * input arguments - renamed `indx` (index of model parameters to be checked) into `indpmodel`, the p makes it more clear that this is a parameter index - renamed `indexo` (index of stderr parameters) into `indpstderr`, the p makes it more clear that this is a parameter index - renamed `iv` (index of variables to consider) into `indvar` - Renamed `M_` to `M`, `estim_params_` to `estim_params`, `options_` to `options` , `oo_` to `oo` to visualize that these are local and not global variables - included `indpcorr` a matrix of indices for corr parameters to be checked * misc - distinguished clearly between variables in DR or in declaration order without overwriting this in between - added which functions call getH.m - updated copyright to 2010-2019 # Detailed changes in getJJ.m * functionality improvements - heavily commented and changed notation of several variables to make this function (hopefully) more readable and understandable, and hence, easier to debug - added functionality when Sigma_e is not diagonal and/or when one wants to consider corr parameters of exogenous shocks independent of the value of kronflag - tidied the function up, such that it sets up all Jacobians which are needed for identification, i.e. Iskrev's J matrix, Qu and Tkachenko (2012)'s G matrix, Komunjer and Ng (2011)'s D matrix, reduced-form solution (dTAU), linear rational expectation (i.e. Jacobian of steady state and dynamic model equations dLRE). - dTAU is now constructed in getJJ instead of in getH (see comment above in getH.m) - works for all kronflags, i.e. for numerical derivatives (-1 and -2) as well as for analytical derivatives based on kronecker products (1) or Sylvester Equations (0) - added functionality for stderr and corr parameters independent of the value of kronflag (previously this was only possible with numerical derivatives, now it works for all kronflags) - finds minimal state vector needed for Komunjer and Ng (2011)'s criteria (function `DeriveMinimalState.m`) - moved computations from kronflag=-1 (which were used in case of corr in shock block) into getH.m, so that getJJ now only sets up the Jacobians for LRE, Iskrev's J, Qu and Tkachenko's G and Komunjer and Ng's D, whereas getH computes the Jacobians (wrt parameters) of A, B, Sigma_e, Om, Yss and g1. This should simplify debugging as everything is now in one place and not in two * output arguments - renamed `JJ` into `J` - renamed `H` into `dTAU` (as H is very confusing, e.g. in other functions it is a Hessian, or Hss and H2ss is also just the steady state. Morevoer, tau is used in Iskrev(2010) for the steady state and reduced-form solution) - renamed `gp` into `dLRE`, as this corresponds to Jacobian of LRE=[Yss;vec(g1)] where g1 is the Jacobian of the dynamic model equations. - renamed `gam` into `MOMENTS` - added `G` for Qu and Tkachenko's Jacobian matrix G - added `D` for Komunjer and Ng's Jacobian matrix D - reordered output arguments * input arguments - added `options_ident` as input argument; hence, `kronflag`, `nlags` and `useautocorr` are removed from input arguments as these are available in options_ident - Renamed `M_` to `M`, `estim_params_` to `estim_params`, `options_` to `options` , `oo_` to `oo` to visualize that these are local and not global variables - renamed `indx` (index of model parameters to be checked) into `indpmodel`, the p makes it more clear that this is a parameter index - renamed `indexo` (index of stderr parameters) into `indpstderr`, the p makes it more clear that this is a parameter index - added `indpcorr` (index of corr parameters) - renamed `mf` (index of VAROBS variables) into `indvobs` * misc - updated copyright to 2010-2019 - provided some comments on several ways to compute the spectral density matrix - added which functions call getJJ.m # Detailed changes in thet2tau.m * functionality improvements - heavily commented and changed notation of several variables to make this function (hopefully) more readable and understandable, and hence, easier to debug - Added output option to compute spectral density matrix - Reorded and added some output option. - Instead of Om, `outputflag=0` computes B and Sigma_e, which are needed for Qu and Tkachenko as well as Komunjer and Ng. The Jacobian of Om is then computed in getJJ or getH from Jacobian of B and Sigma_e. Due to some testing with An and Schorfheide model this seems to be more accurate when I compare these with the analytical derivatives. The old behavior (computing Om directly) can be restored by setting `outputflag=-2`. - In total this function can now be used to compute numerically Jacobians of Yss, A, B, Sigma_e, Om, g1, autocovariogram and spectral density - Clearly distinguished (and commented) on the different outputs of this function. - Works for all types of parameters, ie. model, stderr and corr. - This function can now also be used when there is no estimated_params block. Previously, there was an error when there was no estimated_params block when calling `set_all_parameters` as this requires some information in `estim_params`. I fixed this by providing a temporary local estim_parms structure with the necessary information on model, stderr and corr parameters. In this way, this can be easily extended to also include stderr and corr parameters of measurement errors. * output arguments - renamed `tau` into `out`, as this function computes *very* different things (and not only tau) depending on an input flag * input arguments - renamed `flagmoments` into `outputflag` as this function does not only compute moments but many other things (see above) - renamed `indx` (index of model parameters to be checked) into `indpmodel`, the p makes it more clear that this is a parameter index - renamed `indexo` (index of stderr parameters) into `indpstderr`, the p makes it more clear that this is a parameter index - added `indpcorr` (index of corr parameters) - merged `mf` (index of observable variables) and `iv` (index of variables to consider) into a single index `indvar` as there is no need to distinguish between these two indices (they were never used in combination) - added `grid_nbr` (number of grid points to compute spectral density) - reordered input arguments * misc - added which functions call thet2tau - updated copyright to 2010-2019 # Detailed changes in identification_analysis.m * functionality improvements - heavily commented and changed notation of several variables to make this function (hopefully) more readable and understandable, and hence, easier to debug - renamed `dg1` to `dLRE`, renamed `vecg1` to `lre`, renamed `H` to `dTAU` (see comments above) - added option `numzerotolderiv` with default `1.e-8` used for non-zero derivatives - added option `numzerotolrank` with default `1.e-10` used for rank computations - added theoretical identification analysis based on Komunjer and Ng (2011)'s method, i.e. steady state and observational equivalent spectral densities within a minimal system - added theoretical identification analysis based on Qu and Tkachenko (2012)'s method, i.e. steady state and spectral density - restructured the code slightly to combined chunks of code that belong together on the one hand, and on the other hand to differentiate between the different criteria - added call to new function `identification_checks_via_subsets.m` (see above for the definition of the functionality) to perform identification checks differently as find it more intuitive and (most likely) more precise. * input arguments - removed `bounds` and `dataset_` as input argument, because these are not needed - moved `name_tex` and `tittxt` into `options_ident` as these two inputs are only used in `ident_bruteforce.m` and already set in `dynare_identification.m` * output arguments - added `ide_spectrum` structure for Qu and Tkachenko's criteria based on the spectral density - added `ide_minimal` structure for Komunjer and Ng's criteria based on the minimal state space system - reordered output arguments * misc - added which functions call identification_analysis - updated copyright to 2010-2019 # Detailed changes in dynare_identification.m * functionality improvements - heavily commented and changed notation of several variables to make this function (hopefully) more readable and understandable, and hence, easier to debug - included more options (and default values) which can be set by the user, i.e. nostrength, nomoments, nominimal, nospectrum, tex, tol_rank, tol_deriv, tol_sv, grid_nbr, ChecksViaSubsets, max_dim_subsets_group - instead of turning warnings globally off, I specified the relevant warnings for matlab and octave, respectively, off - improved the warning messages slightly - restructured chunks of code with respect to different criteria * output arguments - renamed arguments: TAU to STO_TAU, GAM to STO_MOMENTS, LRE to STO_LRE, gp to STO_si_dLRE, H to STO_si_dTAU, JJ to STO_si_J - added arguments: STO_G and STO_D for the two new criteria * misc - added which functions call dynare_identification - updated copyright to 2010-2019 # Detailed changes in identification_checks.m * functionality improvements - added checks for Komunjer and Ng's D matrix. Note that the Jacobian D=[D_par D_rest], where D_par depends on the parameters and D_rest does not. So this is taken into account. - added checks for Qu and Tkachenko's G matrix. Note that the Jacobian G is a Gram matrix with dimension nparam x nparam, similar to Ahess. So this is taken into account. I am, however, not sure whether this is correct regarding the multicorrelation and pairwise correlation coefficients. Please double check. - the rank is now actually computed at the prespecified tolerance level (and not Matlab's default level), so this is in accordance to the further analysis of problematic parameter sets * output arguments - added the rank to output arguments which is later also displayed - replaced the J or JJ part in the variable names with X as this function is used for all sorts of Jacobians, not only Iskrev's J * input arguments - renamed hess_flag to output_flag (and clearly outlined what each value does) - added tol_rank and tol_sv as input arguments, such that the tolerance levels can be changed by the user and not preimplemented in this function - added param_nbr which is needed for Komunjer and Ng's D matrix * misc - updated copyright to 2010-2019 # Detailed changes in ident_bruteforce.m * functionality improvements - the output directory was set with a capital I, i.e. Identification, whereas in all other functions we rely on lower case i, i.e. identification. I changed this to lower-cases, so everything is now saved in the same folder. - changed displayed strings to be more precise with the corresponding papers and notation * input arguments - renamed `n` to `max_dim_cova_group` to name options the same across functions - renamed `pnames_TeX` to `name_tex` to name options the same across functions - added `tol_deriv` as tolerance level which can be changed by the user * misc - Added some comments - updated copyright to 2010-2019 # Detailed changes in disp_identification.m * functionality improvements - this function displays the same output for different Jacobians, hence I put the common code into a for loop. This should simplify changing the output that is printed to the console. Previously the code was simply repeated for the different criteria and only the strings changed. - some settings relevant for the computation are now printed as a summary to the console - the tolerance level, rank and required rank are always displayed on the command line to see how many problematic sets there are and which tolerance level was used - the function is also able to display problematic parameters computed by the new function `identification_checks_via_subsets.m` which is only used for debugging. * input arguments - added `idespectrum` structure for analysis based on Qu and Tkachenko - added `ideminimal` structure for analysis based on Komunjer and Ng - added `options_ident` to have all necessary settings in a structure * misc - Added some comments - Removed uncommented code that was not used as this was redundant and probably an artifact of the original programming?! - updated copyright to 2010-2019 # Detailed changes in dsge_likelihood.m * misc - adjusted call of getH due to changes of input and output arguments - updated copyright to 2010-2019 # Detailed changes in cosn.m * misc - commented functionality, input and output arguments of this function - updated copyright to 2010-2019
2019-03-20 16:44:54 +01:00
function [dA, dB, dSigma_e, dOm, dYss, dg1, d2A, d2Om, d2Yss] = get_first_order_solution_params_deriv(A, B, estim_params, M, oo, options, kronflag, indpmodel, indpstderr, indpcorr, indvar)
%[dA, dB, dSigma_e, dOm, dYss, dg1, d2A, d2Om, d2Yss] = get_first_order_solution_params_deriv(A, B, estim_params, M, oo, options, kronflag, indpmodel, indpstderr, indpcorr, indvar)
% previously getH.m
% -------------------------------------------------------------------------
% Computes first and second derivatives (with respect to parameters) of
% (1) reduced-form solution (dA, dB, dSigma_e, dOm, d2A, d2Om)
% (1) steady-state (dYss, d2Yss)
% (3) Jacobian (wrt to dynamic variables) of dynamic model (dg1)
% Note that the order in the parameter Jacobians is the following:
% first stderr parameters, second corr parameters, third model parameters
% =========================================================================
% INPUTS
% A: [endo_nbr by endo_nbr] Transition matrix from Kalman filter
% for all endogenous declared variables, in DR order
% B: [endo_nbr by exo_nbr] Transition matrix from Kalman filter
% mapping shocks today to endogenous variables today, in DR order
% estim_params: [structure] storing the estimation information
% M: [structure] storing the model information
% oo: [structure] storing the reduced-form solution results
% options: [structure] storing the options
% kronflag: [scalar] method to compute Jacobians (equal to analytic_derivation_mode in options_ident). Default:0
% * 0: efficient sylvester equation method to compute
% analytical derivatives as in Ratto & Iskrev (2011)
% * 1: kronecker products method to compute analytical
% derivatives as in Iskrev (2010)
% * -1: numerical two-sided finite difference method to
% compute numerical derivatives of all output arguments
% using function identification_numerical_objective.m
% (previously thet2tau.m)
% * -2: numerical two-sided finite difference method to
% compute numerically dYss, dg1, d2Yss and d2g1, the other
% output arguments are computed analytically as in kronflag=0
% 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; if estimated_params block is
% not available, then all model parameters are selected
% 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; if estimated_params block
% is not available, then all stderr parameters are selected
% indpcorr: [corrparam_nbr by 2] matrix of estimated correlations,
% i.e. for all exogenous variables where "corr" is given
% in the estimated_params block; if estimated_params block
% is not available, then no corr parameters are selected
% indvar: [var_nbr by 1] index of considered (or observed) variables
% -------------------------------------------------------------------------
% OUTPUTS
% dA: [var_nbr by var_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of transition matrix A
% dB: [var_nbr by exo_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all parameters) of transition matrix B
% dSigma_e: [exo_nbr by exo_nbr by totparam_nbr] in declaration order
% Jacobian (wrt to all paramters) of M_.Sigma_e
% dOm: [var_nbr by var_nbr by totparam_nbr] in DR order
% Jacobian (wrt to all paramters) of Om = (B*M_.Sigma_e*B')
% dYss: [var_nbr by modparam_nbr] in DR order
% Jacobian (wrt model parameters only) of steady state
% dg1: [endo_nbr by (dynamicvar_nbr + exo_nbr) by modparam_nbr] in DR order
% Jacobian (wrt to model parameters only) of Jacobian of dynamic model
% d2A: [var_nbr*var_nbr by totparam_nbr*(totparam_nbr+1)/2] in DR order
% Unique entries of Hessian (wrt all parameters) of transition matrix A
% d2Om: [var_nbr*(var_nbr+1)/2 by totparam_nbr*(totparam_nbr+1)/2] in DR order
% Unique entries of Hessian (wrt all parameters) of Omega
% d2Yss: [var_nbr by modparam_nbr by modparam_nbr] in DR order
% Unique entries of Hessian (wrt model parameters only) of steady state
% -------------------------------------------------------------------------
% This function is called by
% * dsge_likelihood.m
% * get_identification_jacobians.m (previously getJJ.m)
% -------------------------------------------------------------------------
% 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
% * identification_numerical_objective.m (previously thet2tau.m)
% =========================================================================
% Copyright (C) 2010-2019 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/>.
% =========================================================================
fname = M.fname;
dname = M.dname;
maximum_exo_lag = M.maximum_exo_lag;
maximum_exo_lead = M.maximum_exo_lead;
maximum_endo_lag = M.maximum_endo_lag;
maximum_endo_lead = M.maximum_endo_lead;
lead_lag_incidence = M.lead_lag_incidence;
[I,~] = find(lead_lag_incidence'); %I is used to select nonzero columns of the Jacobian of endogenous variables in dynamic model files
ys = oo.dr.ys; %steady state of endogenous variables in declaration order
yy0 = oo.dr.ys(I); %steady state of dynamic (endogenous and auxiliary variables) in DR order
ex0 = oo.exo_steady_state'; %steady state of exogenous variables in declaration order
params0 = M.params; %values at which to evaluate dynamic, static and param_derivs files
Sigma_e0 = M.Sigma_e; %covariance matrix of exogenous shocks
Corr_e0 = M.Correlation_matrix; %correlation matrix of exogenous shocks
stderr_e0 = sqrt(diag(Sigma_e0)); %standard errors of exogenous shocks
param_nbr = M.param_nbr; %number of all declared model parameters in mod file
modparam_nbr = length(indpmodel); %number of model parameters to be used
stderrparam_nbr = length(indpstderr); %number of stderr parameters to be used
corrparam_nbr = size(indpcorr,1); %number of stderr parameters to be used
totparam_nbr = modparam_nbr + stderrparam_nbr + corrparam_nbr; %total number of parameters to be used
if nargout > 6
modparam_nbr2 = modparam_nbr*(modparam_nbr+1)/2; %number of unique entries of model parameters only in second-order derivative matrix
totparam_nbr2 = totparam_nbr*(totparam_nbr+1)/2; %number of unique entries of all 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
end
endo_nbr = size(A,1); %number of all declared endogenous variables
var_nbr = length(indvar); %number of considered variables
exo_nbr = size(B,2); %number of exogenous shocks in model
if kronflag == -1
% numerical two-sided finite difference method using function identification_numerical_objective.m (previously thet2tau.m) for Jacobian (wrt parameters) of A, B, Sig, Om, Yss, and g1
para0 = get_all_parameters(estim_params, M); %get all selected parameters in estimated_params block, stderr and corr come first, then model parameters
if isempty(para0)
%if there is no estimated_params block, consider all stderr and all model parameters, but no corr parameters
para0 = [stderr_e0', params0'];
end
%Jacobians (wrt paramters) of steady state, solution matrices A and B, as well as Sigma_e for ALL variables [outputflag=0]
dYssABSige = fjaco('identification_numerical_objective', para0, 0, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvar);
M.params = params0; %make sure values are set back
M.Sigma_e = Sigma_e0; %make sure values are set back
M.Correlation_matrix = Corr_e0 ; %make sure values are set back
% get Jacobians for Yss, A, and B from dYssABSige
indYss = 1:var_nbr;
indA = (var_nbr+1):(var_nbr+var_nbr^2);
indB = (var_nbr+var_nbr^2+1):(var_nbr+var_nbr^2+var_nbr*exo_nbr);
indSigma_e = (var_nbr+var_nbr^2+var_nbr*exo_nbr+1):(var_nbr+var_nbr^2+var_nbr*exo_nbr+exo_nbr*(exo_nbr+1)/2);
dYss = dYssABSige(indYss , stderrparam_nbr+corrparam_nbr+1:end); %in tensor notation only wrt model parameters
dA = reshape(dYssABSige(indA , :) , [var_nbr var_nbr totparam_nbr]); %in tensor notation
dB = reshape(dYssABSige(indB , :) , [var_nbr exo_nbr totparam_nbr]); %in tensor notation
dOm = zeros(var_nbr,var_nbr,totparam_nbr); %initialize in tensor notation
dSigma_e = zeros(exo_nbr,exo_nbr,totparam_nbr); %initialize in tensor notation
% get Jacobians of Sigma_e and Om wrt stderr parameters
if ~isempty(indpstderr)
for jp=1:stderrparam_nbr
dSigma_e(:,:,jp) = dyn_unvech(dYssABSige(indSigma_e , jp));
dOm(:,:,jp) = B*dSigma_e(:,:,jp)*B'; %note that derivatives of B wrt stderr parameters are zero by construction
end
end
% get Jacobians of Sigma_e and Om wrt corr parameters
if ~isempty(indpcorr)
for jp=1:corrparam_nbr
dSigma_e(:,:,stderrparam_nbr+jp) = dyn_unvech(dYssABSige(indSigma_e , stderrparam_nbr+jp));
dOm(:,:,stderrparam_nbr+jp) = B*dSigma_e(:,:,stderrparam_nbr+jp)*B'; %note that derivatives of B wrt corr parameters are zero by construction
end
end
% get Jacobian of Om wrt model parameters
if ~isempty(indpmodel)
for jp=1:modparam_nbr
dOm(:,:,stderrparam_nbr+corrparam_nbr+jp) = dB(:,:,stderrparam_nbr+corrparam_nbr+jp)*Sigma_e0*B' + B*Sigma_e0*dB(:,:,stderrparam_nbr+corrparam_nbr+jp)'; %note that derivatives of Sigma_e wrt model parameters are zero by construction
end
end
%Jacobian (wrt model parameters ONLY) of steady state and of Jacobian of all dynamic model equations [outputflag=-1]
dYssg1 = fjaco('identification_numerical_objective', params0(indpmodel), -1, estim_params, M, oo, options, indpmodel, [], [], (1:endo_nbr)');
M.params = params0; %make sure values are set back
M.Sigma_e = Sigma_e0; %make sure values are set back
M.Correlation_matrix = Corr_e0 ; %make sure values are set back
dg1 = reshape(dYssg1(endo_nbr+1:end,:),[endo_nbr, length(yy0)+length(ex0), modparam_nbr]); %get rid of steady state and in tensor notation
if nargout > 6
%Hessian (wrt paramters) of steady state, solution matrices A and Om [outputflag=-2]
% 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
d2YssAOm = hessian_sparse('identification_numerical_objective', para0', options.gstep, -2, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvar);
M.params = params0; %make sure values are set back
M.Sigma_e = Sigma_e0; %make sure values are set back
M.Correlation_matrix = Corr_e0 ; %make sure values are set back
d2A = d2YssAOm(indA , indp2tottot2); %only unique elements
d2Om = d2YssAOm(indA(end)+1:end , indp2tottot2); %only unique elements
d2Yss = zeros(var_nbr,modparam_nbr,modparam_nbr); %initialize
for j = 1:var_nbr
d2Yss(j,:,:) = dyn_unvech(full(d2YssAOm(j,indp2modmod2))); %full Hessian for d2Yss, note that here we duplicate unique values for model parameters
end
clear d2YssAOm
end
return %[END OF MAIN FUNCTION]!!!!!
end
if kronflag == -2
% numerical two-sided finite difference method to compute numerically
% dYss, dg1, d2Yss and d2g1, the rest is computed analytically (kronflag=0) below
modpara0 = params0(indpmodel); %focus only on model parameters for dYss, d2Yss and dg1
[~, g1] = feval([fname,'.dynamic'], yy0, ex0, params0, ys, 1);
%g1 is [endo_nbr by (dynamicvar_nbr+exo_nbr)] first derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. df/d[yy0;ex0], in DR order
if nargout > 6
% computation of d2Yss and d2g1, i.e. second derivative (wrt. parameters) of Jacobian (wrt endogenous and auxilary variables) of dynamic model [outputflag = -1]
% 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
d2Yssg1 = hessian_sparse('identification_numerical_objective', modpara0, options.gstep, -1, estim_params, M, oo, options, indpmodel, [], [], (1:endo_nbr)');
M.params = params0; %make sure values are set back
M.Sigma_e = Sigma_e0; %make sure values are set back
M.Correlation_matrix = Corr_e0 ; %make sure values are set back
d2Yss = reshape(full(d2Yssg1(1:endo_nbr,:)), [endo_nbr modparam_nbr modparam_nbr]); %put into tensor notation
for j=1:endo_nbr
d2Yss(j,:,:) = dyn_unvech(dyn_vech(d2Yss(j,:,:))); %add duplicate values to full hessian
end
d2g1_full = d2Yssg1(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;
end
%Jacobian (wrt parameters) of steady state and Jacobian of dynamic model equations [outputflag=-1]
dg1 = fjaco('identification_numerical_objective', modpara0, -1, estim_params, M, oo, options, indpmodel, [], [], (1:endo_nbr)');
M.params = params0; %make sure values are set back
M.Sigma_e = Sigma_e0; %make sure values are set back
M.Correlation_matrix = Corr_e0 ; %make sure values are set back
dYss = dg1(1:endo_nbr , :);
dg1 = reshape(dg1(endo_nbr+1 : end , :),[endo_nbr, length(yy0)+length(ex0), modparam_nbr]); %get rid of steady state
elseif (kronflag == 0 || kronflag == 1)
% Analytical method to compute dYss, dg1, d2Yss and d2g1
[~, g1_static] = feval([fname,'.static'], ys, ex0, params0);
%g1_static is [endo_nbr by endo_nbr] first-derivative (wrt variables) of static model equations f, i.e. df/dys, in declaration order
rp_static = feval([fname,'.static_params_derivs'], ys, repmat(ex0, maximum_exo_lag+maximum_exo_lead+1), params0);
%rp_static is [endo_nbr by param_nbr] first-derivative (wrt parameters) of static model equations f, i.e. df/dparams, in declaration order
dys = -g1_static\rp_static;
%use implicit function theorem (equation 5 of Ratto and Iskrev (2011) to compute [endo_nbr by param_nbr] first-derivative (wrt parameters) of steady state analytically, note that dys is in declaration order
d2ys = zeros(length(ys), param_nbr, param_nbr); %initialize in tensor notation
if nargout > 6
[~, ~, g2_static] = feval([fname,'.static'], ys, ex0, params0);
%g2_static is [endo_nbr by endo_nbr^2] second derivative (wrt variables) of static model equations f, i.e. d(df/dys)/dys, in declaration order
[~, g1, g2, g3] = feval([fname,'.dynamic'], yy0, ex0, params0, ys, 1);
%g1 is [endo_nbr by (dynamicvar_nbr+exo_nbr)] first derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. df/d[yy0;ex0], in DR order
%g2 is [endo_nbr by (dynamicvar_nbr+exo_nbr)^2] second derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. d(df/d[yy0;ex0])/d[yy0;ex0], in DR order
%g3 is [endo_nbr by (dynamicvar_nbr+exo_nbr)^2] third-derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. d(df/d[yy0;ex0])/d[yy0;ex0], in DR order
[~, gp_static, rpp_static] = feval([fname,'.static_params_derivs'], ys, ex0, params0);
%gp_static is [endo_nbr by endo_nbr by param_nbr] first derivative (wrt parameters) of first-derivative (wrt variables) of static model equations f, i.e. (df/dys)/dparams, in declaration order
%rpp_static are nonzero values and corresponding indices of second derivative (wrt parameters) of static model equations f, i.e. d(df/dparams)/dparams, in declaration order
rpp_static = get_all_resid_2nd_derivs(rpp_static, length(ys), param_nbr); %make full matrix out of nonzero values and corresponding indices
%rpp_static is [endo_nbr by param_nbr by param_nbr] second derivative (wrt 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 (2011) is zero, i.e. gam = 0
for j = 1:param_nbr
%using the implicit function theorem, equation 15 on page 7 of Ratto and Iskrev (2011)
d2ys(:,:,j) = -g1_static\rpp_static(:,:,j);
%d2ys is [endo_nbr by param_nbr by param_nbr] second-derivative (wrt parameters) of steady state, i.e. d(dys/dparams)/dparams, in declaration order
end
else
gam = rpp_static*0; %initialize auxiliary expression on page 8 of Ratto and Iskrev (2011)
for j = 1:endo_nbr
tmp_gp_static_dys = (squeeze(gp_static(j,:,:))'*dys);
gam(j,:,:) = transpose(reshape(g2_static(j,:),[endo_nbr endo_nbr])*dys)*dys + tmp_gp_static_dys + tmp_gp_static_dys';
end
for j = 1:param_nbr
%using the implicit function theorem, equation 15 on page 7 of Ratto and Iskrev (2011)
d2ys(:,:,j) = -g1_static\(rpp_static(:,:,j)+gam(:,:,j));
%d2ys is [endo_nbr by param_nbr by param_nbr] second-derivative (wrt parameters) of steady state, i.e. d(dys/dparams)/dparams, in declaration order
end
clear gp_static g2_static tmp_gp_static_dys gam
end
end
%handling of steady state for nonstationary variables
if any(any(isnan(dys)))
[U,T] = schur(g1_static);
qz_criterium = options.qz_criterium;
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 (2011), in declaration order
dys = -U(:,k+1:end)*(T\U(:,k+1:end)')*rp_static;
if nargout > 6
disp('Computation of d2ys for nonstationary variables is not yet correctly handled if g2_static is nonempty, but continue anyways...')
for j = 1:param_nbr
%using implicit function theorem, equation 15 of Ratto and Iskrev (2011), 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 nargout > 6
[~, gp, ~, gpp, hp] = feval([fname,'.dynamic_params_derivs'], yy0, ex0, params0, ys, 1, dys, d2ys);
%gp is [endo_nbr by (dynamicvar_nbr + exo_nbr) by param_nbr] first-derivative (wrt parameters) of first-derivative (wrt all endogenous, auxiliary and exogenous variables) of dynamic model equations, i.e. d(df/dvars)/dparam, in DR order
%gpp are nonzero values and corresponding indices of second-derivative (wrt parameters) of first-derivative (wrt all endogenous, auxiliary and exogenous variables) of dynamic model equations, i.e. d(d(df/dvars)/dparam)/dparam, in DR order
%hp are nonzero values and corresponding indices of first-derivative (wrt parameters) of second-derivative (wrt all endogenous, auxiliary and exogenous variables) of dynamic model equations, i.e. d(d(df/dvars)/dvars)/dparam, in DR order
d2Yss = d2ys(oo.dr.order_var,indpmodel,indpmodel);
%[endo_nbr by mod_param_nbr by mod_param_nbr], i.e. put into DR order and focus only on model parameters
else
[~, gp] = feval([fname,'.dynamic_params_derivs'], yy0, repmat(ex0, [maximum_exo_lag+maximum_exo_lead+1,1]), params0, ys, 1, dys, d2ys);
%gp is [endo_nbr by (dynamicvar_nbr + exo_nbr) by param_nbr] first-derivative (wrt parameters) of first-derivative (wrt all endogenous, auxiliary and exogenous variables) of dynamic model equations, i.e. d(df/dvars)/dparam, in DR order
[~, g1, g2 ] = feval([fname,'.dynamic'], yy0, repmat(ex0, [maximum_exo_lag+maximum_exo_lead+1,1]), params0, ys, 1);
%g1 is [endo_nbr by (dynamicvar_nbr+exo_nbr)] first derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. df/d[yy0;ex0], in DR order
%g2 is [endo_nbr by (dynamicvar_nbr+exo_nbr)^2] second derivative (wrt all endogenous, exogenous and auxiliary variables) of dynamic model equations, i.e. d(df/d[yy0;ex0])/d[yy0;ex0], in DR order
end
yy0ex0_nbr = sqrt(size(g2,2)); % number of dynamic variables + exogenous variables (length(yy0)+length(ex0))
dYss = dys(oo.dr.order_var, indpmodel); %focus only on model parameters, note dys is in declaration order, dYss is in DR-order
dyy0 = dys(I,:);
yy0_nbr = max(max(lead_lag_incidence)); % retrieve the number of states excluding columns for shocks
% Computation of dg1, i.e. first derivative (wrt. parameters) of Jacobian (wrt endogenous and auxilary variables) of dynamic model using the implicit function theorem
% Let g1 denote the Jacobian of dynamic model equations, i.e. g1 = df/d[yy0ex0], evaluated at the steady state
% Let dg1 denote the first-derivative (wrt parameters) of g1 evaluated at the steady state
% Note that g1 is a function of both the parameters and of the steady state, which also depends on the parameters.
% Hence, implicitly g1=g1(p,yy0ex0(p)) and dg1 consists of two parts (see Ratto and Iskrev (2011) formula 7):
% (1) direct derivative wrt to parameters given by the preprocessor, i.e. gp
% and
% (2) contribution of derivative of steady state (wrt parameters), i.e. g2*dyy0
% Note that in a stochastic context ex0 is always zero and hence can be skipped in the computations
dg1_part2 = gp*0; %initialize part 2, it has dimension [endo_nbr by (dynamicvar_nbr+exo_nbr) by param_nbr]
for j = 1:endo_nbr
[II, JJ] = ind2sub([yy0ex0_nbr yy0ex0_nbr], find(g2(j,:)));
%g2 is [endo_nbr by (dynamicvar_nbr+exo_nbr)^2]
for i = 1:yy0ex0_nbr
is = find(II==i);
is = is(find(JJ(is)<=yy0_nbr)); %focus only on yy0 derivatives as ex0 variables are 0 in a stochastic context
if ~isempty(is)
tmp_g2 = full(g2(j,find(g2(j,:))));
dg1_part2(j,i,:) = tmp_g2(is)*dyy0(JJ(is),:); %put into tensor notation
end
end
end
dg1 = gp + dg1_part2; %dg is sum of two parts due to implicit function theorem
dg1 = dg1(:,:,indpmodel); %focus only on model parameters
if nargout > 6
% Computation of d2g1, i.e. second derivative (wrt. parameters) of Jacobian (wrt endogenous and auxilary variables) of dynamic model using the implicit function theorem
% Let g1 denote the Jacobian of dynamic model equations, i.e. g1 = df/d[yy0ex0], evaluated at the steady state
% Let d2g1 denote the second-derivative (wrt parameters) of g1
% Note that g1 is a function of both the parameters and of the steady state, which also depends on the parameters.
% Hence, implicitly g1=g1(p,yy0ex0(p)) and the first derivative is given by dg1 = gp + g2*dyy0ex0 (see above)
% Accordingly, d2g1, the second-derivative (wrt parameters), consists of five parts (ignoring transposes, see Ratto and Iskrev (2011) formula 16)
% (1) d(gp)/dp = gpp
% (2) d(gp)/dyy0ex0*d(yy0ex0)/dp = hp * dyy0ex0
% (3) d(g2)/dp * dyy0ex0 = hp * 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 (2011) formula 16)
d2g1_full = sparse(endo_nbr*yy0ex0_nbr, param_nbr*param_nbr); %initialize
dyy0ex0 = sparse([dyy0; zeros(yy0ex0_nbr-yy0_nbr,param_nbr)]); %Jacobian (wrt model parameters) of steady state of dynamic (endogenous and auxiliary) and exogenous variables
g3_tmp = reshape(g3,[endo_nbr*yy0ex0_nbr*yy0ex0_nbr yy0ex0_nbr]);
d2g1_part4_left = sparse(endo_nbr*yy0ex0_nbr*yy0ex0_nbr,param_nbr);
for j = 1:param_nbr
%compute first two terms of part 4
d2g1_part4_left(:,j) = g3_tmp*dyy0ex0(:,j);
end
for j=1:endo_nbr
%Note that in the following we focus only on dynamic variables as exogenous variables 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,param_nbr*param_nbr]);
for i=1:yy0ex0_nbr
ind_part4 = sub2ind([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(hp,j,i,yy0ex0_nbr,param_nbr))'*dyy0ex0;
d2g1_part1 = get_2nd_deriv_mat(gpp,j,i,param_nbr);
d2g1_tmp = d2g1_part1 + d2g1_part2_and_part3 + d2g1_part2_and_part3' + d2g1_part4 + reshape(d2g1_part5(i,:,:),[param_nbr 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([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:
% 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;
end
end
% clear variables that are not used any more
clear rp_static g1_static
clear ys dys dyy0 dyy0ex0
clear dg1_part2 tmp_g2
clear g2 gp rpp_static g2_static gp_static d2ys
clear hp g3 g3_tmp gpp
clear ind_d2g1 ind_d2g1_tmp ind_part4 i j i1 i2 ig1 ig2 I II JJ ip1 ip2 is
% Construct nonzero derivatives wrt to t+1, t, and t-1 variables using kstate
klen = maximum_endo_lag + maximum_endo_lead + 1; %total length
k11 = lead_lag_incidence(find([1:klen] ~= maximum_endo_lag+1),:);
g1nonzero = g1(:,nonzeros(k11'));
dg1nonzero = dg1(:,nonzeros(k11'),:);
if nargout > 6
indind = ismember(d2g1(:,2),nonzeros(k11'));
tmp = d2g1(indind,:);
d2g1nonzero = tmp;
for j = 1:size(tmp,1)
inxinx = find(nonzeros(k11')==tmp(j,2));
d2g1nonzero(j,2) = inxinx;
end
end
kstate = oo.dr.kstate;
% Construct nonzero derivatives wrt to t+1, i.e. GAM1=-f_{y^+} in Villemot (2011)
GAM1 = zeros(endo_nbr,endo_nbr);
dGAM1 = zeros(endo_nbr,endo_nbr,modparam_nbr);
k1 = find(kstate(:,2) == maximum_endo_lag+2 & kstate(:,3));
GAM1(:, kstate(k1,1)) = -g1nonzero(:,kstate(k1,3));
dGAM1(:, kstate(k1,1), :) = -dg1nonzero(:,kstate(k1,3),:);
if nargout > 6
indind = ismember(d2g1nonzero(:,2),kstate(k1,3));
tmp = d2g1nonzero(indind,:);
tmp(:,end)=-tmp(:,end);
d2GAM1 = tmp;
for j = 1:size(tmp,1)
inxinx = (kstate(k1,3)==tmp(j,2));
d2GAM1(j,2) = kstate(k1(inxinx),1);
end
end
% Construct nonzero derivatives wrt to t, i.e. GAM0=f_{y^0} in Villemot (2011)
[~,cols_b,cols_j] = find(lead_lag_incidence(maximum_endo_lag+1, oo.dr.order_var));
GAM0 = zeros(endo_nbr,endo_nbr);
dGAM0 = zeros(endo_nbr,endo_nbr,modparam_nbr);
GAM0(:,cols_b) = g1(:,cols_j);
dGAM0(:,cols_b,:) = dg1(:,cols_j,:);
if nargout > 6
indind = ismember(d2g1(:,2),cols_j);
tmp = d2g1(indind,:);
d2GAM0 = tmp;
for j = 1:size(tmp,1)
inxinx = (cols_j==tmp(j,2));
d2GAM0(j,2) = cols_b(inxinx);
end
end
% Construct nonzero derivatives wrt to t-1, i.e. GAM2=-f_{y^-} in Villemot (2011)
k2 = find(kstate(:,2) == maximum_endo_lag+1 & kstate(:,4));
GAM2 = zeros(endo_nbr,endo_nbr);
dGAM2 = zeros(endo_nbr,endo_nbr,modparam_nbr);
GAM2(:, kstate(k2,1)) = -g1nonzero(:,kstate(k2,4));
dGAM2(:, kstate(k2,1), :) = -dg1nonzero(:,kstate(k2,4),:);
if nargout > 6
indind = ismember(d2g1nonzero(:,2),kstate(k2,4));
tmp = d2g1nonzero(indind,:);
tmp(:,end) = -tmp(:,end);
d2GAM2 = tmp;
for j = 1:size(tmp,1)
inxinx = (kstate(k2,4)==tmp(j,2));
d2GAM2(j,2) = kstate(k2(inxinx),1);
end
end
% Construct nonzero derivatives wrt to u_t, i.e. GAM3=-f_{u} in Villemot (2011)
GAM3 = -g1(:,length(yy0)+1:end);
dGAM3 = -dg1(:,length(yy0)+1:end,:);
if nargout > 6
cols_ex = [length(yy0)+1:size(g1,2)];
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 d2g1nonzero tmp
end
clear cols_b cols_ex cols_j k1 k11 k2 klen kstate
clear g1nonzero dg1nonzero g1 yy0
%% Construct first derivative of Sigma_e
dSigma_e = zeros(exo_nbr,exo_nbr,totparam_nbr); %initialize
% note that derivatives wrt model parameters are zero by construction
% Compute first derivative of Sigma_e wrt stderr parameters (these come first)
if ~isempty(indpstderr)
for jp = 1:stderrparam_nbr
dSigma_e(indpstderr(jp),indpstderr(jp),jp) = 2*stderr_e0(indpstderr(jp));
if isdiag(Sigma_e0) == 0 % if there are correlated errors add cross derivatives
indotherex0 = 1:exo_nbr;
indotherex0(indpstderr(jp)) = [];
for kk = indotherex0
dSigma_e(indpstderr(jp), kk, jp) = Corr_e0(indpstderr(jp),kk)*stderr_e0(kk);
dSigma_e(kk, indpstderr(jp), jp) = dSigma_e(indpstderr(jp), kk, jp); %symmetry
end
end
end
end
% Compute first derivative of Sigma_e 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) = stderr_e0(indpcorr(jp,1))*stderr_e0(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
end
end
%% Construct second derivative of Sigma_e
if nargout > 6
% note that derivatives wrt (mod x mod) and (corr x corr) parameters
% are zero by construction; hence we only need to focus on (stderr x stderr), and (stderr x corr)
d2Sigma_e = zeros(exo_nbr,exo_nbr,totparam_nbr^2); %initialize full matrix, even though we'll reduce it later on to unique upper triangular values
% Compute upper triangular values of 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(Sigma_e0) == 0 % if there are correlated errors
d2Sigma_e(indpstderr(jp),indpstderr(ip),indp2stderrstderr(ip,jp)) = Corr_e0(indpstderr(jp),indpstderr(ip));
d2Sigma_e(indpstderr(ip),indpstderr(jp),indp2stderrstderr(ip,jp)) = Corr_e0(indpstderr(jp),indpstderr(ip)); %symmetry
end
end
end
end
end
% Compute upper triangular values of 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 equal to first index of corr parameter, derivative is equal to stderr corresponding to second index
d2Sigma_e(indpstderr(jp),indpcorr(ip,2),indp2stderrcorr(jp,ip)) = stderr_e0(indpcorr(ip,2));
d2Sigma_e(indpcorr(ip,2),indpstderr(jp),indp2stderrcorr(jp,ip)) = stderr_e0(indpcorr(ip,2)); % symmetry
end
if indpstderr(jp) == indpcorr(ip,2) %if stderr equal to second index of corr parameter, derivative is equal to stderr corresponding to first index
d2Sigma_e(indpstderr(jp),indpcorr(ip,1),indp2stderrcorr(jp,ip)) = stderr_e0(indpcorr(ip,1));
d2Sigma_e(indpcorr(ip,1),indpstderr(jp),indp2stderrcorr(jp,ip)) = stderr_e0(indpcorr(ip,1)); % symmetry
end
end
end
end
d2Sigma_e = d2Sigma_e(:,:,indp2tottot2); %focus on upper triangular hessian values
end
if kronflag == 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.
% Let F = GAM0*A - GAM1*A*A - GAM2 = 0
% Note that F is a function of parameters p and A, which is also a
% function of p,therefore, F = F(p,A(p)), and hence,
% dF = Fp + dF_dA*dA or dA = - Fp/dF_dA
% Some auxiliary matrices
I_endo = speye(endo_nbr);
I_exo = speye(exo_nbr);
% Reshape to write derivatives in the Magnus and Neudecker style, i.e. dvec(X)/dp
dGAM0 = reshape(dGAM0, endo_nbr^2, modparam_nbr);
dGAM1 = reshape(dGAM1, endo_nbr^2, modparam_nbr);
dGAM2 = reshape(dGAM2, endo_nbr^2, modparam_nbr);
dGAM3 = reshape(dGAM3, endo_nbr*exo_nbr, modparam_nbr);
dSigma_e = reshape(dSigma_e, exo_nbr^2, totparam_nbr);
% Compute dA via implicit function
dF_dA = kron(I_endo,GAM0) - kron(A',GAM1) - kron(I_endo,GAM1*A); %equation 31 in Appendix A of Iskrev (2010)
Fp = kron(A',I_endo)*dGAM0 - kron( (A')^2,I_endo)*dGAM1 - dGAM2; %equation 32 in Appendix A of Iskrev (2010)
dA = -dF_dA\Fp;
% Compute dB from expressions 33 in Iskrev (2010) Appendix A
MM = GAM0-GAM1*A; %this corresponds to matrix M in Ratto and Iskrev (2011, page 6) and will be used if nargout > 6 below
invMM = MM\eye(endo_nbr);
dB = - kron( (invMM*GAM3)' , invMM ) * ( dGAM0 - kron( A' , I_endo ) * dGAM1 - kron( I_endo , GAM1 ) * dA ) + kron( I_exo, invMM ) * dGAM3 ;
dBt = commutation(endo_nbr, exo_nbr)*dB; %transose of derivative using the commutation matrix
% Add derivatives for stderr and corr parameters, which are zero by construction
dA = [zeros(endo_nbr^2, stderrparam_nbr+corrparam_nbr) dA];
dB = [zeros(endo_nbr*exo_nbr, stderrparam_nbr+corrparam_nbr) dB];
dBt = [zeros(endo_nbr*exo_nbr, stderrparam_nbr+corrparam_nbr) dBt];
% Compute dOm = dvec(B*Sig*B') from expressions 34 in Iskrev (2010) Appendix A
dOm = kron(I_endo,B*Sigma_e0)*dBt + kron(B,B)*dSigma_e + kron(B*Sigma_e0,I_endo)*dB;
% Put into tensor notation
dA = reshape(dA, endo_nbr, endo_nbr, totparam_nbr);
dB = reshape(dB, endo_nbr, exo_nbr, totparam_nbr);
dOm = reshape(dOm, endo_nbr, endo_nbr, totparam_nbr);
dSigma_e = reshape(dSigma_e, exo_nbr, exo_nbr, totparam_nbr);
if nargout > 6
% Put back into tensor notation as these will be reused later
dGAM0 = reshape(dGAM0, endo_nbr, endo_nbr, modparam_nbr);
dGAM1 = reshape(dGAM1, endo_nbr, endo_nbr, modparam_nbr);
dGAM2 = reshape(dGAM2, endo_nbr, endo_nbr, modparam_nbr);
dGAM3 = reshape(dGAM3, endo_nbr, exo_nbr, modparam_nbr);
dAA = dA(:, :, stderrparam_nbr+corrparam_nbr+1:end); %this corresponds to matrix dA in Ratto and Iskrev (2011, page 6), i.e. derivative of A with respect to model parameters only in tensor notation
dBB = dB(:, :, stderrparam_nbr+corrparam_nbr+1:end); %dBB is for all endogenous variables, whereas dB is only for selected variables
N = -GAM1; %this corresponds to matrix N in Ratto and Iskrev (2011, page 6)
P = A; %this corresponds to matrix P in Ratto and Iskrev (2011, page 6)
end
% Focus only on selected variables
dYss = dYss(indvar,:);
dA = dA(indvar,indvar,:);
dB = dB(indvar,:,:);
dOm = dOm(indvar,indvar,:);
elseif (kronflag == 0 || kronflag == -2)
% generalized sylvester equation solves MM*dAA+N*dAA*P=Q from Ratto and Iskrev (2011) equation 11 where
% dAA is derivative of A with respect to model parameters only in tensor notation
MM = (GAM0-GAM1*A);
N = -GAM1;
P = A;
Q_rightpart = zeros(endo_nbr,endo_nbr,modparam_nbr); %initialize
Q = Q_rightpart; %initialize and compute matrix Q in Ratto and Iskrev (2011, page 6)
for j = 1:modparam_nbr
Q_rightpart(:,:,j) = (dGAM0(:,:,j)-dGAM1(:,:,j)*A);
Q(:,:,j) = dGAM2(:,:,j)-Q_rightpart(:,:,j)*A;
end
%use iterated generalized sylvester equation to compute dAA
dAA = sylvester3(MM,N,P,Q);
flag = 1; icount = 0;
while flag && icount < 4
[dAA, flag] = sylvester3a(dAA,MM,N,P,Q);
icount = icount+1;
end
%stderr parameters come first, then corr parameters, model parameters come last
%note that stderr and corr derivatives are:
% - zero by construction for A and B
% - depend only on dSig for Om
dOm = zeros(var_nbr, var_nbr, totparam_nbr);
dA = zeros(var_nbr, var_nbr, totparam_nbr);
dB = zeros(var_nbr, exo_nbr, totparam_nbr);
if nargout > 6
dBB = zeros(endo_nbr, exo_nbr, modparam_nbr); %dBB is always for all endogenous variables, whereas dB is only for selected variables
end
%compute derivative of Om=B*Sig*B' that depends on Sig (other part is added later)
if ~isempty(indpstderr)
for j = 1:stderrparam_nbr
BSigjBt = B*dSigma_e(:,:,j)*B';
dOm(:,:,j) = BSigjBt(indvar,indvar);
end
end
if ~isempty(indpcorr)
for j = 1:corrparam_nbr
BSigjBt = B*dSigma_e(:,:,stderrparam_nbr+j)*B';
dOm(:,:,stderrparam_nbr+j) = BSigjBt(indvar,indvar);
end
end
%compute derivative of B and the part of Om=B*Sig*B' that depends on B (other part is computed above)
invMM = inv(MM);
for j = 1:modparam_nbr
dAAj = dAA(:,:,j);
dBj = invMM * ( dGAM3(:,:,j) - (Q_rightpart(:,:,j) -GAM1*dAAj ) * B ); %equation 14 in Ratto and Iskrev (2011), except in the paper there is a typo as the last B is missing
dOmj = dBj*Sigma_e0*B'+B*Sigma_e0*dBj';
%store derivatives in tensor notation
dA(:, :, stderrparam_nbr+corrparam_nbr+j) = dAAj(indvar,indvar);
dB(:, :, stderrparam_nbr+corrparam_nbr+j) = dBj(indvar,:);
dOm(:, :, stderrparam_nbr+corrparam_nbr+j) = dOmj(indvar,indvar);
if nargout > 6
dBB(:, :, j) = dBj;
end
end
dYss = dYss(indvar,:); % Focus only on relevant variables
end
%% Compute second-order derivatives (wrt params) of solution matrices using generalized sylvester equations, see equations 17 and 18 in Ratto and Iskrev (2011)
if nargout > 6
% solves MM*d2AA+N*d2AA*P = QQ where d2AA are second order derivatives (wrt model parameters) of A
d2Yss = d2Yss(indvar,:,:);
QQ = zeros(endo_nbr,endo_nbr,floor(sqrt(modparam_nbr2)));
jcount=0;
cumjcount=0;
jinx = [];
x2x=sparse(endo_nbr*endo_nbr,modparam_nbr2);
for i=1:modparam_nbr
for j=1:i
elem1 = (get_2nd_deriv(d2GAM0,endo_nbr,endo_nbr,j,i)-get_2nd_deriv(d2GAM1,endo_nbr,endo_nbr,j,i)*A);
elem1 = get_2nd_deriv(d2GAM2,endo_nbr,endo_nbr,j,i)-elem1*A;
elemj0 = dGAM0(:,:,j)-dGAM1(:,:,j)*A;
elemi0 = dGAM0(:,:,i)-dGAM1(:,:,i)*A;
elem2 = -elemj0*dAA(:,:,i)-elemi0*dAA(:,:,j);
elem2 = elem2 + ( dGAM1(:,:,j)*dAA(:,:,i) + dGAM1(:,:,i)*dAA(:,:,j) )*A;
elem2 = elem2 + GAM1*( dAA(:,:,i)*dAA(:,:,j) + dAA(:,:,j)*dAA(:,:,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,N,P,QQ);
flag=1;
icount=0;
while flag && icount<4
[xx2, flag]=sylvester3a(xx2,MM,N,P,QQ);
icount = icount + 1;
end
x2x(:,cumjcount+1:cumjcount+jcount)=reshape(xx2,[endo_nbr*endo_nbr jcount]);
cumjcount=cumjcount+jcount;
jcount = 0;
jinx = [];
end
end
end
clear d xx2;
jcount = 0;
icount = 0;
cumjcount = 0;
MAX_DIM_MAT = 100000000;
ncol = max(1,floor(MAX_DIM_MAT/(8*var_nbr*(var_nbr+1)/2)));
ncol = min(ncol, totparam_nbr2);
d2A = sparse(var_nbr*var_nbr,totparam_nbr2);
d2Om = sparse(var_nbr*(var_nbr+1)/2,totparam_nbr2);
d2A_tmp = zeros(var_nbr*var_nbr,ncol);
d2Om_tmp = zeros(var_nbr*(var_nbr+1)/2,ncol);
tmpDir = CheckPath('tmp_derivs',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 = B*d2Sigma_e(:,:,jcount)*B';
d2Om_tmp(:,jcount) = dyn_vech(y(indvar,indvar));
else %model parameters
jind = j-offset;
iind = i-offset;
if i<=offset
y = dBB(:,:,jind)*dSigma_e(:,:,i)*B'+B*dSigma_e(:,:,i)*dBB(:,:,jind)';
% y(abs(y)<1.e-8)=0;
d2Om_tmp(:,jcount) = dyn_vech(y(indvar,indvar));
else
icount=icount+1;
dAAj = reshape(x2x(:,icount),[endo_nbr endo_nbr]);
% x = get_2nd_deriv(x2x,m,m,iind,jind);%xx2(:,:,jcount);
elem1 = (get_2nd_deriv(d2GAM0,endo_nbr,endo_nbr,iind,jind)-get_2nd_deriv(d2GAM1,endo_nbr,endo_nbr,iind,jind)*A);
elem1 = elem1 -( dGAM1(:,:,jind)*dAA(:,:,iind) + dGAM1(:,:,iind)*dAA(:,:,jind) );
elemj0 = dGAM0(:,:,jind)-dGAM1(:,:,jind)*A-GAM1*dAA(:,:,jind);
elemi0 = dGAM0(:,:,iind)-dGAM1(:,:,iind)*A-GAM1*dAA(:,:,iind);
elem0 = elemj0*dBB(:,:,iind)+elemi0*dBB(:,:,jind);
y = invMM * (get_2nd_deriv(d2GAM3,endo_nbr,exo_nbr,iind,jind)-elem0-(elem1-GAM1*dAAj)*B);
% d2B(:,:,j+length(indexo),i+length(indexo)) = y;
% d2B(:,:,i+length(indexo),j+length(indexo)) = y;
y = y*Sigma_e0*B'+B*Sigma_e0*y'+ ...
dBB(:,:,jind)*Sigma_e0*dBB(:,:,iind)'+dBB(:,:,iind)*Sigma_e0*dBB(:,:,jind)';
% x(abs(x)<1.e-8)=0;
d2A_tmp(:,jcount) = vec(dAAj(indvar,indvar));
% y(abs(y)<1.e-8)=0;
d2Om_tmp(:,jcount) = dyn_vech(y(indvar,indvar));
end
end
if jcount==ncol || i*j==totparam_nbr^2
d2A(:,cumjcount+1:cumjcount+jcount) = d2A_tmp(:,1:jcount);
% d2A(:,:,j+length(indexo),i+length(indexo)) = x;
% d2A(:,:,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 'd2A_' int2str(cumjcount+1) '_' int2str(cumjcount+jcount) '.mat'],'d2A')
save([tmpDir filesep 'd2Om_' int2str(cumjcount+1) '_' int2str(cumjcount+jcount) '.mat'],'d2Om')
cumjcount = cumjcount+jcount;
jcount=0;
% d2A = 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);
d2A_tmp = zeros(var_nbr*var_nbr,ncol);
d2Om_tmp = zeros(var_nbr*(var_nbr+1)/2,ncol);
end
end
end
end
return
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 g22 = get_all_2nd_derivs(gpp,m,n,npar,fsparse)
if nargin==4 || isempty(fsparse)
fsparse=0;
end
if fsparse
g22=sparse(m*n,npar*npar);
else
g22=zeros(m,n,npar,npar);
end
% c=ones(npar,npar);
% c=triu(c);
% ic=find(c);
for is=1:length(gpp)
% d=zeros(npar,npar);
% d(gpp(is,3),gpp(is,4))=1;
% indx = find(ic==find(d));
if fsparse
g22(sub2ind([m,n],gpp(is,1),gpp(is,2)),sub2ind([npar,npar],gpp(is,3),gpp(is,4)))=gpp(is,5);
else
g22(gpp(is,1),gpp(is,2),gpp(is,3),gpp(is,4))=gpp(is,5);
end
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 endo_nbr
% - npar: scalar Number of model parameters, i.e. equals param_nbr
%
% output:
% r22: [endo_nbr by param_nbr by 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:length(rpp)
% 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_all_hess_derivs(hp,r,m,npar)
h2=zeros(r,m,m,npar);
for is=1:length(hp)
h2(hp(is,1),hp(is,2),hp(is,3),hp(is,4))=hp(is,5);
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. dynamicvar_nbr + exo_nbr
% - npar: scalar Number of model parameters, i.e. equals M_.param_nbr
%
% output:
% h2: [(dynamicvar_nbr + 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