diff --git a/matlab/dsge_likelihood.m b/matlab/dsge_likelihood.m index 0c67c65987858c4b1e1c5e1116b1f93801cf75b6..f44cb13fb2a123aacbd3211f6d6050cfa989b19a 100644 --- a/matlab/dsge_likelihood.m +++ b/matlab/dsge_likelihood.m @@ -111,7 +111,7 @@ function [fval,info,exit_flag,DLIK,Hess,SteadyState,trend_coeff,Model,DynareOpti %! @sp 2 %! @strong{This function calls:} %! @sp 1 -%! @ref{dynare_resolve}, @ref{lyapunov_symm}, @ref{lyapunov_solver}, @ref{compute_Pinf_Pstar}, @ref{kalman_filter_d}, @ref{missing_observations_kalman_filter_d}, @ref{univariate_kalman_filter_d}, @ref{kalman_steady_state}, @ref{get_first_order_solution_params_deriv}, @ref{kalman_filter}, @ref{score}, @ref{AHessian}, @ref{missing_observations_kalman_filter}, @ref{univariate_kalman_filter}, @ref{priordens} +%! @ref{dynare_resolve}, @ref{lyapunov_symm}, @ref{lyapunov_solver}, @ref{compute_Pinf_Pstar}, @ref{kalman_filter_d}, @ref{missing_observations_kalman_filter_d}, @ref{univariate_kalman_filter_d}, @ref{kalman_steady_state}, @ref{get_perturbation_params_deriv}, @ref{kalman_filter}, @ref{score}, @ref{AHessian}, @ref{missing_observations_kalman_filter}, @ref{univariate_kalman_filter}, @ref{priordens} %! @end deftypefn %@eod: @@ -522,11 +522,29 @@ if analytic_derivation else indparam=[]; end + old_order = DynareOptions.order; + if DynareOptions.order > 1%not sure whether this check is necessary + DynareOptions.order = 1; fprintf('Reset order to 1 for analytical parameter derivatives.\n'); + end + old_analytic_derivation_mode = DynareOptions.analytic_derivation_mode; + DynareOptions.analytic_derivation_mode = kron_flag; if full_Hess - [DT, ~, ~, DOm, DYss, ~, D2T, D2Om, D2Yss] = get_first_order_solution_params_deriv(A, B, EstimatedParameters, Model,DynareResults,DynareOptions,kron_flag,indparam,indexo,[],iv); + DERIVS = get_perturbation_params_derivs(Model, DynareOptions, EstimatedParameters, DynareResults, indparam, indexo, [], true); + indD2T = reshape(1:Model.endo_nbr^2, Model.endo_nbr, Model.endo_nbr); + indD2Om = dyn_unvech(1:Model.endo_nbr*(Model.endo_nbr+1)/2); + D2T = DERIVS.d2KalmanA(indD2T(iv,iv),:); + D2Om = DERIVS.d2Om(dyn_vech(indD2Om(iv,iv)),:); + D2Yss = DERIVS.d2Yss(iv,:,:); else - [DT, ~, ~, DOm, DYss] = get_first_order_solution_params_deriv(A, B, EstimatedParameters, Model,DynareResults,DynareOptions,kron_flag,indparam,indexo,[],iv); - end + DERIVS = get_perturbation_params_derivs(Model, DynareOptions, EstimatedParameters, DynareResults, indparam, indexo, [], false); + end + DT = zeros(Model.endo_nbr, Model.endo_nbr, size(DERIVS.dghx,3)); + DT(:,Model.nstatic+(1:Model.nspred),:) = DERIVS.dghx; + DT = DT(iv,iv,:); + DOm = DERIVS.dOm(iv,iv,:); + DYss = DERIVS.dYss(iv,:); + DynareOptions.order = old_order; %make sure order is reset (not sure if necessary) + DynareOptions.analytic_derivation_mode = old_analytic_derivation_mode;%make sure analytic_derivation_mode is reset (not sure if necessary) else DT = derivatives_info.DT(iv,iv,:); DOm = derivatives_info.DOm(iv,iv,:); diff --git a/matlab/dynare_identification.m b/matlab/dynare_identification.m index 8f9141896c6f5cab8cf9ff44f844ce50a22ca163..6a09e8705715613e552b6f61fbb379d43fe55e71 100644 --- a/matlab/dynare_identification.m +++ b/matlab/dynare_identification.m @@ -284,7 +284,6 @@ options_ = set_default_option(options_,'datafile',''); options_.mode_compute = 0; options_.plot_priors = 0; options_.smoother = 1; -options_.options_ident = options_ident; %store identification options into global options [dataset_, dataset_info, xparam1, hh, M_, options_, oo_, estim_params_, bayestopt_, bounds] = dynare_estimation_init(M_.endo_names, fname, 1, M_, options_, oo_, estim_params_, bayestopt_); %outputting dataset_ is needed for Octave @@ -294,6 +293,7 @@ options_ident = set_default_option(options_ident,'analytic_derivation_mode', opt % 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 Jacobians 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 Jacobians are then computed analytically as in options 0 +options_.analytic_derivation_mode = options_ident.analytic_derivation_mode; %overwrite setting % initialize persistent variables in prior_draw if prior_exist @@ -385,12 +385,13 @@ options_ident = set_default_option(options_ident,'max_dim_subsets_groups',min([4 % In identification_checks_via_subsets.m, when checks_via_subsets=1, this % option sets the maximum dimension of groups of parameters for which % the corresponding rank criteria is checked - + +options_.options_ident = options_ident; %store identification options into global options MaxNumberOfBytes = options_.MaxNumberOfBytes; %threshold when to save from memory to files store_options_ident = options_ident; + iload = options_ident.load_ident_files; SampleSize = options_ident.prior_mc; - if iload <=0 %% Perform new identification analysis, i.e. do not load previous analysis if prior_exist diff --git a/matlab/fjaco.m b/matlab/fjaco.m index 9b6f68abc34cc7bbee0aa3a55b02d4a6ea8dd615..ab8b645a9cf472e85d1e2fc76655e004ada4e5a7 100644 --- a/matlab/fjaco.m +++ b/matlab/fjaco.m @@ -10,7 +10,7 @@ function fjac = fjaco(f,x,varargin) % OUTPUT % fjac : finite difference Jacobian % -% Copyright (C) 2010-2017 Dynare Team +% Copyright (C) 2010-2017,2019 Dynare Team % % This file is part of Dynare. % @@ -29,7 +29,10 @@ function fjac = fjaco(f,x,varargin) ff=feval(f,x,varargin{:}); -tol = eps.^(1/3); +tol = eps.^(1/3); %some default value +if strcmp(func2str(f),'get_perturbation_params_derivs_numerical_objective') || strcmp(func2str(f),'identification_numerical_objective') + tol= varargin{5}.dynatol.x; +end h = tol.*max(abs(x),1); xh1=x+h; xh0=x-h; h=xh1-xh0; @@ -37,8 +40,69 @@ fjac = NaN(length(ff),length(x)); for j=1:length(x) xx = x; xx(j) = xh1(j); f1=feval(f,xx,varargin{:}); + if isempty(f1) && (strcmp(func2str(f),'get_perturbation_params_derivs_numerical_objective') || strcmp(func2str(f),'identification_numerical_objective') ) + [~,info]=feval(f,xx,varargin{:}); + disp_info_error_identification_perturbation(info,j); + end xx(j) = xh0(j); f0=feval(f,xx,varargin{:}); + if isempty(f0) && (strcmp(func2str(f),'get_perturbation_params_derivs_numerical_objective') || strcmp(func2str(f),'identification_numerical_objective') ) + [~,info]=feval(f,xx,varargin{:}); + disp_info_error_identification_perturbation(info,j) + end fjac(:,j) = (f1-f0)/h(j); end feval(f,x,varargin{:}); + +%Auxiliary functions +function disp_info_error_identification_perturbation(info,j) + % there are errors in the solution algorithm + SE_names = {}; CORR_names={}; MOD_names={}; %initialize parameter names as they appear in estimated_params block + if varargin{2}.nvx > 0 + SE_names = strcat('SE_' , varargin{3}.exo_names(varargin{2}.var_exo(:,1),:)); + end + if varargin{2}.nvx > 0 + CORR_names = strcat('CORR_' , varargin{3}.exo_names(varargin{2}.corrx(:,1),:), '_', varargin{3}.exo_names(varargin{2}.corrx(:,2),:)); + end + if varargin{2}.np > 0 + MOD_names = varargin{3}.param_names(varargin{2}.param_vals(:,1),:); + end + param_names = [SE_names; CORR_names; MOD_names]; + skipline() + fprintf('Parameter error in numerical two-sided difference method:\n') + fprintf('The model does not solve for %s with error code info = %d: ', param_names{j,:} , info(1)) + if info(1)==1 + fprintf('The model doesn''t determine the current variables uniquely.\n') + elseif info(1)==2 + fprintf('MJDGGES returned an error code.\n') + elseif info(1)==3 + fprintf('Blanchard & Kahn conditions are not satisfied: no stable equilibrium.\n') + elseif info(1)==4 + fprintf('Blanchard & Kahn conditions are not satisfied: indeterminacy.\n') + elseif info(1)==5 + fprintf('Blanchard & Kahn conditions are not satisfied: indeterminacy due to rank failure.\n') + elseif info(1)==6 + fprintf('The jacobian evaluated at the deterministic steady state is complex.\n') + elseif info(1)==19 + fprintf('The steadystate routine has thrown an exception (inconsistent deep parameters).\n') + elseif info(1)==20 + fprintf('Cannot find the steady state, info(2) contains the sum of square residuals (of the static equations).\n') + elseif info(1)==21 + fprintf('The steady state is complex, info(2) contains the sum of square of imaginary parts of the steady state\n') + elseif info(1)==22 + fprintf('The steady has NaNs.\n') + elseif info(1)==23 + fprintf('M_.params has been updated in the steadystate routine and has complex valued scalars.\n') + elseif info(1)==24 + fprintf('M_.params has been updated in the steadystate routine and has some NaNs.\n') + elseif info(1)==30 + fprintf('Ergodic variance can''t be computed.\n') + end + fprintf('Possible solutions:\n') + fprintf(' -- use analytic derivatives, i.e. set analytic_derivation_mode=0\n'); + fprintf(' -- use an estimated_params block without %s or change its value\n', param_names{j,:}); + fprintf(' -- change numerical tolerance level in fjaco.m (you can tune ''options_.dynatol.x'' or change fjaco.m function directly)\n'); + error('fjaco.m: numerical two-sided difference method yields errors in solution algorithm'); +end + +end %main function end \ No newline at end of file diff --git a/matlab/get_first_order_solution_params_deriv.m b/matlab/get_first_order_solution_params_deriv.m deleted file mode 100644 index 6cf4b0cc5f6fc8e3b664ec46eff1fcf921f15e88..0000000000000000000000000000000000000000 --- a/matlab/get_first_order_solution_params_deriv.m +++ /dev/null @@ -1,959 +0,0 @@ -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 = unfold_g3(g3, yy0ex0_nbr); - 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 diff --git a/matlab/get_identification_jacobians.m b/matlab/get_identification_jacobians.m index d4f5ebc525fe3246156642b2bc07cccdd28f1889..20e919a78b2dd91f653e7e6fd2681cfd31380f48 100644 --- a/matlab/get_identification_jacobians.m +++ b/matlab/get_identification_jacobians.m @@ -71,7 +71,7 @@ function [J, G, D, dTAU, dLRE, dA, dOm, dYss, MOMENTS] = get_identification_jaco % * get_minimal_state_representation % * duplication % * dyn_vech -% * get_first_order_solution_params_deriv (previously getH) +% * get_perturbation_params_deriv (previously getH) % * get_all_parameters % * fjaco % * lyapunov_symm @@ -124,7 +124,13 @@ exo_nbr = M.exo_nbr; endo_nbr = M.endo_nbr; %% Construct dTAU, dLRE, dA, dOm, dYss -[dA, dB, dSig, dOm, dYss, dg1] = get_first_order_solution_params_deriv(A, B, estim_params, M, oo, options, kronflag, indpmodel, indpstderr, indpcorr, (1:endo_nbr)'); +DERIVS = get_perturbation_params_derivs(M, options, estim_params, oo, indpmodel, indpstderr, indpcorr, 0);%d2flag=0 +dA = zeros(M.endo_nbr, M.endo_nbr, size(DERIVS.dghx,3)); +dA(:,M.nstatic+(1:M.nspred),:) = DERIVS.dghx; +dB = DERIVS.dghu; +dSig = DERIVS.dSigma_e; +dOm = DERIVS.dOm; +dYss = DERIVS.dYss; % Collect terms for derivative of tau=[Yss; vec(A); vech(Om)] dTAU = zeros(endo_nbr*endo_nbr+endo_nbr*(endo_nbr+1)/2, totparam_nbr); @@ -132,7 +138,7 @@ for j=1:totparam_nbr dTAU(:,j) = [vec(dA(:,:,j)); dyn_vech(dOm(:,:,j))]; end dTAU = [ [zeros(endo_nbr, stderrparam_nbr+corrparam_nbr) dYss]; dTAU ]; % add steady state -dLRE = [dYss; reshape(dg1,size(dg1,1)*size(dg1,2),size(dg1,3)) ]; %reshape dg1 and add steady state +dLRE = [dYss; reshape(DERIVS.dg1,size(DERIVS.dg1,1)*size(DERIVS.dg1,2),size(DERIVS.dg1,3)) ]; %reshape dg1 and add steady state %State Space Matrices for VAROBS variables C = A(indvobs,:); @@ -144,7 +150,7 @@ dD = dB(indvobs,:,:); if ~no_identification_moments if kronflag == -1 %numerical derivative of autocovariogram [outputflag=1] - J = fjaco('identification_numerical_objective', para0, 1, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvobs, useautocorr, nlags, grid_nbr); + J = fjaco(str2func('identification_numerical_objective'), para0, 1, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvobs, useautocorr, nlags, grid_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 @@ -254,7 +260,7 @@ if ~no_identification_spectrum IA = eye(size(A,1)); if kronflag == -1 %numerical derivative of spectral density [outputflag=2] - dOmega_tmp = fjaco('identification_numerical_objective', para0, 2, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvobs, useautocorr, nlags, grid_nbr); + dOmega_tmp = fjaco(str2func('identification_numerical_objective'), para0, 2, estim_params, M, oo, options, indpmodel, indpstderr, indpcorr, indvobs, useautocorr, nlags, grid_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 diff --git a/matlab/get_perturbation_params_derivs.m b/matlab/get_perturbation_params_derivs.m new file mode 100644 index 0000000000000000000000000000000000000000..28b7fd119f44577565180b540199c8ecd92c0a5f --- /dev/null +++ b/matlab/get_perturbation_params_derivs.m @@ -0,0 +1,1533 @@ +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 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' (wrt selected stderr, corr and model paramters) + DERIVS.dOm = zeros(M.endo_nbr,M.endo_nbr,totparam_nbr); %initialize in tensor notation + 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'; + 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, err] = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0,kyy0)+(jp-1)*yy0ex0_nbr^2),zx(1:yy0_nbr,:),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_2, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0,kyy0)),dzx(1:yy0_nbr,:,jp),zx(1:yy0_nbr,:),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_3, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0,kyy0)),zx(1:yy0_nbr,:),dzx(1:yy0_nbr,:,jp),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + 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,err] = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghx(idx_states,:),oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); %auxiliary expressions for dghxu + [abcOutuu, err] = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); %auxiliary expressions for dghuu + [RHSs2, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), oo.dr.ghu(klead~=0,:),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + 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, err] = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2),zx,zu,threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_2, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),dzx(:,:,jp),zu,threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_3, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),zx,dzu(:,:,jp),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dabcOut_1,err] = A_times_B_kronecker_C(dghxx(:,:,jp),oo.dr.ghx(idx_states,:),oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); + [dabcOut_2,err] = A_times_B_kronecker_C(oo.dr.ghxx,dghx(idx_states,:,jp),oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); + [dabcOut_3,err] = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghx(idx_states,:),dghu(idx_states,:,jp)); mexErrCheck('A_times_B_kronecker_C', err); + 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, err] = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(kyy0ex0,kyy0ex0)+(jp-1)*yy0ex0_nbr^2),zu,threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_2, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),dzu(:,:,jp),zu,threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_3, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(kyy0ex0,kyy0ex0)),zu,dzu(:,:,jp),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dabcOut_1, err] = A_times_B_kronecker_C(dghxx(:,:,jp),oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); + [dabcOut_2, err] = A_times_B_kronecker_C(oo.dr.ghxx,dghu(idx_states,:,jp),oo.dr.ghu(idx_states,:)); mexErrCheck('A_times_B_kronecker_C', err); + [dabcOut_3, err] = A_times_B_kronecker_C(oo.dr.ghxx,oo.dr.ghu(idx_states,:),dghu(idx_states,:,jp)); mexErrCheck('A_times_B_kronecker_C', err); + 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, err] = sparse_hessian_times_B_kronecker_C(dg2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))+(jp-1)*yy0ex0_nbr^2), oo.dr.ghu(klead~=0,:),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_2, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), dghu(klead~=0,:,jp), oo.dr.ghu(klead~=0,:),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + [dRHS_3, err] = sparse_hessian_times_B_kronecker_C(g2(:,k2yy0ex0(nonzeros(klead),nonzeros(klead))), oo.dr.ghu(klead~=0,:), dghu(klead~=0,:,jp),threads_BC); mexErrCheck('sparse_hessian_times_B_kronecker_C', err); + 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.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 + diff --git a/matlab/get_perturbation_params_derivs_numerical_objective.m b/matlab/get_perturbation_params_derivs_numerical_objective.m new file mode 100644 index 0000000000000000000000000000000000000000..e108704f875d069c8f087884d1ff8b6f68af7464 --- /dev/null +++ b/matlab/get_perturbation_params_derivs_numerical_objective.m @@ -0,0 +1,109 @@ +function [out,info] = get_perturbation_params_derivs_numerical_objective(params, outputflag, estim_params, M, oo, options) +%function [out,info] = get_perturbation_params_derivs_numerical_objective(params, outputflag, estim_params, M, oo, options) +% ------------------------------------------------------------------------- +% Objective function to compute numerically the Jacobians used for get_perturbation_params_derivs +% ========================================================================= +% INPUTS +% params: [vector] parameter values at which to evaluate objective function +% stderr parameters come first, corr parameters second, model parameters third +% outputflag: [string] flag which objective to compute (see below) +% estim_params: [structure] storing the estimation information +% M: [structure] storing the model information +% oo: [structure] storing the solution results +% options: [structure] storing the options +% ------------------------------------------------------------------------- +% +% OUTPUT (dependent on outputflag and order of approximation): +% - 'perturbation_solution': out = [vec(Sigma_e);vec(ghx);vec(ghu);vec(ghxx);vec(ghxu);vec(ghuu);vec(ghs2);vec(ghxxx);vec(ghxxu);vec(ghxuu);vec(ghuuu);vec(ghxss);vec(ghuss)] +% - 'dynamic_model': out = [Yss; vec(g1); vec(g2); vec(g3)] +% - 'Kalman_Transition': out = [Yss; vec(KalmanA); dyn_vech(KalmanB*Sigma_e*KalmanB')]; +% all in DR-order +% ------------------------------------------------------------------------- +% This function is called by +% * get_solution_params_deriv.m (previously getH.m) +% * get_identification_jacobians.m (previously getJJ.m) +% ------------------------------------------------------------------------- +% This function calls +% * [M.fname,'.dynamic'] +% * resol +% * dyn_vech +% ========================================================================= +% Copyright (C) 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/>. +% ========================================================================= + +%% Update stderr, corr and model parameters and compute perturbation approximation and steady state with updated parameters +M = set_all_parameters(params,estim_params,M); +Sigma_e = M.Sigma_e; +[~,info,M,options,oo] = resol(0,M,options,oo); + +if info(1) > 0 + % there are errors in the solution algorithm + out = []; + return +else + ys = oo.dr.ys; %steady state of model variables in declaration order + ghx = oo.dr.ghx; ghu = oo.dr.ghu; + if options.order > 1 + ghxx = oo.dr.ghxx; ghxu = oo.dr.ghxu; ghuu = oo.dr.ghuu; ghs2 = oo.dr.ghs2; + %ghxs = oo.dr.ghxs; ghus = oo.dr.ghus; %these are zero due to certainty equivalence and Gaussian shocks + end + if options.order > 2 + ghxxx = oo.dr.ghxxx; ghxxu = oo.dr.ghxxu; ghxuu = oo.dr.ghxuu; ghxss = oo.dr.ghxss; ghuuu = oo.dr.ghuuu; ghuss = oo.dr.ghuss; + %ghxxs = oo.dr.ghxxs; ghxus = oo.dr.ghxus; ghuus = oo.dr.ghuus; ghsss = oo.dr.ghsss; %these are zero due to certainty equivalence and Gaussian shocks + end +end +Yss = ys(oo.dr.order_var); %steady state of model variables in DR order + +%% out = [vec(Sigma_e);vec(ghx);vec(ghu);vec(ghxx);vec(ghxu);vec(ghuu);vec(ghs2);vec(ghxxx);vec(ghxxu);vec(ghxuu);vec(ghuuu);vec(ghxss);vec(ghuss)] +if strcmp(outputflag,'perturbation_solution') + out = [Sigma_e(:); ghx(:); ghu(:)]; + if options.order > 1 + out = [out; ghxx(:); ghxu(:); ghuu(:); ghs2(:);]; + end + if options.order > 2 + out = [out; ghxxx(:); ghxxu(:); ghxuu(:); ghuuu(:); ghxss(:); ghuss(:)]; + end +end + +%% out = [Yss; vec(g1); vec(g2); vec(g3)]; of all endogenous variables, in DR order +if strcmp(outputflag,'dynamic_model') + [I,~] = find(M.lead_lag_incidence'); %I is used to evaluate dynamic model files + if options.order == 1 + [~, g1] = feval([M.fname,'.dynamic'], ys(I), oo.exo_steady_state', M.params, ys, 1); + out = [Yss; g1(:)]; + elseif options.order == 2 + [~, g1, g2] = feval([M.fname,'.dynamic'], ys(I), oo.exo_steady_state', M.params, ys, 1); + out = [Yss; g1(:); g2(:)]; + elseif options.order == 3 + [~, g1, g2, g3] = feval([M.fname,'.dynamic'], ys(I), oo.exo_steady_state', M.params, ys, 1); + g3 = unfold_g3(g3, length(ys(I))+M.exo_nbr); + out = [Yss; g1(:); g2(:); g3(:)]; + end +end + +%% out = [Yss; vec(KalmanA); dyn_vech(KalmanB*Sigma_e*KalmanB')]; in DR order, where A and B are Kalman transition matrices +if strcmp(outputflag,'Kalman_Transition') + if options.order == 1 + KalmanA = zeros(M.endo_nbr,M.endo_nbr); + KalmanA(:,M.nstatic+(1:M.nspred)) = ghx; + Om = ghu*Sigma_e*transpose(ghu); + out = [Yss; KalmanA(:); dyn_vech(Om)]; + else + error('''get_perturbation_params_derivs_numerical_objective.m'': Kalman_Transition works only at order=1'); + end +end diff --git a/matlab/identification_numerical_objective.m b/matlab/identification_numerical_objective.m index 3de182d9fca3be8e3a25d53778c7a5fa843c942c..c7acf5e4b4d9960f20a6fc5e53ce886748a20eb1 100644 --- a/matlab/identification_numerical_objective.m +++ b/matlab/identification_numerical_objective.m @@ -92,17 +92,6 @@ end ys = oo.dr.ys; %steady state of model variables in declaration order y0 = ys(oo.dr.order_var); %steady state of model variables in DR order -%% out = [Yss; vec(A); vec(B); dyn_vech(Sig_e)]; of indvar variables only, in DR order -if outputflag == 0 - out = [y0(indvar); vec(A(indvar,indvar)); vec(B(indvar,:)); dyn_vech(M.Sigma_e)]; -end - -%% out = [Yss; vec(A); dyn_vech(Om)]; of indvar variables only, in DR order -if outputflag == -2 - Om = B*M.Sigma_e*transpose(B); - out = [y0(indvar); vec(A(indvar,indvar)); dyn_vech(Om(indvar,indvar))]; -end - %% out = [vech(cov(Y_t,Y_t)); vec(cov(Y_t,Y_{t-1}); ...; vec(cov(Y_t,Y_{t-nlags})] of indvar variables, in DR order. This is Iskrev (2010)'s J matrix. if outputflag == 1 % Denote Ezz0 = E_t(z_t * z_t'), then the following Lyapunov equation defines the autocovariagrom: Ezz0 -A*Ezz*A' = B*Sig_e*B' @@ -145,14 +134,4 @@ if outputflag == 2 kk = kk+1; out(1 + (kk-1)*var_nbr^2 : kk*var_nbr^2) = g_omega(:); end -end - - -%% out = [Yss; vec(g1)]; of all endogenous variables, in DR order -if outputflag == -1 - [I,~] = find(M.lead_lag_incidence'); %I is used to evaluate dynamic model files - yy0 = oo.dr.ys(I); %steady state of dynamic model variables in DR order - ex0 = oo.exo_steady_state'; - [~, g1] = feval([M.fname,'.dynamic'], yy0, ex0, M.params, ys, 1); - out = [y0; g1(:)]; -end +end \ No newline at end of file diff --git a/matlab/unfold_g4.m b/matlab/unfold_g4.m new file mode 100644 index 0000000000000000000000000000000000000000..7c35456b43e4c48bd5b1d71589fc69b97ac24f59 --- /dev/null +++ b/matlab/unfold_g4.m @@ -0,0 +1,46 @@ +function g4_unfolded = unfold_g4(g4, ny) +% Given the 4th order derivatives stored in a sparse matrix and without +% symmetric elements (as returned by the static/dynamic files) and the number +% of (static or dynamic) variables in the jacobian, returns +% an unfolded version of the same matrix (i.e. with symmetric elements). + +% Copyright (C) 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/>. + +[i, j, v] = find(g4); + +i_unfolded = []; +j_unfolded = []; +v_unfolded = []; + +for k = 1:length(v) + l1 = rem(j(k)-1, ny); + j2 = floor((j(k)-1)/ny); + l2 = rem(j2, ny); + j3 = floor((j(k)-1)/ny^2); + l3 = rem(j3,ny); + l4 = floor(j3/ny); + + p = unique(perms([l1 l2 l3 l4]), 'rows'); + np = rows(p); + + i_unfolded = [i_unfolded; repmat(i(k), np, 1)]; + j_unfolded = [j_unfolded; 1 + p(:,1) + ny*(p(:,2) + ny*(p(:,3) + ny*p(:,4)))]; + v_unfolded = [v_unfolded; repmat(v(k), np, 1)]; +end + +g4_unfolded = sparse(i_unfolded, j_unfolded, v_unfolded, size(g4, 1), size(g4, 2)); diff --git a/tests/.gitignore b/tests/.gitignore index 7e271be0bd7ba77044b4ee179efbd3facabcb638..e7925b2d482816d9995679ef09a0bc939a55ef19 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -33,6 +33,7 @@ wsOct !/AIM/fs2000_b1L1L_steadystate.m !/AIM/fsdat.m !/analytic_derivatives/fsdat_simul.m +!/analytic_derivatives/nBrockMirmanSYM.mat !/block_bytecode/run_ls2003.m !/bvar_a_la_sims/bvar_sample.m !/conditional_forecasts/2/fsdat_simul.m @@ -67,6 +68,7 @@ wsOct !/gsa/ls2003scr_results.mat !/gsa/morris/nk_est_data.m !/identification/as2007/as2007_steadystate.m +!/identification/as2007/G_QT.mat !/identification/kim/kim2_steadystate.m !/initval_file/ramst_initval_file_data.m !/internals/tests.m diff --git a/tests/Makefile.am b/tests/Makefile.am index 8f2e014910ada107d9079ac44dbf6d115cd885b9..06d2a13f14ee7baac69bdeaebc7cbee60db987ca 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,6 +19,9 @@ MODFILES = \ optimizers/fs2000_9.mod \ optimizers/fs2000_10.mod \ analytic_derivatives/fs2000_analytic_derivation.mod \ + analytic_derivatives/BrockMirman_PertParamsDerivs.mod \ + analytic_derivatives/burnside_3_order_PertParamsDerivs.mod \ + analytic_derivatives/LindeTrabandt2019.mod \ measurement_errors/fs2000_corr_me_ml_mcmc/fs2000_corr_ME.mod \ TeX/fs2000_corr_ME.mod \ estimation/MH_recover/fs2000_recover_tarb.mod \ @@ -383,6 +386,7 @@ XFAIL_MODFILES = ramst_xfail.mod \ estimation/fs2000_mixed_ML_xfail.mod \ estimation/fs2000_stochastic_singularity_xfail.mod \ identification/ident_unit_root/ident_unit_root_xfail.mod \ + identification/LindeTrabandt/LindeTrabandt2019_xfail.mod \ steady_state/Linear_steady_state_xfail.mod \ optimal_policy/Ramsey/ramsey_histval_xfail.mod \ example1_extra_exo_xfail.mod @@ -696,6 +700,10 @@ identification: m/identification o/identification m/identification: $(patsubst %.mod, %.m.trs, $(filter identification/%.mod, $(MODFILES))) o/identification: $(patsubst %.mod, %.o.trs, $(filter identification/%.mod, $(MODFILES))) +analytic_derivatives: m/analytic_derivatives o/analytic_derivatives +m/analytic_derivatives: $(patsubst %.mod, %.m.trs, $(filter analytic_derivatives/%.mod, $(MODFILES))) +o/analytic_derivatives: $(patsubst %.mod, %.o.trs, $(filter analytic_derivatives/%.mod, $(MODFILES))) + fs2000: m/fs2000 o/fs2000 m/fs2000: $(patsubst %.mod, %.m.trs, $(filter fs2000/%.mod, $(MODFILES))) o/fs2000: $(patsubst %.mod, %.o.trs, $(filter fs2000/%.mod, $(MODFILES))) @@ -813,6 +821,7 @@ EXTRA_DIST = \ data/test.xlsx \ gsa/morris/nk_est_data.m \ analytic_derivatives/fsdat_simul.m \ + analytic_derivatives/nBrockMirmanSYM.mat \ fs2000/fsdat_simul.m \ ls2003/data_ca1.m \ measurement_errors/data_ca1.m \ @@ -848,6 +857,7 @@ EXTRA_DIST = \ kalman/likelihood_from_dynare/fs2000_estimation_check.inc \ kalman/likelihood_from_dynare/fs2000ns_model.inc \ kalman/likelihood_from_dynare/fs2000ns_estimation_check.inc \ + identification/as2007/G_QT.mat \ estimation/fsdat_simul.m \ ep/mean_preserving_spread.m \ decision_rules/example1_results_dyn_432.mat \ diff --git a/tests/analytic_derivatives/BrockMirman_PertParamsDerivs.mod b/tests/analytic_derivatives/BrockMirman_PertParamsDerivs.mod new file mode 100644 index 0000000000000000000000000000000000000000..280ae10cc66d91023f1e48b8c702d86f43d793fd --- /dev/null +++ b/tests/analytic_derivatives/BrockMirman_PertParamsDerivs.mod @@ -0,0 +1,474 @@ +% "Augmented" Brock Mirman model +% True policy functions and their exact derivatives (ghx,ghu,ghxx,ghxu,ghuu,ghs2,ghxxx,ghxxu,ghxuu,ghuuu,ghxss,ghuss) are computed using Matlab's symbolic toolbox and saved to a mat file +% Created by @wmutschl (Willi Mutschler, willi@mutschler.eu) + +% ========================================================================= +% Copyright (C) 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/>. +% ========================================================================= + + +@#define CREATE_SYMBOLIC = 0 +@#define ORDER = 3 + +%define parameter values which are used for calibration and estimated_params block +@#define value_SE_A = 0.3 +@#define value_SE_X = 0.1 +@#define value_SE_Y = 0.9 +@#define value_rho_AX = 0.4 +@#define value_alph = 0.35 +@#define value_betta = 0.99 +@#define value_rhoA = 0.9 +@#define value_sigA = 0.6 +@#define value_sigX = 0.25 +@#define value_Xss = 1.2 +@#define value_dumA = 2 +@#define value_dumK = 1 +@#define value_dumepsA = 4 +@#define value_dumepsX = 5 + + +%define parameter values which are used for estimated_params block, note that all are different +@#define prior_value_SE_A = 0.8 +@#define prior_value_SE_X = 0.6 +@#define prior_value_SE_Y = 0.1 +@#define prior_value_rho_AX = 0.1 +@#define prior_value_alph = 0.15 +@#define prior_value_betta = 0.92 +@#define prior_value_rhoA = 0.3 +@#define prior_value_sigA = 0.3 +@#define prior_value_sigX = 0.15 +@#define prior_value_Xss = 1.1 +@#define prior_value_dumA = 2 +@#define prior_value_dumK = 1 +@#define prior_value_dumepsA = 5 +@#define prior_value_dumepsX = 6 + +var Y X K C A W Z; %note that declaration order is different from DR order on purpose +varobs C K A; +varexo epsA epsX epsY; +parameters alph betta rhoA sigA sigX Xss dumA dumK dumepsA dumepsX; + +%Calibration +alph = @{value_alph}; +betta = @{value_betta}; +rhoA = @{value_rhoA}; +sigA = @{value_sigA}; +sigX = @{value_sigX}; +Xss = @{value_Xss}; +dumA = @{value_dumA}; +dumK = @{value_dumK}; +dumepsA = @{value_dumepsA}; +dumepsX = @{value_dumepsX}; + +model; +%this is original Brock-Mirman model equations with AR(1) shock +C^(-1) = alph*betta*C(+1)^(-1)*A(+1)*K^(alph-1); +K = A*K(-1)^alph - C; +log(A) = rhoA*log(A(-1)) + sigA*epsA; +Y = A*K(-1)^alph + epsY; +%augmented auxiliary equations to get nonzero ghs2, ghxss and ghuss, they have no economic meaning +log(X) = log(Xss) + sigX*epsX; +W = X(+1)*exp(dumA*A(-1))*exp(dumK*K(-1)); %this will get a nonzero ghs2 and ghxss +Z = X(+1)*exp(dumepsA*epsA)*exp(dumepsX*epsX); %this will get a nonzero ghs2 and ghuss +end; + +shocks; +var epsA = (@{value_SE_A})^2; +var epsX = (@{value_SE_X})^2; +var epsA, epsX = @{value_rho_AX}*@{value_SE_A}*@{value_SE_X}; +var epsY = (@{value_SE_Y})^2; +end; + +steady_state_model; +X = Xss; +A = 1; +K = (alph*betta*A)^(1/(1-alph)); +C = A*K^alph-K; +Y = A*K^alph; +W = Xss*exp(dumA*A)*exp(dumK*K); +Z = Xss*exp(dumepsA*0)*exp(dumepsX*0); +end; + +estimated_params;%note that the parameter ordering is different than declaration order +rhoA, normal_pdf, @{prior_value_rhoA}, 0.1; +betta, normal_pdf, @{prior_value_betta}, 0.1; +alph, normal_pdf, @{prior_value_alph}, 0.1; +corr epsA, epsX, normal_pdf, @{prior_value_rho_AX}, 0.1; +sigA, normal_pdf, @{prior_value_sigA}, 0.1; +stderr epsA, normal_pdf, @{prior_value_SE_A}, 0.1; +stderr epsX, normal_pdf, @{prior_value_SE_X}, 0.1; +stderr epsY, normal_pdf, @{prior_value_SE_Y}, 0.1; +sigX, normal_pdf, @{prior_value_sigX}, 0.1; +Xss, normal_pdf, @{prior_value_Xss}, 0.1; +dumepsX, normal_pdf, @{prior_value_dumepsX}, 0.1; +dumK, normal_pdf, @{prior_value_dumK}, 0.1; +dumepsA, normal_pdf, @{prior_value_dumepsA}, 0.1; +dumA, normal_pdf, @{prior_value_dumA}, 0.1; +end; + +%save calibration parameters as these get overwritten through stoch_simul and identification command +calib_params = M_.params; +calib_Sigma_e = M_.Sigma_e; + +stoch_simul(order=@{ORDER},nograph,irf=0,periods=0); +identification(order=@{ORDER},nograph,no_identification_strength); + +indpmodel = estim_params_.param_vals(:,1); +indpstderr = estim_params_.var_exo(:,1); +indpcorr = estim_params_.corrx(:,1:2); +[I,~] = find(M_.lead_lag_incidence'); + +%% Parameter derivatives of perturbation +@#if CREATE_SYMBOLIC == 1 + syms Y_ Y0 Yp C_ C0 Cp K_ K0 Kp A_ A0 Ap X_ X0 Xp W_ W0 Wp Z_ Z0 Zp; + syms epsA0 epsX0 epsY0; + syms RHO_AX SE_A SE_X SE_Y ALPH BETTA RHOA SIGA SIGX XSS DUMA DUMK DUMEPSA DUMEPSX; + syms sig; + + SYM.corr_params = [RHO_AX]; + SYM.stderr_params_decl = [SE_A SE_X SE_Y]; + SYM.modparams_decl = [ALPH BETTA RHOA SIGA SIGX XSS DUMA DUMK DUMEPSA DUMEPSX]; + SYM.endo_decl_ = [Y_ X_ K_ C_ A_ W_ Z_]; + SYM.endo_decl0 = [Y0 X0 K0 C0 A0 W0 Z0]; + SYM.endo_declp = [Yp Xp Kp Cp Ap Wp Zp]; + SYM.ex0 = [epsA0 epsX0 epsY0]; + SYM.model_eqs = [C0^(-1)-ALPH*BETTA*Cp^(-1)*Ap*K0^(ALPH-1); + K0-A0*K_^ALPH+C0; + log(A0)-RHOA*log(A_)-SIGA*epsA0; + Y0 - A0*K_^ALPH - epsY0; + log(X0)-log(XSS)-SIGX*epsX0; + W0 - Xp*exp(DUMA*A_)*exp(DUMK*K_); + Z0 - Xp*exp(DUMEPSA*epsA0)*exp(DUMEPSX*epsX0); + ]; + SYM.Sigma_e = [SE_A^2 RHO_AX*SE_A*SE_X 0; RHO_AX*SE_A*SE_X SE_X^2 0; 0 0 SE_Y^2]; + SYM.Correlation_matrix = [1 RHO_AX 0; RHO_AX 1 0; 0 0 1]; + %steady states + SYM.epsAbar = sym(0); + SYM.epsXbar = sym(0); + SYM.epsYbar = sym(0); + SYM.Abar = sym(1); + SYM.Xbar = XSS; + SYM.Kbar = (ALPH*BETTA*SYM.Abar)^(1/(1-ALPH)); + SYM.Cbar = SYM.Abar*SYM.Kbar^ALPH-SYM.Kbar; + SYM.Ybar = SYM.Abar*SYM.Kbar^ALPH; + SYM.Wbar = XSS*exp(DUMA*SYM.Abar)*exp(DUMK*SYM.Kbar); + SYM.Zbar = XSS*exp(DUMEPSA*0)*exp(DUMEPSX*0); + SYM.endo_bar_decl = [SYM.Ybar SYM.Xbar SYM.Kbar SYM.Cbar SYM.Abar SYM.Wbar SYM.Zbar]; + SYM.ex0bar = [SYM.epsAbar SYM.epsXbar SYM.epsYbar]; + %True policy functions (in declaration order): gs is used for derivatives wrt to perturbation parameter + SYM.g = [A_^RHOA*K_^ALPH*exp(SIGA*epsA0) + epsY0; %Y + XSS*exp(SIGX*epsX0); %X + ALPH*BETTA*A_^RHOA*K_^ALPH*exp(SIGA*epsA0); %K + (1-ALPH*BETTA)*A_^RHOA*K_^ALPH*exp(SIGA*epsA0); %C + A_^RHOA*exp(SIGA*epsA0); %A + XSS*exp(SIGX*0)*exp(DUMA*A_)*exp(DUMK*K_); %W + XSS*exp(SIGX*0)*exp(DUMEPSA*epsA0)*exp(DUMEPSX*epsX0); %Z + ]; + SYM.gs = [A_^RHOA*K_^ALPH*exp(SIGA*sig*epsA0) + sig*epsY0; %Y + XSS*exp(SIGX*sig*epsX0); %X + ALPH*BETTA*A_^RHOA*K_^ALPH*exp(SIGA*sig*epsA0); %K + (1-ALPH*BETTA)*A_^RHOA*K_^ALPH*exp(SIGA*sig*epsA0); %C + A_^RHOA*exp(SIGA*sig*epsA0); %A + XSS*(1+1/2*SIGX^2*sig^2*SE_X^2)*exp(DUMA*A_)*exp(DUMK*K_); %W + XSS*(1+1/2*SIGX^2*sig^2*SE_X^2)*exp(DUMEPSA*epsA0)*exp(DUMEPSX*epsX0); %Z + ]; + %put into in DR-order + SYM.g = SYM.g(oo_.dr.order_var); + SYM.gs = SYM.gs(oo_.dr.order_var); + SYM.endo_DR_ = SYM.endo_decl_(oo_.dr.order_var); + SYM.endo_DR0 = SYM.endo_decl0(oo_.dr.order_var); + SYM.endo_DRp = SYM.endo_declp(oo_.dr.order_var); + SYM.Yss = SYM.endo_bar_decl(oo_.dr.order_var); + SYM.yy0 = [SYM.endo_decl_(M_.lead_lag_incidence(1,:)~=0) SYM.endo_decl0(M_.lead_lag_incidence(2,:)~=0) SYM.endo_declp(M_.lead_lag_incidence(3,:)~=0)]; + SYM.yy0ex0 = [SYM.yy0 SYM.ex0]; + SYM.yy0ex0bar = [SYM.endo_bar_decl(I) SYM.ex0bar]; + SYM.x = SYM.endo_DR_(M_.nstatic + (1:M_.nspred)); + SYM.xbar = SYM.Yss(M_.nstatic + (1:M_.nspred)); + SYM.stderr_params = SYM.stderr_params_decl(indpstderr); + SYM.modparams = SYM.modparams_decl(indpmodel); + SYM.params = [SYM.stderr_params SYM.corr_params SYM.modparams]; + SYM.yy0ex0_nbr = length(SYM.yy0ex0); + + %% Parameter derivatives + SYM.dYss = jacobian(SYM.Yss,SYM.modparams); + SYM.d2Yss = jacobian(SYM.dYss(:),SYM.modparams); + SYM.g1 = jacobian(SYM.model_eqs,SYM.yy0ex0); + SYM.g2 = reshape(jacobian(vec(SYM.g1),SYM.yy0ex0),M_.endo_nbr,SYM.yy0ex0_nbr^2); + for j = 1:M_.endo_nbr + SYM.g3(j,:) = vec(transpose(jacobian(vec(SYM.g2(j,:)),SYM.yy0ex0))); %dynare ordering + end + SYM.dg1 = jacobian(vec(subs(SYM.g1,SYM.yy0ex0,SYM.yy0ex0bar)),SYM.modparams); + SYM.dg2 = jacobian(vec(subs(SYM.g2,SYM.yy0ex0,SYM.yy0ex0bar)),SYM.modparams); + SYM.dg3 = jacobian(vec(subs(SYM.g3,SYM.yy0ex0,SYM.yy0ex0bar)),SYM.modparams); + SYM.dSigma_e = jacobian(SYM.Sigma_e(:),SYM.params); + SYM.dCorrelation_matrix = jacobian(SYM.Correlation_matrix(:),SYM.params); + SYM.ghx = jacobian(SYM.g,SYM.x); + SYM.KalmanA = sym(zeros(M_.endo_nbr,M_.endo_nbr)); + SYM.KalmanA(:,M_.nstatic + (1:M_.nspred)) = SYM.ghx; + SYM.dghx = jacobian(vec(subs(SYM.ghx, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dKalmanA = jacobian(vec(subs(SYM.KalmanA, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.d2KalmanA = jacobian(SYM.dKalmanA(:),SYM.params); + SYM.ghu = jacobian(SYM.g,SYM.ex0); + SYM.dghu = jacobian(vec(subs(SYM.ghu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.Om = SYM.ghu*SYM.Sigma_e*transpose(SYM.ghu); + SYM.dOm = jacobian(vec(subs(SYM.Om,[SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.d2Om = jacobian(SYM.dOm(:),SYM.params); + SYM.ghxx = jacobian(SYM.ghx(:),SYM.x); + SYM.ghxx = reshape(SYM.ghxx,M_.endo_nbr,M_.nspred^2); + SYM.dghxx = jacobian(vec(subs(SYM.ghxx, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.ghxu = jacobian(SYM.ghu(:),SYM.x); + SYM.ghxu = reshape(SYM.ghxu,M_.endo_nbr,M_.nspred*M_.exo_nbr); + SYM.dghxu = jacobian(vec(subs(SYM.ghxu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.ghuu = jacobian(SYM.ghu(:),SYM.ex0); + SYM.ghuu = reshape(SYM.ghuu,M_.endo_nbr,M_.exo_nbr*M_.exo_nbr); + SYM.dghuu = jacobian(vec(subs(SYM.ghuu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.ghs2 = jacobian(jacobian(SYM.gs,sig),sig); + SYM.dghs2 = jacobian(vec(subs(SYM.ghs2, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + for j = 1:M_.endo_nbr + SYM.ghxxx(j,:) = vec(transpose(jacobian(vec(SYM.ghxx(j,:)),SYM.x))); %dynare ordering + SYM.ghxxu(j,:) = vec(transpose(jacobian(vec(SYM.ghxx(j,:)),SYM.ex0))); %dynare ordering + SYM.ghxuu(j,:) = vec(transpose(jacobian(vec(SYM.ghxu(j,:)),SYM.ex0))); %dynare ordering + SYM.ghuuu(j,:) = vec(transpose(jacobian(vec(SYM.ghuu(j,:)),SYM.ex0))); %dynare ordering + SYM.ghxss(j,:) = vec(transpose(jacobian(vec(SYM.ghs2(j,:)),SYM.x))); %dynare ordering + SYM.ghuss(j,:) = vec(transpose(jacobian(vec(SYM.ghs2(j,:)),SYM.ex0))); %dynare ordering + end + SYM.dghxxx = jacobian(vec(subs(SYM.ghxxx, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dghxxu = jacobian(vec(subs(SYM.ghxxu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dghxuu = jacobian(vec(subs(SYM.ghxuu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dghuuu = jacobian(vec(subs(SYM.ghuuu, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dghxss = jacobian(vec(subs(SYM.ghxss, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + SYM.dghuss = jacobian(vec(subs(SYM.ghuss, [SYM.x SYM.ex0], [SYM.xbar SYM.ex0bar])),SYM.params); + + % Evaluate numerically + for jj = 1:2 + if jj == 1 + RHO_AX = @{prior_value_rho_AX}; + SE_A = @{prior_value_SE_A}; + SE_X = @{prior_value_SE_X}; + SE_Y = @{prior_value_SE_Y}; + ALPH = @{prior_value_alph}; + BETTA = @{prior_value_betta}; + RHOA = @{prior_value_rhoA}; + SIGA = @{prior_value_sigA}; + SIGX = @{prior_value_sigX}; + XSS = @{prior_value_Xss}; + DUMA = @{prior_value_dumA}; + DUMK = @{prior_value_dumK}; + DUMEPSA = @{prior_value_dumepsA}; + DUMEPSX = @{prior_value_dumepsX}; + elseif jj == 2 + RHO_AX = @{value_rho_AX}; + SE_A = @{value_SE_A}; + SE_X = @{value_SE_X}; + SE_Y = @{value_SE_Y}; + ALPH = @{value_alph}; + BETTA = @{value_betta}; + RHOA = @{value_rhoA}; + SIGA = @{value_sigA}; + SIGX = @{value_sigX}; + XSS = @{value_Xss}; + DUMA = @{value_dumA}; + DUMK = @{value_dumK}; + DUMEPSA = @{value_dumepsA}; + DUMEPSX = @{value_dumepsX}; + end + sig = 1; + + nSYM.Yss = transpose(double(subs(SYM.Yss))); + nSYM.dYss = reshape(double(subs(SYM.dYss)), M_.endo_nbr, length(SYM.modparams)); + nSYM.d2Yss = double(reshape(subs(SYM.d2Yss), [M_.endo_nbr length(SYM.modparams) length(SYM.modparams)])); + nSYM.g1 = double(subs(subs(SYM.g1, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dg1 = reshape(double(subs(SYM.dg1)),M_.endo_nbr, SYM.yy0ex0_nbr, length(SYM.modparams)); + nSYM.g2 = sparse(double(subs(subs(SYM.g2, SYM.yy0ex0, SYM.yy0ex0bar)))); + nSYM.dg2 = reshape(sparse(double(subs(SYM.dg2))), M_.endo_nbr, SYM.yy0ex0_nbr^2*length(SYM.modparams)); + nSYM.g3 = sparse(double(subs(subs(SYM.g3, SYM.yy0ex0, SYM.yy0ex0bar)))); + nSYM.dg3 = reshape(sparse(double(subs(SYM.dg3))), M_.endo_nbr, SYM.yy0ex0_nbr^3*length(SYM.modparams)); + nSYM.Sigma_e = double(subs(SYM.Sigma_e)); + nSYM.dSigma_e = double(reshape(subs(SYM.dSigma_e), M_.exo_nbr, M_.exo_nbr,length(SYM.params))); + nSYM.Correlation_matrix = double(subs(SYM.Correlation_matrix)); + nSYM.dCorrelation_matrix = double(reshape(subs(SYM.dCorrelation_matrix), M_.exo_nbr, M_.exo_nbr,length(SYM.params))); + nSYM.ghx = double(subs(subs(SYM.ghx, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghx = reshape(double(subs(SYM.dghx)), M_.endo_nbr, M_.nspred, length(SYM.params)); + nSYM.ghu = double(subs(subs(SYM.ghu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghu = reshape(double(subs(SYM.dghu)), M_.endo_nbr, M_.exo_nbr, length(SYM.params)); + nSYM.Om = double(subs(subs(SYM.Om, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dOm = reshape(double(subs(SYM.dOm)), M_.endo_nbr, M_.endo_nbr, length(SYM.params)); + nSYM.d2Om = reshape(sparse(double(subs(SYM.d2Om))), M_.endo_nbr^2, length(SYM.params)^2); + SYM.indp2 = reshape(1:length(SYM.params)^2,length(SYM.params),length(SYM.params)); + SYM.indx2 = reshape(1:M_.endo_nbr^2, M_.endo_nbr, M_.endo_nbr); + nSYM.d2Om = nSYM.d2Om(dyn_vech(SYM.indx2),dyn_vech(SYM.indp2)); + nSYM.KalmanA = double(subs(subs(SYM.KalmanA, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dKalmanA = reshape(double(subs(SYM.dKalmanA)), M_.endo_nbr, M_.endo_nbr, length(SYM.params)); + nSYM.d2KalmanA = reshape(double(subs(SYM.d2KalmanA)), M_.endo_nbr^2, length(SYM.params)^2); + nSYM.d2KalmanA = nSYM.d2KalmanA(:,dyn_vech(SYM.indp2)); + nSYM.ghxx = double(subs(subs(SYM.ghxx, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxx = reshape(double(subs(SYM.dghxx)), M_.endo_nbr, M_.nspred^2, length(SYM.params)); + nSYM.ghxu = double(subs(subs(SYM.ghxu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxu = reshape(double(subs(SYM.dghxu)), M_.endo_nbr, M_.nspred*M_.exo_nbr, length(SYM.params)); + nSYM.ghuu = double(subs(subs(SYM.ghuu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghuu = reshape(double(subs(SYM.dghuu)), M_.endo_nbr, M_.exo_nbr^2, length(SYM.params)); + nSYM.ghs2 = double(subs(subs(SYM.ghs2, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghs2 = reshape(double(subs(SYM.dghs2)), M_.endo_nbr, length(SYM.params)); + nSYM.ghxxx = double(subs(subs(SYM.ghxxx, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxxx = reshape(double(subs(SYM.dghxxx)), M_.endo_nbr, M_.nspred^3, length(SYM.params)); + nSYM.ghxxu = double(subs(subs(SYM.ghxxu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxxu = reshape(double(subs(SYM.dghxxu)), M_.endo_nbr, M_.nspred^2*M_.exo_nbr, length(SYM.params)); + nSYM.ghxuu = double(subs(subs(SYM.ghxuu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxuu = reshape(double(subs(SYM.dghxuu)), M_.endo_nbr, M_.nspred*M_.exo_nbr^2, length(SYM.params)); + nSYM.ghuuu = double(subs(subs(SYM.ghuuu, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghuuu = reshape(double(subs(SYM.dghuuu)), M_.endo_nbr, M_.exo_nbr^3, length(SYM.params)); + nSYM.ghxss = double(subs(subs(SYM.ghxss, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghxss = reshape(double(subs(SYM.dghxss)), M_.endo_nbr, M_.nspred, length(SYM.params)); + nSYM.ghuss = double(subs(subs(SYM.ghuss, SYM.yy0ex0, SYM.yy0ex0bar))); + nSYM.dghuss = reshape(double(subs(SYM.dghuss)), M_.endo_nbr, M_.exo_nbr, length(SYM.params)); + if jj == 1 + nSYMprior = nSYM; + save('nBrockMirmanSYM.mat','nSYMprior') + elseif jj==2 + nSYMcalib = nSYM; + save('nBrockMirmanSYM.mat','nSYMcalib','-append') + end + end +@#endif + + +clc; +tol_vars.Yss = 1e-14; +tol_vars.Sigma_e = 1e-15; +tol_vars.Correlation_matrix = 1e-16; +tol_vars.g1 = 1e-13; +tol_vars.ghx = 1e-13; +tol_vars.ghu = 1e-13; +@#if ORDER > 1 +tol_vars.g2 = 1e-12; +tol_vars.ghxx = 1e-12; +tol_vars.ghxu = 1e-12; +tol_vars.ghuu = 1e-12; +tol_vars.ghs2 = 1e-12; +@#endif +@#if ORDER > 2 +tol_vars.g3 = 1e-11; +tol_vars.ghxxx = 1e-11; +tol_vars.ghxxu = 1e-11; +tol_vars.ghxuu = 1e-11; +tol_vars.ghuuu = 1e-11; +tol_vars.ghxss = 1e-11; +tol_vars.ghuss = 1e-11; +@#endif + +tol_dvars.dYss = [1e-9 1e-9 1e-14 1e-14]; +tol_dvars.dSigma_e = [1e-9 1e-15 1e-14 1e-14]; +tol_dvars.dCorrelation_matrix = [1e-9 1e-15 1e-14 1e-14]; +tol_dvars.dg1 = [1e-6 1e-6 1e-13 1e-13]; +tol_dvars.dghx = [1e-8 1e-8 1e-13 1e-13]; +tol_dvars.dghu = [1e-8 1e-8 1e-13 1e-13]; +@#if ORDER > 1 +tol_dvars.dg2 = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghxx = [1e-6 1e-6 1e-12 1e-12]; +tol_dvars.dghxu = [1e-6 1e-6 1e-12 1e-12]; +tol_dvars.dghuu = [1e-6 1e-6 1e-12 1e-12]; +tol_dvars.dghs2 = [1e-6 1e-6 1e-12 1e-12]; +@#endif +@#if ORDER > 2 +tol_dvars.dg3 = [1e-3 1e-3 1e-9 1e-9]; +tol_dvars.dghxxx = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghxxu = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghxuu = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghuuu = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghxss = [1e-5 1e-5 1e-11 1e-11]; +tol_dvars.dghuss = [1e-5 1e-5 1e-11 1e-11]; +@#endif +tol_dvars.d2KalmanA = [1e-3 1e-3 1e-13 1e-13]; +tol_dvars.d2Om = [1e-3 1e-3 1e-13 1e-13]; +tol_dvars.d2Yss = [1e-3 1e-3 1e-13 1e-13]; + +options_.dynatol.x = eps.^(1/3); %set numerical differentiation step in fjaco.m + +for jj = 1:2 + lst_vars = {'Yss', 'Sigma_e', 'Correlation_matrix','g1','ghx','ghu'}; + @#if ORDER > 1 + lst_vars = [lst_vars, 'g2','ghxx','ghxu','ghuu','ghs2']; + @#endif + @#if ORDER > 2 + lst_vars = [lst_vars, 'g3','ghxxx','ghxxu','ghxuu','ghuuu','ghxss','ghuss']; + @#endif + lst_dvars = {'dYss','dSigma_e','dg1','dghx','dghu'}; + @#if ORDER > 1 + lst_dvars = [lst_dvars, 'dg2','dghxx','dghxu','dghuu','dghs2']; + @#endif + @#if ORDER > 2 + lst_dvars = [lst_dvars, 'dg3','dghxxx','dghxxu','dghxuu','dghuuu','dghxss','dghuss']; + @#endif + load('nBrockMirmanSYM.mat'); + if jj==1 + strparamset = 'PRIOR'; + nSYM = nSYMprior; + xparam_prior = set_prior(estim_params_,M_,options_); + M_ = set_all_parameters(xparam_prior,estim_params_,M_); + elseif jj==2 + strparamset = 'CALIBRATION'; + nSYM = nSYMcalib; + xparam1_calib = []; + for j = 1:length(indpstderr) + xparam1_calib = [xparam1_calib; sqrt(calib_Sigma_e(j,j))]; + end + for j = 1:size(indpcorr,1) + xparam1_calib = [xparam1_calib; calib_Sigma_e(indpcorr(j,1),indpcorr(j,2))/( sqrt(calib_Sigma_e(indpcorr(j,1),indpcorr(j,1))) * sqrt(calib_Sigma_e(indpcorr(j,2),indpcorr(j,2))) )]; + end + xparam1_calib = [xparam1_calib; calib_params(indpmodel)]; + M_ = set_all_parameters(xparam1_calib,estim_params_,M_); + end + [~,info,M_,options_,oo_] = resol(0,M_, options_, oo_); + %For convenience we save the objects to compare into oo_.dr. + oo_.dr.Yss = oo_.dr.ys(oo_.dr.order_var); + oo_.dr.Sigma_e = M_.Sigma_e; + oo_.dr.Correlation_matrix = M_.Correlation_matrix; + ex0 = oo_.exo_steady_state'; + [~, oo_.dr.g1, oo_.dr.g2, oo_.dr.g3] = feval([M_.fname,'.dynamic'], oo_.dr.ys(I), oo_.exo_steady_state', M_.params, oo_.dr.ys, 1); + oo_.dr.g3 = unfold_g3(oo_.dr.g3, length(oo_.dr.ys(I))+length(oo_.exo_steady_state')); %add symmetric elements to g3 + + fprintf('***** %s: SOME COMMON OBJECTS *****\n', strparamset) + for id_var = 1:size(lst_vars,2) + dx = norm( nSYM.(sprintf('%s',lst_vars{id_var})) - oo_.dr.(sprintf('%s',lst_vars{id_var})), Inf); + fprintf('Max absolute deviation for %s: %e\n', lst_vars{id_var}, dx); + if dx > tol_vars.(sprintf('%s',lst_vars{id_var})) + error('Something wrong in steady state computation, solution algorithm or preprocessor') + end + end + + + for d2flag = [0 1]; + if d2flag + lst_dvars = [lst_dvars {'d2KalmanA', 'd2Om', 'd2Yss'}]; + end + KRONFLAG = [-1 -2 0 1]; + for id_kronflag = 1:length(KRONFLAG) + fprintf('***** %s: d2flag=%d and kronflag=%d *****\n',strparamset, d2flag,KRONFLAG(id_kronflag)) + options_.analytic_derivation_mode = KRONFLAG(id_kronflag); + DERIVS = get_perturbation_params_derivs(M_, options_, estim_params_, oo_, indpmodel, indpstderr, indpcorr, d2flag); + for id_var = 1:size(lst_dvars,2) + dx = norm( vec(nSYM.(sprintf('%s',lst_dvars{id_var}))) - vec(DERIVS.(sprintf('%s',lst_dvars{id_var}))), Inf); + fprintf('Max absolute deviation for %s: %e\n', lst_dvars{id_var}, dx); + if dx > tol_dvars.(sprintf('%s',lst_dvars{id_var}))(id_kronflag) + error('Something wrong in get_perturbation_params_derivs.m') + end + end + end + end +end + diff --git a/tests/analytic_derivatives/LindeTrabandt2019.mod b/tests/analytic_derivatives/LindeTrabandt2019.mod new file mode 100644 index 0000000000000000000000000000000000000000..67c302596bd38d54db3474db52b90e39d50ba0d2 --- /dev/null +++ b/tests/analytic_derivatives/LindeTrabandt2019.mod @@ -0,0 +1,449 @@ +% Original model by: J. Linde, M. Trabandt (2019: Should We Use Linearized Models to Calculate Fiscal Multipliers? +% Journal of Applied Econometrics, 2018, 33: 937-965. http://dx.doi.org/10.1002/jae.2641 +% This version has some additional dynamics for capital and investment +% Created by @wmutschl (Willi Mutschler, willi@mutschler.eu) + +% ========================================================================= +% Copyright (C) 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/>. +% ========================================================================= + +% ========================================================================= +% Declare endogenous variables +% ========================================================================= + +var + % Staggered-price economy + c ${c}$ (long_name='consumption') + lam ${\lambda}$ (long_name='lagrange multiplier budget') + n ${n}$ (long_name='labor') + w ${w}$ (long_name='real wage') + r ${r}$ (long_name='interest rate') + pie ${\pi}$ (long_name='inflation') + y ${y}$ (long_name='output') + pstar ${p^\ast}$ (long_name='price dispersion') + vartheta ${\vartheta}$ (long_name='aggregate price index') + mc ${mc}$ (long_name='marginal costs') + s ${s}$ (long_name='auxiliary variable for nonlinear pricing 1') + f ${f}$ (long_name='auxiliary variable for nonlinear pricing 2') + a ${a}$ (long_name='auxiliary variable for nonlinear pricing 3') + ptilde ${\tilde{p}}$ (long_name='reoptimized price') + delta1 ${\Delta_1}$ (long_name='price dispersion 1') + delta2 ${\Delta_2}$ (long_name='price dispersion 2') + delta3 ${\Delta_3}$ (long_name='price dispersion 3') + b ${b}$ (long_name='bonds') + tau ${\tau}$ (long_name='lump-sum tax') + g + nu %consumption preference shock + + % Flex-price economy + cpot ${c^{pot}}$ (long_name='flex-price consumption') + npot ${n^{pot}}$ (long_name='flex-price labor') + wpot ${w^{pot}}$ (long_name='flex-price real wage') + rrpot ${r^{pot}}$ (long_name='flex-price interest rate') + ypot ${y^{pot}}$ (long_name='flex-price output') + bpot ${b^{pot}}$ (long_name='flex-price bonds') + taupot ${\tau^{pot}}$ (long_name='flex-price lump-sum tax') + + % Added variables for capital and investment + k ${k}$ (long_name='capital') + rk ${r^{K}}$ (long_name='rental rate on capital') + iv ${i}$ (long_name='investment') + q ${q}$ (long_name='Tobins Q') + kpot ${k^{pot}}$ (long_name='flex-price capital') + rkpot ${r^{K,pot}}$ (long_name='flex-price rental rate on capital') + ivpot ${i^{pot}}$ (long_name='flex-price investment') +; + +% ========================================================================= +% Declare observable variables +% ========================================================================= +varobs c y; + +% ========================================================================= +% Declare exogenous variables +% ========================================================================= +varexo +epsg +epsnu + ; + +% ========================================================================= +% Declare parameters +% ========================================================================= +parameters + ALPHA ${\alpha}$ (long_name='capital share') + BETA ${\beta}$ (long_name='discount rate') + PIEBAR ${\bar{\pi}}$ (long_name='target inflation rate') + IOTA ${\iota}$ (long_name='indexation') + CHI ${\chi}$ (long_name='inverse frisch elasticity') + THETAP ${\theta_p}$ (long_name='net markup') + XIP ${\xi_p}$ (long_name='Calvo probability') + PSI ${\psi}$ (long_name='Kimbal curvature') + GAMMAPIE ${\gamma_\pi}$ (long_name='Taylor rule parameter inflation') + GAMMAX ${\gamma_x}$ (long_name='Taylor rule parameter output') + DELTA ${\delta}$ (long_name='depreciation rate') + QBAR ${\bar{Q}}$ (long_name='steady state Q') + NUBAR ${\bar{\nu}}$ (long_name='steady state consumption preference shock') + BBAR %government debt to annualized output ratio + GBAR_o_YBAR % government consumption ratio + TAUBAR + TAUNBAR + PHI + RHONU + RHOG + SIGNU + SIGG +; + + +% ========================================================================= +% Calibration +% ========================================================================= +BETA = 0.995; +PIEBAR = 1 + 0.005; +ALPHA = 0.3; +NUBAR = 0;%0.01; +BBAR = 0;%0.6; +GBAR_o_YBAR = 0;%0.2; +TAUBAR = 0; +PHI = 0.0101; +IOTA = 0.5; +CHI = 1/0.4; +XIP = 2/3; +PSI = -12.2; +THETAP = 0.1; +GAMMAPIE = 1.5; +GAMMAX = 0.125; +QBAR=1; +DELTA = 0;%0.025; +RHONU = 0.95; +RHOG = 0.95; +SIGG = 0.6/100; +SIGNU = 0.6/100; +TAUNBAR = 0; + +% ======================================================================== +% Model equations +% ========================================================================= +model; +% ------------------------------------------------------------------------- +% Auxiliary expressions +% ------------------------------------------------------------------------- +#OMEGAP = (1+THETAP)*(1+PSI)/(1+PSI+THETAP*PSI); %gross markup +#gammap = pie^IOTA*PIEBAR^(1-IOTA); %indexation rule +%#gammap = PIEBAR; +% ------------------------------------------------------------------------- +% Added equations for capital and investment +% ------------------------------------------------------------------------- +[name='foc household wrt i'] +lam = lam*q; +[name='foc household wrt k'] +lam*q = BETA*lam(+1)*(rk(+1)+ (1-DELTA)*q(+1) ); +[name='capital accumulation'] +k = (1-DELTA)*k(-1) + iv; +[name='capital demand'] +rk=ALPHA*mc*y/k(-1); + +[name='flex price foc household wrt k'] +(cpot-steady_state(cpot)*nu)^(-1) = BETA*(cpot(+1)-steady_state(cpot)*nu(+1))^(-1)*(rkpot(+1) + (1-DELTA) ); +[name='flex price capital accumulation'] +kpot = (1-DELTA)*kpot(-1) + ivpot; +[name='flex price capital demand'] +rkpot=ALPHA/(1+THETAP)*(npot/kpot(-1))^(1-ALPHA); + +% ------------------------------------------------------------------------- +% Actual model equations +% ------------------------------------------------------------------------- +[name='foc household wrt c (marginal utility)'] +(c-steady_state(c)*nu)^(-1) = lam; + +[name='foc household wrt l (leisure vs. labor)'] +n^CHI = (1-TAUNBAR)*lam*w; + +[name='foc household wrt b (Euler equation)'] +lam = BETA*r/pie(+1)*lam(+1); + +[name='aggregate resource constraint'] +y = c + g + iv; + +[name='production function'] +y=pstar^(-1)*k(-1)^ALPHA*n^(1-ALPHA); + +[name='Nonlinear pricing 1'] +s = OMEGAP*lam*y*vartheta^(OMEGAP/(OMEGAP-1))*mc + BETA*XIP*(gammap/pie(+1))^(OMEGAP/(1-OMEGAP))*s(+1); + +[name='Nonlinear pricing 2'] +f = lam*y*vartheta^(OMEGAP/(OMEGAP-1)) + BETA*XIP*(gammap/pie(+1))^(1/(1-OMEGAP))*f(+1); + +[name='Nonlinear pricing 3'] +a = PSI*(OMEGAP-1)*lam*y + BETA*XIP*(gammap/pie(+1))*a(+1); + +[name='Nonlinear pricing 4'] +s = f*ptilde -a*ptilde^(1+OMEGAP/(OMEGAP-1)); + +[name='zero profit condition'] +vartheta = 1 + PSI - PSI*delta2; + +[name='aggregate price index'] +vartheta = delta3; + +[name='overall price dispersion'] +pstar = 1/(1+PSI)*vartheta^(OMEGAP/(OMEGAP-1))*delta1^(OMEGAP/(1-OMEGAP)) + PSI/(1+PSI); + +[name='price dispersion 1'] +delta1^(OMEGAP/(1-OMEGAP)) = (1-XIP)*ptilde^(OMEGAP/(1-OMEGAP)) + XIP*(gammap/pie*delta1(-1))^(OMEGAP/(1-OMEGAP)); + +[name='price dispersion 2'] +delta2 = (1-XIP)*ptilde+XIP*gammap/pie*delta2(-1); + +[name='price dispersion 3'] +delta3^(1/(1-OMEGAP)) = (1-XIP)*ptilde^(1/(1-OMEGAP)) + XIP*(gammap/pie*delta3(-1))^(1/(1-OMEGAP)); + +[name='marginal costs'] +(1-ALPHA)*mc = w*k(-1)^(-ALPHA)*n^ALPHA; + +[name='Taylor Rule'] +r = steady_state(r)*(pie/PIEBAR)^GAMMAPIE*( (y/steady_state(y))/(ypot/steady_state(ypot)) )^GAMMAX; + +[name='government budget'] +b = r(-1)/pie*b(-1) + g/steady_state(y) -TAUNBAR*w*n/steady_state(y) - tau; + +[name='fiscal rule'] +tau = TAUBAR + PHI*(b(-1)-BBAR); + +[name='flex price Euler equation'] +(cpot-steady_state(cpot)*nu)^(-1) = BETA*rrpot*(cpot(+1)-steady_state(cpot)*nu(+1))^(-1); + +[name='flex price foc household wrt l (leisure vs. labor)'] +npot^CHI = (1-TAUNBAR)*(cpot-steady_state(cpot)*nu)^(-1)*wpot; + +[name='flex price wage'] +(1-ALPHA)/(1+THETAP)*kpot(-1)^ALPHA = wpot*npot^ALPHA; + +[name='flex price aggregate resource constraint'] +ypot = cpot + g + ivpot; + +[name='flex price production function'] +ypot=kpot(-1)^ALPHA*npot^(1-ALPHA); + +[name='flex price government budget'] +bpot = rrpot(-1)*bpot(-1) + g/steady_state(y) -TAUNBAR*wpot*npot/steady_state(y) - taupot; + +[name='fiscal rule '] +taupot = TAUBAR + PHI*(bpot(-1)-BBAR); + +g/steady_state(y) - GBAR_o_YBAR = RHOG*(g(-1)/steady_state(y) - GBAR_o_YBAR) + epsg; +nu - NUBAR = RHONU*(nu(-1) - NUBAR) + epsnu; +end; + + +% ========================================================================= +% Steady state using a steady_state_model block +% ========================================================================= + +% steady_state_model; +% OMEGP = (1+THETAP)*(1+PSI)/(1+PSI+THETAP*PSI); +% q = QBAR; +% pie = PIEBAR; +% GAMMAP = PIEBAR^IOTA*PIEBAR^(1-IOTA); +% b = BBAR; +% tau = TAUBAR; +% taun = TAUNBAR; +% nu = NUBAR; +% r = pie/BETA; +% RK = (1/BETA+DELTA-1)*q; % foc k +% aux1 = ( (1-XIP)/(1-XIP*(GAMMAP/pie)^(1/(1-OMEGP)) ) )^(1-OMEGP); +% aux2 = (1-XIP)/(1-XIP*(GAMMAP/pie)); +% ptilde = (1+PSI)/ ( aux1 + PSI*aux2 ); +% delta2 = aux2*ptilde; +% delta3 = aux1*ptilde; +% vartheta = delta3; +% delta1 = ( (1-XIP)/(1-XIP*(GAMMAP/pie)^(OMEGP/(1-OMEGP) )) )^((1-OMEGP)/OMEGP)*ptilde; +% pstar = 1/(1+PSI)*vartheta^(OMEGP/(OMEGP-1))*delta1^(OMEGP/(1-OMEGP)) + PSI/(1+PSI); +% f_o_a = ( vartheta^(OMEGP/(OMEGP-1)) / (1-BETA*XIP*(GAMMAP/pie)^(1/(1-OMEGP))) ) / ( PSI*(OMEGP-1) /(1-BETA*XIP*GAMMAP/pie) ); +% s_o_a = ( OMEGP*vartheta^(OMEGP/(OMEGP-1)) / (1-BETA*XIP*(GAMMAP/pie)^(OMEGP/(1-OMEGP))) ) / ( PSI*(OMEGP-1) /(1-BETA*XIP*GAMMAP/pie) ); +% mc = (f_o_a*ptilde-ptilde^(1+OMEGP/(OMEGP-1)))*s_o_a^(-1); +% +% k_o_n = (RK/(mc*ALPHA))^(1/(ALPHA-1)); +% w = (1-ALPHA)*mc*k_o_n^ALPHA; % labor demand +% y_o_n = pstar^(-1)*k_o_n^ALPHA; % production function +% iv_o_n = DELTA*k_o_n; +% iv_o_y = iv_o_n / y_o_n; +% g_o_y = GBAR_o_YBAR; +% c_o_n = y_o_n - iv_o_n - g_o_y; % market clearing +% +% % The labor level, closed-form solution for labor +% n = (c_o_n^(-1)*w)^(1/(CHI+1)) ; +% % Value of remaining variables +% c = c_o_n*n; +% rk = RK; +% +% +% iv = iv_o_n *n; +% k = k_o_n*n; +% y = y_o_n*n; +% lam = n^CHI/w; +% g = g_o_y*y; +% a = PSI*(OMEGP-1)*y*lam/(1-BETA*XIP*GAMMAP/pie); +% f = f_o_a*a; +% s = f*ptilde - a*ptilde^(1+OMEGP/(OMEGP-1)); +% +% %flex price economy +% bpot = BBAR; +% taupot = TAUBAR; +% taun = TAUNBAR; +% +% rrpot = 1/BETA; +% RKpot = (1/BETA+DELTA-1)*QBAR; % foc k +% rkpot = RKpot; +% +% kpot_o_npot = (RKpot/(ALPHA/(1+THETAP)))^(1/(ALPHA-1)); +% wpot = (1-ALPHA)/(1+THETAP)*kpot_o_npot^ALPHA; % labor demand +% ypot_o_npot = kpot_o_npot^ALPHA; % production function +% ivpot_o_npot = DELTA*kpot_o_npot; +% ivpot_o_ypot = ivpot_o_npot / ypot_o_npot; +% cpot_o_npot = ypot_o_npot - ivpot_o_npot - g_o_y; % market clearing +% % The labor level, closed-form solution for labor +% npot = (cpot_o_npot^(-1)*wpot)^(1/(CHI+1)) ; +% % Value of remaining variables +% cpot = cpot_o_npot*npot; +% ivpot = ivpot_o_npot *npot; +% kpot = kpot_o_npot*npot; +% ypot = ypot_o_npot*npot; +% +% end; + +initval; +c = 4.86752; +lam = 0.205443; +n = 0.878852; +w = 3.5245; +r = 1.01005; +pie = 1.005; +y = 4.86752; +pstar = 1; +vartheta = 1; +mc = 0.909091; +s = 2.67853; +f = 2.9703; +a = 0.291768; +ptilde = 1; +delta1 = 1; +delta2 = 1; +delta3 = 1; +b = 0; +tau = 0; +g = 0; +nu = 0; +cpot = 4.86752; +npot = 0.878852; +wpot = 3.5245; +rrpot = 1.00503; +ypot = 4.86752; +bpot = 0; +taupot = 0; +k = 264.174; +rk = 0.00502513; +iv = 0; +q = 1; +kpot = 264.174; +rkpot = 0.00502513; +ivpot = 0; +end; + +% ========================================================================= +% Declare settings for shocks +% ========================================================================= +shocks; +var epsg = 1; +var epsnu = 1; +end; + +estimated_params; +ALPHA, 0.3, normal_pdf, 0.3 , 0.1; +BETA, 0.995, normal_pdf, 0.995, 0.1; +PIEBAR, 1.005, normal_pdf, 1.005, 0.1; +IOTA, 0.5, normal_pdf, 0.5, 0.1; +CHI, 1/0.4, normal_pdf, 1/0.4, 0.1; +THETAP, 0.1, normal_pdf, 0.1, 0.1; +XIP, 2/3, normal_pdf, 2/3, 0.1; +PSI, -12.2, normal_pdf, -12.2, 0.1; +GAMMAPIE, 1.5, normal_pdf, 1.5, 0.1; +GAMMAX, 0.125, normal_pdf, 0.125, 0.1; +%DELTA, 0, normal_pdf, 0, 0.1; +%QBAR, 1, normal_pdf, 1, 0.1; +%NUBAR, 0, normal_pdf, 0, 0.1; +%BBAR, 0, normal_pdf, 0, 0.1; +%GBAR_o_YBAR, 0, normal_pdf, 0, 0.1; %commenting this solves the analytic_derivation_mode=-2|-1 problem +%TAUBAR, 0, normal_pdf, 0, 0.1; +%TAUNBAR, 0, normal_pdf, 0, 0.1; +PHI, 0.0101, normal_pdf, 0.0101, 0.1; +RHONU, 0.95, normal_pdf, 0.95, 0.1; +RHOG, 0.95, normal_pdf, 0.95, 0.1; +SIGNU, 0.6/100, normal_pdf, 0.6/100, 0.1; +SIGG, 0.6/100, normal_pdf, 0.6/100, 0.1; +end; + +% ========================================================================= +% Computations +% ========================================================================= +model_diagnostics; +steady(maxit=5000,tolf=1e-8); +resid; +check; + +stoch_simul(order=3,irf=0,pruning,periods=0); +identification(order=3,no_identification_strength,ar=5); + +indpmodel = estim_params_.param_vals(:,1); +indpstderr = estim_params_.var_exo(:,1); +indpcorr = estim_params_.corrx(:,1:2); + +xparam_prior = set_prior(estim_params_,M_,options_); +M_ = set_all_parameters(xparam_prior,estim_params_,M_); +[~,info,M_,options_,oo_] = resol(0,M_, options_, oo_); + +d2flag=1; +options_.analytic_derivation_mode = 0; +DERIVSa0 = get_perturbation_params_derivs(M_, options_, estim_params_, oo_, indpmodel, indpstderr, indpcorr, d2flag); +options_.analytic_derivation_mode = -1; +DERIVSn1 = get_perturbation_params_derivs(M_, options_, estim_params_, oo_, indpmodel, indpstderr, indpcorr, d2flag); + +norm( vec(DERIVSn1.dYss) - vec(DERIVSa0.dYss), Inf) + +norm( vec(DERIVSn1.dg1) - vec(DERIVSa0.dg1), Inf) +norm( vec(DERIVSn1.dghx) - vec(DERIVSa0.dghx), Inf) +norm( vec(DERIVSn1.dghu) - vec(DERIVSa0.dghu), Inf) + +norm( vec(DERIVSn1.dg2) - vec(DERIVSa0.dg2), Inf) +norm( vec(DERIVSn1.dghxx) - vec(DERIVSa0.dghxx), Inf) +norm( vec(DERIVSn1.dghxu) - vec(DERIVSa0.dghxu), Inf) +norm( vec(DERIVSn1.dghuu) - vec(DERIVSa0.dghuu), Inf) +norm( vec(DERIVSn1.dghs2) - vec(DERIVSa0.dghs2), Inf) + +norm( vec(DERIVSn1.dg3) - vec(DERIVSa0.dg3), Inf) +norm( vec(DERIVSn1.dghxxx) - vec(DERIVSa0.dghxxx), Inf) +norm( vec(DERIVSn1.dghxxu) - vec(DERIVSa0.dghxxu), Inf) +norm( vec(DERIVSn1.dghxuu) - vec(DERIVSa0.dghxuu), Inf) +norm( vec(DERIVSn1.dghuuu) - vec(DERIVSa0.dghuuu), Inf) +norm( vec(DERIVSn1.dghxss) - vec(DERIVSa0.dghxss), Inf) +norm( vec(DERIVSn1.dghuss) - vec(DERIVSa0.dghuss), Inf) + +norm( vec(DERIVSn1.d2KalmanA) - vec(DERIVSa0.d2KalmanA), Inf) +norm( vec(DERIVSn1.d2Om) - vec(DERIVSa0.d2Om), Inf) +norm( vec(DERIVSn1.d2Yss) - vec(DERIVSa0.d2Yss), Inf) \ No newline at end of file diff --git a/tests/analytic_derivatives/burnside_3_order_PertParamsDerivs.mod b/tests/analytic_derivatives/burnside_3_order_PertParamsDerivs.mod new file mode 100644 index 0000000000000000000000000000000000000000..84b6ec7e0df33c902291f2afc92487957dc21f95 --- /dev/null +++ b/tests/analytic_derivatives/burnside_3_order_PertParamsDerivs.mod @@ -0,0 +1,230 @@ +% ========================================================================= +% Copyright (C) 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/>. +% ========================================================================= + + +/* + Check the policy functions obtained by perturbation at a high approximation + order, using the Burnside (1998, JEDC) model (for which the analytical form of + the policy function is known). + + As shown by Burnside, the policy function for yₜ is: + + yₜ = βⱠexp[aáµ¢+báµ¢(xₜ−xₛₛ)] + + + where: + θ² ⎛ 2Ï 1−ϲâ±âŽž + — aáµ¢ = iθxₛₛ + σ² ─────── ⎢i − ────(1−Ïâ±) + ϲ ─────⎥ + 2(1−Ï)² ⎠1âˆ’Ï 1−ϲ ⎠+ + Î¸Ï + — báµ¢ = ───(1−Ïâ±) + 1âˆ’Ï + + — xₛₛ is the steady state of x + — σ is the standard deviation of e. + + With some algebra, it can be shown that the derivative of yₜ at the deterministic + steady state is equal to: + + ∂áµâºâ¿âºÂ²áµ– yₜ ∞ (2p)! + ──────────────── = ∑ βⱠbáµ¢áµâºâ¿ Ïᵠ───── cᵢᵖ exp(iθxₛₛ) + ∂áµxₜ₋₠∂â¿eₜ ∂²ᵖs â±â¼Â¹ p! + + where: + — s is the stochastic scale factor + + θ² ⎛ 2Ï 1−ϲâ±âŽž + — cáµ¢ = ─────── ⎢i − ────(1−Ïâ±) + ϲ ─────⎥ + 2(1−Ï)² ⎠1âˆ’Ï 1−ϲ ⎠+ + Note that derivatives with respect to an odd order for s (i.e. ∂²ᵖâºÂ¹s) are always + equal to zero. + + The policy function as returned in the oo_.dr.g_* matrices has the following properties: + — its elements are pre-multiplied by the Taylor coefficients; + — derivatives w.r.t. the stochastic scale factor have already been summed up; + — symmetric elements are folded (and they are not pre-multiplied by the number of repetitions). + + As a consequence, the element gₘₙ corresponding to the m-th derivative w.r.t. + to xₜ₋₠and the n-th derivative w.r.t. to eₜ is given by: + + 1 ∞ cᵢᵖ + gₘₙ = ────── ∑ ∑ βⱠbáµ¢áµâºâ¿ Ïᵠ──── exp(iθxₛₛ) + (m+n)! 0≤2p≤k-m-n â±â¼Â¹ p! + + where k is the order of approximation. + + */ + +@#define ORDER = 3 + +var y x; +varobs y; +varexo e; + +parameters beta theta rho xbar; +xbar = 0.0179; +rho = -0.139; +theta = -1.5; +theta = -10; +beta = 0.95; + +model; +y = beta*exp(theta*x(+1))*(1+y(+1)); +x = (1-rho)*xbar + rho*x(-1)+e; +end; + +shocks; +var e; stderr 0.0348; +end; + +steady_state_model; +x = xbar; +y = beta*exp(theta*xbar)/(1-beta*exp(theta*xbar)); +end; + +estimated_params; +stderr e, normal_pdf, 0.0348,0.01; +beta, normal_pdf, 0.95, 0.01; +theta, normal_pdf, -10, 0.01; +rho, normal_pdf, -0.139, 0.01; +xbar, normal_pdf, 0.0179, 0.01; +end; + +steady;check;model_diagnostics; +stoch_simul(order=@{ORDER},k_order_solver,irf=0,drop=0,periods=0,nograph); +identification(order=@{ORDER},nograph,no_identification_strength); + +%make sure everything is computed at prior mean +xparam_prior = set_prior(estim_params_,M_,options_); +M_ = set_all_parameters(xparam_prior,estim_params_,M_); +[~,info,M_,options_,oo_] = resol(0,M_, options_, oo_); + +indpmodel = estim_params_.param_vals(:,1); +indpstderr = estim_params_.var_exo(:,1); +indpcorr = estim_params_.corrx(:,1:2); +totparam_nbr = length(indpmodel) + length(indpstderr) + size(indpcorr,1); + +%% Verify that the policy function coefficients are correct +i = 1:800; +SE_e=sqrt(M_.Sigma_e); +aux1 = rho*(1-rho.^i)/(1-rho); +aux2 = (1-rho.^(2*i))/(1-rho^2); +aux3 = 1/((1-rho)^2); +aux4 = (i-2*aux1+rho^2*aux2); +aux5=aux3*aux4; +b = theta*aux1; +c = 1/2*theta^2*SE_e^2*aux5; + +%derivatives wrt to rho only +daux1_drho = zeros(1,length(i)); +daux2_drho = zeros(1,length(i)); +daux3_drho = 2/((1-rho)^3); +daux4_drho = zeros(1,length(i)); +daux5_drho = zeros(1,length(i)); +for ii = 1:length(i) + if ii == 1 + daux1_drho(ii) = 1; + daux2_drho(ii) = 0; + else + daux1_drho(ii) = rho/(rho^2 - 2*rho + 1) - 1/(rho - 1) + ((ii+1)*rho^ii)/(rho - 1) - rho^(ii+1)/(rho^2 - 2*rho + 1); + daux2_drho(ii) = (2*rho)/(rho^4 - 2*rho^2 + 1) + (2*ii*rho^(2*ii-1))/(rho^2 - 1) - (2*rho^(2*ii+1))/(rho^4 - 2*rho^2 + 1); + end + daux4_drho(ii) = -2*daux1_drho(ii) + 2*rho*aux2(ii) + rho^2*daux2_drho(ii); + daux5_drho(ii) = daux3_drho*aux4(ii) + aux3*daux4_drho(ii); +end +%derivatives of b and c wrt to all parameters +db = zeros(size(b,1),size(b,2),M_.exo_nbr+M_.param_nbr); +db(:,:,3) = aux1;%wrt theta +db(:,:,4) = theta*daux1_drho;%wrt rho +dc = zeros(size(c,1),size(c,2),M_.exo_nbr+M_.param_nbr); +dc(:,:,1) = theta^2*SE_e*aux3*aux4;%wrt SE_e +dc(:,:,3) = theta*SE_e^2*aux3*aux4;%wrt theta +dc(:,:,4) = 1/2*theta^2*SE_e^2*daux5_drho; %wrt rho + +d2flag=0; +g_0 = 1/2*oo_.dr.ghs2; if ~isequal(g_0,oo_.dr.g_0); error('something wrong'); end +g_1 = [oo_.dr.ghx oo_.dr.ghu] +3/6*[oo_.dr.ghxss oo_.dr.ghuss]; if ~isequal(g_1,oo_.dr.g_1); error('something wrong'); end +g_2 = 1/2*[oo_.dr.ghxx oo_.dr.ghxu oo_.dr.ghuu]; if ~isequal(g_2,oo_.dr.g_2); error('something wrong'); end +g_3 = 1/6*[oo_.dr.ghxxx oo_.dr.ghxxu oo_.dr.ghxuu oo_.dr.ghuuu]; if ~isequal(g_3,oo_.dr.g_3); error('something wrong'); end + +tols = [1e-4 1e-4 1e-12 1e-12]; +KRONFLAGS = [-1 -2 0 1]; +for k = 1:length(KRONFLAGS) + fprintf('KRONFLAG=%d\n',KRONFLAGS(k)); + options_.analytic_derivation_mode = KRONFLAGS(k); + DERIVS = get_perturbation_params_derivs(M_, options_, estim_params_, oo_, indpmodel, indpstderr, indpcorr, d2flag); + oo_.dr.dg_0 = permute(1/2*DERIVS.dghs2,[1 3 2]); + oo_.dr.dg_1 = cat(2,DERIVS.dghx,DERIVS.dghu) + 3/6*cat(2,DERIVS.dghxss,DERIVS.dghuss); + oo_.dr.dg_2 = 1/2*cat(2,DERIVS.dghxx,DERIVS.dghxu,DERIVS.dghuu); + oo_.dr.dg_3 = 1/6*[DERIVS.dghxxx DERIVS.dghxxu DERIVS.dghxuu DERIVS.dghuuu]; + + for ord = 0:@{ORDER} + g = oo_.dr.(['g_' num2str(ord)])(2,:); % Retrieve computed policy function for variable y + dg = oo_.dr.(['dg_' num2str(ord)])(2,:,:); + for m = 0:ord % m is the derivation order with respect to x(-1) + v = 0; + dv = zeros(1,M_.exo_nbr + M_.param_nbr); + for p = 0:floor((@{ORDER}-ord)/2) % 2p is the derivation order with respect to s + if ord+2*p > 0 % Skip the deterministic steady state constant + v = v + sum(beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*c.^p)/factorial(ord)/factorial(p); + %derivatives + dv(:,1) = dv(:,1) + sum( beta.^i.*exp(theta*xbar*i).*ord.*b.^(ord-1).*db(:,:,1).*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*p.*c.^(p-1).*dc(:,:,1)... + )/factorial(ord)/factorial(p);%wrt SE_E + dv(:,2) = dv(:,2) + sum( i.*beta.^(i-1).*exp(theta*xbar*i).*b.^ord.*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*ord.*b.^(ord-1).*db(:,:,2).*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*p.*c.^(p-1).*dc(:,:,2)... + )/factorial(ord)/factorial(p);%wrt beta + dv(:,3) = dv(:,3) + sum( beta.^i.*exp(theta*xbar*i).*xbar.*i.*b.^ord.*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*ord.*b.^(ord-1).*db(:,:,3).*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*p.*c.^(p-1).*dc(:,:,3)... + )/factorial(ord)/factorial(p);%wrt theta + dv(:,4) = dv(:,4) + sum( beta.^i.*exp(theta*xbar*i).*b.^ord.*m.*rho^(m-1).*c.^p... + +beta.^i.*exp(theta*xbar*i).*ord.*b.^(ord-1).*db(:,:,4).*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*p.*c.^(p-1).*dc(:,:,4)... + )/factorial(ord)/factorial(p);%wrt rho + dv(:,5) = dv(:,5) + sum( beta.^i.*exp(theta*xbar*i).*theta.*i.*b.^ord.*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*ord.*b.^(ord-1).*db(:,:,5).*rho^m.*c.^p... + +beta.^i.*exp(theta*xbar*i).*b.^ord.*rho^m.*p.*c.^(p-1).*dc(:,:,5)... + )/factorial(ord)/factorial(p);%wrt xbar + end + end + if abs(v-g(ord+1-m)) > 1e-14 + error(['Error in matrix oo_.dr.g_' num2str(ord)]) + end + chk_dg = squeeze(dg(:,ord+1-m,:))'; + if isempty(indpstderr) + chk_dv = dv(:,M_.exo_nbr+indpmodel); + elseif isempty(indpmodel) + chk_dv = dv(:,1:M_.exo_nbr); + else + chk_dv = dv; + end + fprintf('Max absolute deviation for dg_%d(2,%d,:): %e\n',ord,ord+1-m,norm( chk_dv - chk_dg, Inf)); + if norm( chk_dv - chk_dg, Inf) > tols(k) + error(['Error in matrix dg_' num2str(ord)]) + chk_dv + chk_dg + end + end + end + fprintf('\n'); +end \ No newline at end of file diff --git a/tests/analytic_derivatives/ls2003.mod b/tests/analytic_derivatives/ls2003.mod deleted file mode 100644 index a6cb0e6845bdc39100e19183fd84a86823c2c92c..0000000000000000000000000000000000000000 --- a/tests/analytic_derivatives/ls2003.mod +++ /dev/null @@ -1,66 +0,0 @@ -var y y_s R pie dq pie_s de A y_obs pie_obs R_obs; -varexo e_R e_q e_ys e_pies e_A; - -parameters psi1 psi2 psi3 rho_R tau alpha rr k rho_q rho_A rho_ys rho_pies; - -psi1 = 1.54; -psi2 = 0.25; -psi3 = 0.25; -rho_R = 0.5; -alpha = 0.3; -rr = 2.51; -k = 0.5; -tau = 0.5; -rho_q = 0.4; -rho_A = 0.2; -rho_ys = 0.9; -rho_pies = 0.7; - - -model(linear); -y = y(+1) - (tau +alpha*(2-alpha)*(1-tau))*(R-pie(+1))-alpha*(tau +alpha*(2-alpha)*(1-tau))*dq(+1) + alpha*(2-alpha)*((1-tau)/tau)*(y_s-y_s(+1))-A(+1); -pie = exp(-rr/400)*pie(+1)+alpha*exp(-rr/400)*dq(+1)-alpha*dq+(k/(tau+alpha*(2-alpha)*(1-tau)))*y+k*alpha*(2-alpha)*(1-tau)/(tau*(tau+alpha*(2-alpha)*(1-tau)))*y_s; -pie = de+(1-alpha)*dq+pie_s; -R = rho_R*R(-1)+(1-rho_R)*(psi1*pie+psi2*(y+alpha*(2-alpha)*((1-tau)/tau)*y_s)+psi3*de)+e_R; -dq = rho_q*dq(-1)+e_q; -y_s = rho_ys*y_s(-1)+e_ys; -pie_s = rho_pies*pie_s(-1)+e_pies; -A = rho_A*A(-1)+e_A; -y_obs = y-y(-1)+A; -pie_obs = 4*pie; -R_obs = 4*R; -end; - -shocks; - var e_R = 1.25^2; - var e_q = 2.5^2; - var e_A = 1.89; - var e_ys = 1.89; - var e_pies = 1.89; -end; - -varobs y_obs R_obs pie_obs dq de; - -estimated_params; -psi1 , gamma_pdf,1.5,0.5; -psi2 , gamma_pdf,0.25,0.125; -psi3 , gamma_pdf,0.25,0.125; -rho_R ,beta_pdf,0.5,0.2; -alpha ,beta_pdf,0.3,0.1; -rr ,gamma_pdf,2.5,1; -k , gamma_pdf,0.5,0.25; -tau ,gamma_pdf,0.5,0.2; -rho_q ,beta_pdf,0.4,0.2; -rho_A ,beta_pdf,0.5,0.2; -rho_ys ,beta_pdf,0.8,0.1; -rho_pies,beta_pdf,0.7,0.15; -stderr e_R,inv_gamma_pdf,1.2533,0.6551; -stderr e_q,inv_gamma_pdf,2.5066,1.3103; -stderr e_A,inv_gamma_pdf,1.2533,0.6551; -stderr e_ys,inv_gamma_pdf,1.2533,0.6551; -stderr e_pies,inv_gamma_pdf,1.88,0.9827; -end; - -estimation(datafile='../ls2003/data_ca1.m',first_obs=8,nobs=79,mh_nblocks=2, - prefilter=1,mh_jscale=0.5,mh_replic=0, mode_compute=1, analytic_derivation); - diff --git a/tests/analytic_derivatives/nBrockMirmanSYM.mat b/tests/analytic_derivatives/nBrockMirmanSYM.mat new file mode 100644 index 0000000000000000000000000000000000000000..7bdc38ac0d54728900867927b11d59e5c88a32dc Binary files /dev/null and b/tests/analytic_derivatives/nBrockMirmanSYM.mat differ diff --git a/tests/identification/LindeTrabandt/LindeTrabandt2019_xfail.mod b/tests/identification/LindeTrabandt/LindeTrabandt2019_xfail.mod new file mode 100644 index 0000000000000000000000000000000000000000..01684d4ba02463b67203e5686eef8963b2ef12c4 --- /dev/null +++ b/tests/identification/LindeTrabandt/LindeTrabandt2019_xfail.mod @@ -0,0 +1,363 @@ +% Original model by: J. Linde, M. Trabandt (2019: Should We Use Linearized Models to Calculate Fiscal Multipliers? +% Journal of Applied Econometrics, 2018, 33: 937-965. http://dx.doi.org/10.1002/jae.2641 +% This version has some additional dynamics for capital and investment +% Created by @wmutschl (Willi Mutschler, willi@mutschler.eu) + +% ========================================================================= +% Declare endogenous variables +% ========================================================================= + +var + % Staggered-price economy + c ${c}$ (long_name='consumption') + lam ${\lambda}$ (long_name='lagrange multiplier budget') + n ${n}$ (long_name='labor') + w ${w}$ (long_name='real wage') + r ${r}$ (long_name='interest rate') + pie ${\pi}$ (long_name='inflation') + y ${y}$ (long_name='output') + pstar ${p^\ast}$ (long_name='price dispersion') + vartheta ${\vartheta}$ (long_name='aggregate price index') + mc ${mc}$ (long_name='marginal costs') + s ${s}$ (long_name='auxiliary variable for nonlinear pricing 1') + f ${f}$ (long_name='auxiliary variable for nonlinear pricing 2') + a ${a}$ (long_name='auxiliary variable for nonlinear pricing 3') + ptilde ${\tilde{p}}$ (long_name='reoptimized price') + delta1 ${\Delta_1}$ (long_name='price dispersion 1') + delta2 ${\Delta_2}$ (long_name='price dispersion 2') + delta3 ${\Delta_3}$ (long_name='price dispersion 3') + b ${b}$ (long_name='bonds') + tau ${\tau}$ (long_name='lump-sum tax') + g + nu %consumption preference shock + + % Flex-price economy + cpot ${c^{pot}}$ (long_name='flex-price consumption') + npot ${n^{pot}}$ (long_name='flex-price labor') + wpot ${w^{pot}}$ (long_name='flex-price real wage') + rrpot ${r^{pot}}$ (long_name='flex-price interest rate') + ypot ${y^{pot}}$ (long_name='flex-price output') + bpot ${b^{pot}}$ (long_name='flex-price bonds') + taupot ${\tau^{pot}}$ (long_name='flex-price lump-sum tax') + + % Added variables for capital and investment + k ${k}$ (long_name='capital') + rk ${r^{K}}$ (long_name='rental rate on capital') + iv ${i}$ (long_name='investment') + q ${q}$ (long_name='Tobins Q') + kpot ${k^{pot}}$ (long_name='flex-price capital') + rkpot ${r^{K,pot}}$ (long_name='flex-price rental rate on capital') + ivpot ${i^{pot}}$ (long_name='flex-price investment') +; + +% ========================================================================= +% Declare observable variables +% ========================================================================= +varobs c y; + +% ========================================================================= +% Declare exogenous variables +% ========================================================================= +varexo +epsg +epsnu + ; + +% ========================================================================= +% Declare parameters +% ========================================================================= +parameters + ALPHA ${\alpha}$ (long_name='capital share') + BETA ${\beta}$ (long_name='discount rate') + PIEBAR ${\bar{\pi}}$ (long_name='target inflation rate') + IOTA ${\iota}$ (long_name='indexation') + CHI ${\chi}$ (long_name='inverse frisch elasticity') + THETAP ${\theta_p}$ (long_name='net markup') + XIP ${\xi_p}$ (long_name='Calvo probability') + PSI ${\psi}$ (long_name='Kimbal curvature') + GAMMAPIE ${\gamma_\pi}$ (long_name='Taylor rule parameter inflation') + GAMMAX ${\gamma_x}$ (long_name='Taylor rule parameter output') + DELTA ${\delta}$ (long_name='depreciation rate') + QBAR ${\bar{Q}}$ (long_name='steady state Q') + NUBAR ${\bar{\nu}}$ (long_name='steady state consumption preference shock') + BBAR %government debt to annualized output ratio + GBAR_o_YBAR % government consumption ratio + TAUBAR + TAUNBAR + PHI + RHONU + RHOG + SIGNU + SIGG +; + + +% ========================================================================= +% Calibration +% ========================================================================= +BETA = 0.995; +PIEBAR = 1 + 0.005; +ALPHA = 0.3; +NUBAR = 0;%0.01; +BBAR = 0;%0.6; +GBAR_o_YBAR = 0;%0.2; +TAUBAR = 0; +PHI = 0.0101; +IOTA = 0.5; +CHI = 1/0.4; +XIP = 2/3; +PSI = -12.2; +THETAP = 0.1; +GAMMAPIE = 1.5; +GAMMAX = 0.125; +QBAR=1; +DELTA = 0;%0.025; +RHONU = 0.95; +RHOG = 0.95; +SIGG = 0.6/100; +SIGNU = 0.6/100; +TAUNBAR = 0; + +% ======================================================================== +% Model equations +% ========================================================================= +model; +% ------------------------------------------------------------------------- +% Auxiliary expressions +% ------------------------------------------------------------------------- +#OMEGAP = (1+THETAP)*(1+PSI)/(1+PSI+THETAP*PSI); %gross markup +#gammap = pie^IOTA*PIEBAR^(1-IOTA); %indexation rule +%#gammap = PIEBAR; +% ------------------------------------------------------------------------- +% Added equations for capital and investment +% ------------------------------------------------------------------------- +[name='foc household wrt i'] +lam = lam*q; +[name='foc household wrt k'] +lam*q = BETA*lam(+1)*(rk(+1)+ (1-DELTA)*q(+1) ); +[name='capital accumulation'] +k = (1-DELTA)*k(-1) + iv; +[name='capital demand'] +rk=ALPHA*mc*y/k(-1); + +[name='flex price foc household wrt k'] +(cpot-steady_state(cpot)*nu)^(-1) = BETA*(cpot(+1)-steady_state(cpot)*nu(+1))^(-1)*(rkpot(+1) + (1-DELTA) ); +[name='flex price capital accumulation'] +kpot = (1-DELTA)*kpot(-1) + ivpot; +[name='flex price capital demand'] +rkpot=ALPHA/(1+THETAP)*(npot/kpot(-1))^(1-ALPHA); + +% ------------------------------------------------------------------------- +% Actual model equations +% ------------------------------------------------------------------------- +[name='foc household wrt c (marginal utility)'] +(c-steady_state(c)*nu)^(-1) = lam; + +[name='foc household wrt l (leisure vs. labor)'] +n^CHI = (1-TAUNBAR)*lam*w; + +[name='foc household wrt b (Euler equation)'] +lam = BETA*r/pie(+1)*lam(+1); + +[name='aggregate resource constraint'] +y = c + g + iv; + +[name='production function'] +y=pstar^(-1)*k(-1)^ALPHA*n^(1-ALPHA); + +[name='Nonlinear pricing 1'] +s = OMEGAP*lam*y*vartheta^(OMEGAP/(OMEGAP-1))*mc + BETA*XIP*(gammap/pie(+1))^(OMEGAP/(1-OMEGAP))*s(+1); + +[name='Nonlinear pricing 2'] +f = lam*y*vartheta^(OMEGAP/(OMEGAP-1)) + BETA*XIP*(gammap/pie(+1))^(1/(1-OMEGAP))*f(+1); + +[name='Nonlinear pricing 3'] +a = PSI*(OMEGAP-1)*lam*y + BETA*XIP*(gammap/pie(+1))*a(+1); + +[name='Nonlinear pricing 4'] +s = f*ptilde -a*ptilde^(1+OMEGAP/(OMEGAP-1)); + +[name='zero profit condition'] +vartheta = 1 + PSI - PSI*delta2; + +[name='aggregate price index'] +vartheta = delta3; + +[name='overall price dispersion'] +pstar = 1/(1+PSI)*vartheta^(OMEGAP/(OMEGAP-1))*delta1^(OMEGAP/(1-OMEGAP)) + PSI/(1+PSI); + +[name='price dispersion 1'] +delta1^(OMEGAP/(1-OMEGAP)) = (1-XIP)*ptilde^(OMEGAP/(1-OMEGAP)) + XIP*(gammap/pie*delta1(-1))^(OMEGAP/(1-OMEGAP)); + +[name='price dispersion 2'] +delta2 = (1-XIP)*ptilde+XIP*gammap/pie*delta2(-1); + +[name='price dispersion 3'] +delta3^(1/(1-OMEGAP)) = (1-XIP)*ptilde^(1/(1-OMEGAP)) + XIP*(gammap/pie*delta3(-1))^(1/(1-OMEGAP)); + +[name='marginal costs'] +(1-ALPHA)*mc = w*k(-1)^(-ALPHA)*n^ALPHA; + +[name='Taylor Rule'] +r = steady_state(r)*(pie/PIEBAR)^GAMMAPIE*( (y/steady_state(y))/(ypot/steady_state(ypot)) )^GAMMAX; + +[name='government budget'] +b = r(-1)/pie*b(-1) + g/steady_state(y) -TAUNBAR*w*n/steady_state(y) - tau; + +[name='fiscal rule'] +tau = TAUBAR + PHI*(b(-1)-BBAR); + +[name='flex price Euler equation'] +(cpot-steady_state(cpot)*nu)^(-1) = BETA*rrpot*(cpot(+1)-steady_state(cpot)*nu(+1))^(-1); + +[name='flex price foc household wrt l (leisure vs. labor)'] +npot^CHI = (1-TAUNBAR)*(cpot-steady_state(cpot)*nu)^(-1)*wpot; + +[name='flex price wage'] +(1-ALPHA)/(1+THETAP)*kpot(-1)^ALPHA = wpot*npot^ALPHA; + +[name='flex price aggregate resource constraint'] +ypot = cpot + g + ivpot; + +[name='flex price production function'] +ypot=kpot(-1)^ALPHA*npot^(1-ALPHA); + +[name='flex price government budget'] +bpot = rrpot(-1)*bpot(-1) + g/steady_state(y) -TAUNBAR*wpot*npot/steady_state(y) - taupot; + +[name='fiscal rule '] +taupot = TAUBAR + PHI*(bpot(-1)-BBAR); + +g/steady_state(y) - GBAR_o_YBAR = RHOG*(g(-1)/steady_state(y) - GBAR_o_YBAR) + epsg; +nu - NUBAR = RHONU*(nu(-1) - NUBAR) + epsnu; +end; + + +% ========================================================================= +% Steady state using a steady_state_model block +% ========================================================================= + +steady_state_model; +OMEGP = (1+THETAP)*(1+PSI)/(1+PSI+THETAP*PSI); +q = QBAR; +pie = PIEBAR; +GAMMAP = PIEBAR^IOTA*PIEBAR^(1-IOTA); +b = BBAR; +tau = TAUBAR; +taun = TAUNBAR; +nu = NUBAR; +r = pie/BETA; +RK = (1/BETA+DELTA-1)*q; % foc k +aux1 = ( (1-XIP)/(1-XIP*(GAMMAP/pie)^(1/(1-OMEGP)) ) )^(1-OMEGP); +aux2 = (1-XIP)/(1-XIP*(GAMMAP/pie)); +ptilde = (1+PSI)/ ( aux1 + PSI*aux2 ); +delta2 = aux2*ptilde; +delta3 = aux1*ptilde; +vartheta = delta3; +delta1 = ( (1-XIP)/(1-XIP*(GAMMAP/pie)^(OMEGP/(1-OMEGP) )) )^((1-OMEGP)/OMEGP)*ptilde; +pstar = 1/(1+PSI)*vartheta^(OMEGP/(OMEGP-1))*delta1^(OMEGP/(1-OMEGP)) + PSI/(1+PSI); +f_o_a = ( vartheta^(OMEGP/(OMEGP-1)) / (1-BETA*XIP*(GAMMAP/pie)^(1/(1-OMEGP))) ) / ( PSI*(OMEGP-1) /(1-BETA*XIP*GAMMAP/pie) ); +s_o_a = ( OMEGP*vartheta^(OMEGP/(OMEGP-1)) / (1-BETA*XIP*(GAMMAP/pie)^(OMEGP/(1-OMEGP))) ) / ( PSI*(OMEGP-1) /(1-BETA*XIP*GAMMAP/pie) ); +mc = (f_o_a*ptilde-ptilde^(1+OMEGP/(OMEGP-1)))*s_o_a^(-1); + +k_o_n = (RK/(mc*ALPHA))^(1/(ALPHA-1)); +w = (1-ALPHA)*mc*k_o_n^ALPHA; % labor demand +y_o_n = pstar^(-1)*k_o_n^ALPHA; % production function +iv_o_n = DELTA*k_o_n; +iv_o_y = iv_o_n / y_o_n; +g_o_y = GBAR_o_YBAR; +c_o_n = y_o_n - iv_o_n - g_o_y; % market clearing + +% The labor level, closed-form solution for labor +n = (c_o_n^(-1)*w)^(1/(CHI+1)) ; +% Value of remaining variables +c = c_o_n*n; +rk = RK; + + +iv = iv_o_n *n; +k = k_o_n*n; +y = y_o_n*n; +lam = n^CHI/w; +g = g_o_y*y; +a = PSI*(OMEGP-1)*y*lam/(1-BETA*XIP*GAMMAP/pie); +f = f_o_a*a; +s = f*ptilde - a*ptilde^(1+OMEGP/(OMEGP-1)); + +%flex price economy +bpot = BBAR; +taupot = TAUBAR; +taun = TAUNBAR; + +rrpot = 1/BETA; +RKpot = (1/BETA+DELTA-1)*QBAR; % foc k +rkpot = RKpot; + +kpot_o_npot = (RKpot/(ALPHA/(1+THETAP)))^(1/(ALPHA-1)); +wpot = (1-ALPHA)/(1+THETAP)*kpot_o_npot^ALPHA; % labor demand +ypot_o_npot = kpot_o_npot^ALPHA; % production function +ivpot_o_npot = DELTA*kpot_o_npot; +ivpot_o_ypot = ivpot_o_npot / ypot_o_npot; +cpot_o_npot = ypot_o_npot - ivpot_o_npot - g_o_y; % market clearing +% The labor level, closed-form solution for labor +npot = (cpot_o_npot^(-1)*wpot)^(1/(CHI+1)) ; +% Value of remaining variables +cpot = cpot_o_npot*npot; +ivpot = ivpot_o_npot *npot; +kpot = kpot_o_npot*npot; +ypot = ypot_o_npot*npot; + +end; + + + +% ========================================================================= +% Declare settings for shocks +% ========================================================================= +shocks; +var epsg = 1; +var epsnu = 1; +end; + +estimated_params; +ALPHA, 0.3, normal_pdf, 0.3 , 0.1; +BETA, 0.995, normal_pdf, 0.995, 0.1; +PIEBAR, 1.005, normal_pdf, 1.005, 0.1; +IOTA, 0.5, normal_pdf, 0.5, 0.1; +CHI, 1/0.4, normal_pdf, 1/0.4, 0.1; +THETAP, 0.1, normal_pdf, 0.1, 0.1; +XIP, 2/3, normal_pdf, 2/3, 0.1; +PSI, -12.2, normal_pdf, -12.2, 0.1; +GAMMAPIE, 1.5, normal_pdf, 1.5, 0.1; +GAMMAX, 0.125, normal_pdf, 0.125, 0.1; +DELTA, 0, normal_pdf, 0, 0.1; +QBAR, 1, normal_pdf, 1, 0.1; +NUBAR, 0, normal_pdf, 0, 0.1; +BBAR, 0, normal_pdf, 0, 0.1; +GBAR_o_YBAR, 0, normal_pdf, 0, 0.1; %commenting this solves the analytic_derivation_mode=-2|-1 problem +TAUBAR, 0, normal_pdf, 0, 0.1; +TAUNBAR, 0, normal_pdf, 0, 0.1; +PHI, 0.0101, normal_pdf, 0.0101, 0.1; +RHONU, 0.95, normal_pdf, 0.95, 0.1; +RHOG, 0.95, normal_pdf, 0.95, 0.1; +SIGNU, 0.6/100, normal_pdf, 0.6/100, 0.1; +SIGG, 0.6/100, normal_pdf, 0.6/100, 0.1; +end; + + +% ========================================================================= +% Computations +% ========================================================================= +model_diagnostics; +steady; +resid; +check; + +identification(no_identification_strength,analytic_derivation_mode= 0,ar=5); %works +%identification(no_identification_strength,analytic_derivation_mode= 1,ar=5); %works, this takes the longest due to Kronecker products +options_.dynatol.x = 1e-9; +identification(no_identification_strength,analytic_derivation_mode=-1,ar=5); %works, but tolerance is way too small +identification(no_identification_strength,analytic_derivation_mode=-2,ar=5); %works, but tolerance is way to small +options_.dynatol.x = 1e-5; %this is the default value +identification(no_identification_strength,analytic_derivation_mode=-1,ar=5); %works only if GBAR_o_YBAR is uncommented +identification(no_identification_strength,analytic_derivation_mode=-2,ar=5); %works only if GBAR_o_YBAR is uncommented diff --git a/tests/identification/as2007/G_QT.mat b/tests/identification/as2007/G_QT.mat new file mode 100644 index 0000000000000000000000000000000000000000..74b7e73992fe5b7efc757fc93bddce5bd2aa4ad0 Binary files /dev/null and b/tests/identification/as2007/G_QT.mat differ diff --git a/tests/identification/as2007/as2007_QT.mod b/tests/identification/as2007/as2007_QT.mod index 8b7cfa35e0c064a54fc90504a32c5f6e80f78c4f..51318e1ccf0a0cc815c21b9e603b36f7f1ee569d 100644 --- a/tests/identification/as2007/as2007_QT.mod +++ b/tests/identification/as2007/as2007_QT.mod @@ -74,24 +74,23 @@ identification(parameter_set=calibration, checks_via_subsets=1, max_dim_subsets_groups=4); -% load('G_QT'); %note that this is computed using replication files of Qu and Tkachenko (2012) -% temp = load([M_.dname filesep 'identification' filesep M_.fname '_identif']); -% G_dynare = temp.ide_spectrum_point.G; -% -% % Compare signs -% if ~isequal(sign(G_dynare),sign(G_QT)) -% error('signs of normalized G are note equal'); -% end -% -% % Compare normalized versions -% tilda_G_dynare = temp.ide_spectrum_point.tilda_G; -% ind_G_QT = (find(max(abs(G_QT'),[],1) > temp.store_options_ident.tol_deriv)); -% tilda_G_QT = zeros(size(G_QT)); -% delta_G_QT = sqrt(diag(G_QT(ind_G_QT,ind_G_QT))); -% tilda_G_QT(ind_G_QT,ind_G_QT) = G_QT(ind_G_QT,ind_G_QT)./((delta_G_QT)*(delta_G_QT')); -% if ~isequal(rank(tilda_G_QT,temp.store_options_ident.tol_rank),rank(tilda_G_dynare,temp.store_options_ident.tol_rank)) -% error('ranks are not the same for normalized version') -% end -% -% max(max(abs(abs(tilda_G_dynare)-abs(tilda_G_QT)))) -% norm(tilda_G_dynare - tilda_G_QT) +load('G_QT'); %note that this is computed using replication files of Qu and Tkachenko (2012) +temp = load([M_.dname filesep 'identification' filesep M_.fname '_identif']); +G_dynare = temp.ide_spectrum_point.G; +% Compare signs +if ~isequal(sign(G_dynare),sign(G_QT)) + error('signs of normalized G are note equal'); +end + +% Compare normalized versions +tilda_G_dynare = temp.ide_spectrum_point.tilda_G; +ind_G_QT = (find(max(abs(G_QT'),[],1) > temp.store_options_ident.tol_deriv)); +tilda_G_QT = zeros(size(G_QT)); +delta_G_QT = sqrt(diag(G_QT(ind_G_QT,ind_G_QT))); +tilda_G_QT(ind_G_QT,ind_G_QT) = G_QT(ind_G_QT,ind_G_QT)./((delta_G_QT)*(delta_G_QT')); +if ~isequal(rank(tilda_G_QT,temp.store_options_ident.tol_rank),rank(tilda_G_dynare,temp.store_options_ident.tol_rank)) + error('ranks are not the same for normalized version') +end + +max(max(abs(abs(tilda_G_dynare)-abs(tilda_G_QT)))) +norm(tilda_G_dynare - tilda_G_QT)