From 5a8c206760dd5244312dfab50f2665755264ad78 Mon Sep 17 00:00:00 2001 From: Willi Mutschler Date: Tue, 17 Dec 2019 18:17:09 +0000 Subject: [PATCH] Added parameter derivatives of perturbation solution up to 3 order MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # Preliminary comments I finished the identification toolbox at orders two and three using the pruned state space system, but before I merge request this, I decided to first merge the new functionality to compute parameter derivatives of perturbation solution matrices at higher orders. So after this is approved, I merge the identification toolbox. I guess @rattoma, @sebastien, and @michel are best choices to review this. I outline the main idea first and then provide some more detailed changes I made to the functions. *** # Main idea This merge request is concerned with the *analytical*computation of the parameter derivatives of first, second and third order perturbation solution matrices, i.e. using _closed-form_ expressions to efficiently compute the derivative of $g_x$ , $g_u$, $g_{xx}$, $g_{xu}$, $g_{uu}$, $g_{\sigma\sigma}$, $g_{xxx}$, $g_{xxu}$, $g_{xuu}$, $g_{uuu}$, $g_{x\sigma\sigma}$, $g_{u\sigma\sigma}$ *with respect to model parameters* $\theta$. Note that $\theta$ contains model parameters, stderr and corr parameters of shocks. stderr and corr parameters of measurement errors are not yet supported, (they can easily be included as exogenous shocks). The availability of such derivatives is beneficial in terms of more reliable analysis of model sensitivity and parameter identifiability as well as more efficient estimation methods, in particular for models solved up to third order, as it is well-known that numerical derivatives are a tricky business, especially for large models. References for my approach are: * Iskrev (2008, 2010) and Schmitt-Grohé and Uribe (2012, Appendix) who were the first to compute the parameter derivatives analytically at first order, however, using inefficient (sparse) Kronecker products. * Mutschler (2015) who provides the expressions for a second-order, but again using inefficient (sparse) Kronecker products. * Ratto and Iskrev (2012) who show how the first-order system can be solved accurately, fast and efficiently using existing numerical algorithms for generalized Sylvester equations by taking the parameter derivative with respect to each parameter separately. * Julliard and Kamenik (2004) who provide the perturbation solution equation system in tensor notation at any order k. * Levintal (2017) who introduces permutation matrices to express the perturbation solution equation system in matrix notation up to fifth order. Note that @rattoma already implemented the parameter derivatives of $g_x$ and $g_u$ analytically (and numerically), and I rely heavily on his work in `get_first_order_solution_params_derivs.m` (previously `getH.m`). My additions are mainly to this function and thus it is renamed to `get_perturbation_params_derivs.m`. The basic idea of this merge request is to take the second- and third-order perturbation solution systems in Julliard and Kamenik (2004), unfold these into an equivalent matrix representation using permutation matrices as in Levintal (2017). Then extending Ratto and Iskrev (2012) one takes the derivative with respect to each parameter separately and gets a computational problem that is linear, albeit large, as it involves either solving generalized Sylvester equations or taking inverses of highly sparse matrices. I will now briefly summarize the perturbation solution system at third order and the system that results when taking the derivative with respect to parameters. ## Perturbation Solution The following systems arise at first, second, and third order: $(ghx): f_{x} z_{x} = f_{y_{-}^*} + f_{y_0} g_{x} + f_{y_{+}^{**}} g^{**}_{x} g^{*}_{x}= A g_{x} + f_{y_{-}^*}=0$ $(ghu): f_{z} z_{u} = f_{y_0} g_{u} + f_{y_{+}^{**}} g^{**}_{x} g^{*}_{u} + f_{u}= A g_u + f_u = 0$ $(ghxx) : A g_{xx} + B g_{xx} \left(g^{*}_{x} \otimes g^{*}_{x}\right) + f_{zz} \left( z_{x} \otimes z_{x} \right) = 0$ $(ghxu) : A g_{xu} + B g_{xx} \left(g^{*}_{x} \otimes g^{*}_{u}\right) + f_{zz} \left( z_{x} \otimes z_{u} \right) = 0$ $(ghuu) : A g_{uu} + B g_{xx} \left(g^{*}_{u} \otimes g^{*}_{u}\right) + f_{zz} \left( z_{u} \otimes z_{u} \right) = 0$ $(ghs2) : (A+B) g_{\sigma\sigma} + \left( f_{y^{**}_{+}y^{**}_{+}} \left(g^{**}_{u} \otimes g^{**}_{u}\right) + f_{y^{**}_{+}} g^{**}_{uu}\right)vec(\Sigma) = 0$ $(ghxxx) : A g_{xxx} + B g_{xxx} \left(g^{*}_{x} \otimes g^{*}_{x} \otimes g^{*}_{x}\right) + f_{y_{+}}g^{**}_{xx} \left(g^{*}_x \otimes g^{*}_{xx}\right)P_{x\_xx} + f_{zz} \left( z_{x} \otimes z_{xx} \right)P_{x\_xx} + f_{zzz} \left( z_{x} \otimes z_{x} \otimes z_{x} \right) = 0$ $(ghxxu) : A g_{xxu} + B g_{xxx} \left(g^{*}_{x} \otimes g^{*}_{x} \otimes g^{*}_{u}\right) + f_{zzz} \left( z_{x} \otimes z_{x} \otimes z_{u} \right) + f_{zz} \left( \left( z_{x} \otimes z_{xu} \right)P_{x\_xu} + \left(z_{xx} \otimes z_{u}\right) \right) + f_{y_{+}}g^{**}_{xx} \left( \left(g^{*}_{x} \otimes g^{*}_{xu}\right)P_{x\_xu} + \left(g^{*}_{xx} \otimes g^{*}_{u}\right) \right) = 0$ $(ghxuu) : A g_{xuu} + B g_{xxx} \left(g^{*}_{x} \otimes g^{*}_{u} \otimes g^{*}_{u}\right) + f_{zzz} \left( z_{x} \otimes z_{u} \otimes z_{u} \right)+ f_{zz} \left( \left( z_{xu} \otimes z_{u} \right)P_{xu\_u} + \left(z_{x} \otimes z_{uu}\right) \right) + f_{y_{+}}g^{**}_{xx} \left( \left(g^{*}_{xu} \otimes g^{*}_{u}\right)P_{xu\_u} + \left(g^{*}_{x} \otimes g^{*}_{uu}\right) \right) = 0$ $(ghuuu) : A g_{uuu} + B g_{xxx} \left(g^{*}_{u} \otimes g^{*}_{u} \otimes g^{*}_{u}\right) + f_{zzz} \left( z_{u} \otimes z_{u} \otimes z_{u} \right)+ f_{zz} \left( z_{u} \otimes z_{uu} \right)P_{u\_uu} + f_{y_{+}}g^{**}_{xx} \left(g^{*}_{u} \otimes g^{*}_{uu}\right)P_{u\_uu} = 0$ $(ghx\sigma\sigma) : A g_{x\sigma\sigma} + B g_{x\sigma\sigma} g^{*}_x + f_{y_{+}} g^{**}_{xx}\left(g^{*}_{x} \otimes g^{*}_{\sigma\sigma}\right) + f_{zz} \left(z_{x} \otimes z_{\sigma\sigma}\right) + F_{xu_{+}u_{+}}\left(I_{n_x} \otimes vec(\Sigma)\right) = 0$ $F_{xu_{+}u_{+}} = f_{y_{+}^{\ast\ast}} g_{xuu}^{\ast\ast} (g_x^{\ast} \otimes I_{n_u^2}) + f_{zz} \left( \left( z_{xu_{+}} \otimes z_{u_{+}} \right)P_{xu\_u} + \left(z_{x} \otimes z_{u_{+}u_{+}}\right) \right) + f_{zzz}\left(z_{x} \otimes z_{u_{+}} \otimes z_{u_{+}}\right)$ $(ghu\sigma\sigma) : A g_{u\sigma\sigma} + B g_{x\sigma\sigma} g^{*}_{u} + f_{y_{+}} g^{**}_{xx}\left(g^{*}_{u} \otimes g^{*}_{\sigma\sigma}\right) + f_{zz} \left(z_{u} \otimes z_{\sigma\sigma}\right) + F_{uu_{+}u_{+}}\left(I_{n_u} \otimes vec(\Sigma_u)\right) = 0$ $F_{uu_{+}u_{+}} = f_{y_{+}^{\ast\ast}} g_{xuu}^{\ast\ast} (g_u^{\ast} \otimes I_{n_u^2}) + f_{zz} \left( \left( z_{uu_{+}} \otimes z_{u_{+}} \right)P_{uu\_u} + \left(z_{u} \otimes z_{u_{+}u_{+}}\right) \right) + f_{zzz}\left(z_{u} \otimes z_{u_{+}} \otimes z_{u_{+}}\right)$ A and B are the common perturbation matrices: $A = f_{y_0} + \begin{pmatrix} \underbrace{0}_{n\times n_{static}} &\vdots& \underbrace{f_{y^{**}_{+}} \cdot g^{**}_{x}}_{n \times n_{spred}} &\vdots& \underbrace{0}_{n\times n_{frwd}} \end{pmatrix}$and $B = \begin{pmatrix} \underbrace{0}_{n \times n_{static}}&\vdots & \underbrace{0}_{n \times n_{pred}} & \vdots & \underbrace{f_{y^{**}_{+}}}_{n \times n_{sfwrd}} \end{pmatrix}$ and $z=(y_{-}^{\ast}; y; y_{+}^{\ast\ast}; u)$ denotes the dynamic model variables as in `M_.lead_lag_incidence`, $y^\ast$ denote state variables, $y^{\ast\ast}$ denote forward looking variables, $y_+$ denote the variables with a lead, $y_{-}$ denote variables with a lag, $y_0$ denote variables at period t, $f$ the model equations, and $f_z$ the first-order dynamic model derivatives, $f_{zz}$ the second-order dynamic derivatives, and $f_{zzz}$ the third-order dynamic model derivatives. Then: $z_{x} = \begin{pmatrix}I\\g_{x}\\g^{**}_{x} g^{*}_{x}\\0\end{pmatrix}$, $z_{u} =\begin{pmatrix}0\\g_{u}\\g^{**}_{x} \cdot g^{*}_{u}\\I\end{pmatrix}$, $z_{u_{+}} =\begin{pmatrix}0\\0\\g^{**}_{u}\\0\end{pmatrix}$ $z_{xx} = \begin{pmatrix} 0\\g_{xx}\\g^{**}_{x} \left( g^{*}_x \otimes g^{*}_{x} \right) + g^{**}_{x} g^{*}_{x}\\0\end{pmatrix}$, $z_{xu} =\begin{pmatrix}0\\g_{xu}\\g^{**}_{xx} \left( g^{*}_x \otimes g^{*}_{u} \right) + g^{**}_{x} g^{*}_{xu}\\0\end{pmatrix}$, $z_{uu} =\begin{pmatrix}0\\g_{uu}\\g^{**}_{xx} \left( g^{*}_u \otimes g^{*}_{u} \right) + g^{**}_{x} g^{*}_{uu}\\0\end{pmatrix}$, $z_{xu_{+}} =\begin{pmatrix}0\\0\\g^{**}_{xu} \left( g^{*}_x \otimes I \right)\\0\end{pmatrix}$, $z_{uu_{+}} =\begin{pmatrix}0\\0\\g^{**}_{xu} \left( g^{*}_{u} \otimes I \right)\\0\end{pmatrix}$, $z_{u_{+}u_{+}} =\begin{pmatrix}0\\0\\g^{\ast\ast}_{uu}\\0\end{pmatrix}$, $z_{\sigma\sigma} = \begin{pmatrix}0\\ g_{\sigma\sigma}\\ g^{\ast\ast}_{x}g^{\ast}_{\sigma\sigma} + g^{\ast\ast}_{\sigma\sigma}\\0 \end{pmatrix}$ $P$ are permutation matrices that can be computed using Matlab's `ipermute` function. ## Parameter derivatives of perturbation solutions First, we need the parameter derivatives of first, second, third, and fourth derivatives of the dynamic model (i.e. g1,g2,g3,g4 in dynamic files), I make use of the implicit function theorem: Let $f_{z^k}$ denote the kth derivative (wrt all dynamic variables) of the dynamic model, then let $df_{z^k}$ denote the first-derivative (wrt all model parameters) of $f_{z^k}$ evaluated at the steady state. Note that $f_{z^k}$ is a function of both the model parameters $\theta$ and of the steady state of all dynamic variables $\bar{z}$, which also depend on the parameters. Hence, implicitly $f_{z^k}=f_{z^k}(\theta,\bar{z}(\theta))$ and $df_{z^k}$ consists of two parts: 1. direct derivative wrt to all model parameters given by the preprocessor in the `_params_derivs.m` files 2. contribution of derivative of steady state of dynamic variables (wrt all model parameters): $f_{z^{k+1}} \cdot d\bar{z}$ Note that we already have functionality to compute $d\bar{z}$ analytically. Having this, the above perturbation systems are basically equations of the following types $AX +BXC = RHS$ or $AX = RHS$ Now when taking the derivative (wrt to one single parameter $\theta_j$), we get $A\mathrm{d}\{X\} + B\mathrm{d}\{X\}C = \mathrm{d}\{RHS\} - \mathrm{d}\{A\}X - \mathrm{d}\{B\}XC - BX\mathrm{d}\{C\}$ or $A\mathrm{d}\{X\} = \mathrm{d}\{RHS\} - \mathrm{d}\{A\}X$ The first one is a Sylvester type equation, the second one can be solved by taking the inverse of $A$. The only diffculty and tedious work arrises in computing (the highly sparse) derivatives of $RHS$. *** # New functions: ` ## get_perturbation_params_derivs.m`and `get_perturbation_params_derivs_numerical_objective.m` * The parameter derivatives up to third order are computed in the new function`get_perturbation_params_derivs.m` both analytically and numerically. For numerical derivatives `get_perturbation_params_derivs_numerical_objective.m` is the objective for `fjaco.m` or `hessian_sparse.m` or `hessian.m`. * `get_perturbation_params_derivs.m` is basically an extended version of the previous `get_first_order_solution_params_derivs.m` function. * * `get_perturbation_params_derivs_numerical_objective.m`builds upon `identification_numerical_objective.m`. It is used for numerical derivatives, whenever `analytic_derivation_mode=-1|-2`. It takes from `identification_numerical_objective.m` the parts that compute numerical parameter Jacobians of steady state, dynamic model equations, and perturbation solution matrices. Hence, these parts are removed in `identification_numerical_objective.m` and it only computes numerical parameter Jacobian of moments and spectrum which are needed for identification analysis in `get_identification_jacobians.m`, when `analytic_derivation_mode=-1` only. * Detailed changes: * Most important: notation of this function is now in accordance to the k_order_solver, i.e. we do not compute derivatives of Kalman transition matrices A and B, but rather the solution matrices ghx,ghu,ghxx,ghxu,ghuu,ghs2,ghxxx,ghxxu,ghxuu,ghuuu,ghxss,ghuss in accordance with notation used in `oo_.dr`. As a byproduct at first-order, focusing on ghx and ghu instead of Kalman transition matrices A and B makes the computations slightly faster for large models (e.g. for Quest the computations were faster by a couple of seconds, not much, but okay). * Removed use of `kstate`, see also Dynare/dynare#1653 and Dynare/dynare!1656 * Output arguments are stored in a structure `DERIVS`, there is also a flag `d2flag` that computes parameter hessians needed only in `dsge_likelihood.m`. * Removed `kronflag` as input. `options_.analytic_derivation_mode` is now used instead of `kronflag`. * Removed `indvar`, an index that was used to selected specific variables in the derivatives. This is not needed, as we always compute the parameter derivatives for all variables first and then select a subset of variables. The selection now takes place in other functions, like `dsge_likelihood.m`. * Introduced some checks: (i) deterministic exogenous variables are not supported, (ii) Kronecker method only compatible with first-order approximation so reset to sylvester method, (iii) for purely backward or forward models we need to be careful with the rows in `M_.lead_la g_incidence`, (iv) if `_params_derivs.m` files are missing an error is thrown. * For numerical derivatives, if mod file does not contain an `estimated_params_block`, a temporary one with the most important parameter information is created. ## `unfold_g4.m` * When evaluating g3 and g4 one needs to take into account that these do not contain symmetric elements, so one needs to use `unfold_g3.m` and the new function `unfold_g4.m`. This returns an unfolded version of the same matrix (i.e. with symmetric elements). *** # New test models `.gitignore` and `Makefile.am` are changed accordingly. Also now it is possible to run test suite on analytic_derivatives, i.e. run `make check m/analytic_derivatives` ## `analytic_derivatives/BrockMirman_PertParamsDerivs.mod` * This is the Brock Mirman model, where we know the exact policy function $g$ for capital and consumption. As this does not imply a nonzero $g_{\sigma\sigma}$, $g_{x\sigma\sigma}$, $g_{u\sigma\sigma}$ I added some artificial equations to get nonzero solution matrices with respect to $\sigma$. The true perturbation solution matrices $g_x$ , $g_u$, $g_{xx}$, $g_{xu}$, $g_{uu}$, $g_{\sigma\sigma}$, $g_{xxx}$, $g_{xxu}$, $g_{xuu}$, $g_{uuu}$, $g_{x\sigma\sigma}$, $g_{u\sigma\sigma}$ are then computed analytically with Matlab's symbolic toolbox and saved in `nBrockMirmanSYM.mat`. There is a preprocessor flag that recreates these analytical computations if changes are needed (and to check whether I made some errors here ;-) ) * Then solution matrices up to third order and their parameter Jacobians are then compared to the ones computed by Dynare's `k_order_solver` and by `get_perturbation_params_derivs` for all `analytic_derivation_mode`'s. There will be an error if the maximum absolute deviation is too large, i.e. for numerical derivatives (`analytic_derivation_mode=-1|-2`) the tolerance is choosen lower (around 1e-5); for analytical methods we are stricter: around 1e-13 for first-order, 1e-12 for second order, and 1e-11 for third-order. * As a side note, this mod file also checks Dynare's `k_order_solver` algorithm and throws an error if something is wrong. * This test model shows that the new functionality works well. And analytical derivatives perform way better and accurate than numerical ones, even for this small model. ## `analytic_derivatives/burnside_3_order_PertParamsDerivs.mod` * This builds upon `tests/k_order_perturbation/burnside_k_order.mod` and computes the true parameter derivatives analytically by hand. * This test model also shows that the new functionality works well. ## `analytic_derivatives/LindeTrabandt2019.mod` * Shows that the new functionality also works for medium-sized models, i.e. a SW type model solved at third order with 35 variables (11 states). 2 shocks and 20 parameters. * This mod file can be used to tweak the speed of the computations in the future. * Compares numerical versus analytical parameter derivatives (for first, second and third order). Note that this model clearly shows that numerical ones are quite different than analytical ones even at first order! ## `identification/LindeTrabandt2019_xfail.mod` * This model is a check for issue Dynare/dynare#1595, see fjaco.m below, and will fail. * Removed `analytic_derivatives/ls2003.mod` as this mod file is neither in the testsuite nor does it work. *** # Detailed changes in other functions ## `get_first_order_solution_params_derivs.m` * Deleted, or actually, renamed to `get_perturbation_params_derivs.m`, as this function now is able to compute the derivatives up to third order ## `identification_numerical_objective.m` * `get_perturbation_params_derivs_numerical_objective.m`builds upon `identification_numerical_objective.m`. It takes from `identification_numerical_objective.m` the parts that compute numerical parameter Jacobians of steady state, dynamic model equations, and perturbation solution matrices. Hence, these parts are removed in `identification_numerical_objective.m` and it only computes numerical parameter Jacobian of moments and spectrum which are needed for identification analysis in `get_identification_jacobians.m`, when `analytic_derivation_mode=-1` only. ## `dsge_likelihood.m` * As `get_first_order_solution_params_derivs.m`is renamed to `get_perturbation_params_derivs.m`, the call is adapted. That is,`get_perturbation_params_derivs` does not compute the derivatives of the Kalman transition `T`matrix anymore, but instead of the dynare solution matrix `ghx`. So we recreate `T` here as this amounts to adding some zeros and focusing on selected variables only. * Added some checks to make sure the first-order approximation is selected. * Removed `kron_flag` as input, as `get_perturbation_params_derivs` looks into `options_.analytic_derivation_mode` for `kron_flag`. ## `dynare_identification.m` * make sure that setting `analytic_derivation_mode` is set both in `options_ident` and `options_`. Note that at the end of the function we restore the `options_` structure, so all changes are local. In a next merge request, I will remove the global variables to make all variables local. ## `get_identification_jacobians.m` * As `get_first_order_solution_params_derivs.m`is renamed to `get_perturbation_params_derivs.m`, the call is adapted. That is,`get_perturbation_params_derivs` does not compute the derivatives of the Kalman transition `A` and `B` matrix anymore, but instead of the dynare solution matrix `ghx` and `ghu`. So we recreate these matrices here instead of in `get_perturbation_params_derivs.m`. * Added `str2func` for better function handles in `fjaco.m`. ## `fjaco.m` * make `tol`an option, which can be adjusted by changing `options_.dynatol.x`for identification and parameter derivatives purposes. * include a check and an informative error message, if numerical derivatives (two-sided finite difference method) yield errors in `resol.m` for identification and parameter derivatives purposes. This closes issue Dynare/dynare#1595. * Changed year of copyright to 2010-2017,2019 *** # Further suggestions and questions * Ones this is merged, I will merge request an improvement of the identification toolbox, which will work up to third order using the pruned state space. This will also remove some issues and bugs, and also I will remove global variables in this request. * The third-order derivatives can be further improved by taking sparsity into account and use mex versions for kronecker products etc. I leave this for further testing (and if anybody actually uses this ;-) ) --- matlab/dsge_likelihood.m | 28 +- matlab/dynare_identification.m | 7 +- matlab/fjaco.m | 33 +- .../get_first_order_solution_params_deriv.m | 959 ----------- matlab/get_identification_jacobians.m | 16 +- matlab/get_perturbation_params_derivs.m | 1533 +++++++++++++++++ ...bation_params_derivs_numerical_objective.m | 109 ++ matlab/identification_numerical_objective.m | 23 +- matlab/unfold_g4.m | 46 + tests/.gitignore | 2 + tests/Makefile.am | 9 + .../BrockMirman_PertParamsDerivs.mod | 474 +++++ .../burnside_3_order_PertParamsDerivs.mod | 230 +++ tests/analytic_derivatives/ls2003.mod | 66 - .../analytic_derivatives/nBrockMirmanSYM.mat | Bin 0 -> 27186 bytes .../LindeTrabandt/LindeTrabandt2019_xfail.mod | 363 ++++ tests/identification/as2007/G_QT.mat | Bin 0 -> 1129 bytes tests/identification/as2007/as2007_QT.mod | 41 +- 18 files changed, 2856 insertions(+), 1083 deletions(-) delete mode 100644 matlab/get_first_order_solution_params_deriv.m create mode 100644 matlab/get_perturbation_params_derivs.m create mode 100644 matlab/get_perturbation_params_derivs_numerical_objective.m create mode 100644 matlab/unfold_g4.m create mode 100644 tests/analytic_derivatives/BrockMirman_PertParamsDerivs.mod create mode 100644 tests/analytic_derivatives/burnside_3_order_PertParamsDerivs.mod delete mode 100644 tests/analytic_derivatives/ls2003.mod create mode 100644 tests/analytic_derivatives/nBrockMirmanSYM.mat create mode 100644 tests/identification/LindeTrabandt/LindeTrabandt2019_xfail.mod create mode 100644 tests/identification/as2007/G_QT.mat diff --git a/matlab/dsge_likelihood.m b/matlab/dsge_likelihood.m index 0c67c6598..f44cb13fb 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 - 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); - else - [DT, ~, ~, DOm, DYss] = get_first_order_solution_params_deriv(A, B, EstimatedParameters, Model,DynareResults,DynareOptions,kron_flag,indparam,indexo,[],iv); + 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 + 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 + 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 8f9141896..6a09e8705 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 9b6f68abc..63f6f32c8 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,34 @@ 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 + probl_par = get_the_name(j,varargin{5}.TeX,varargin{3},varargin{2},varargin{5}); + skipline() + message = get_error_message(info,0,varargin{5}); + fprintf('Parameter error in numerical two-sided difference method:\n') + fprintf('Cannot solve the model for %s (info = %d, %s)\n', probl_par, info(1), message); + fprintf('Possible solutions:\n') + fprintf(' -- check your mod file, calibration and steady state computations carefully\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', probl_par); + 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 6cf4b0cc5..000000000 --- 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 . -% ========================================================================= -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 d4f5ebc52..20e919a78 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 000000000..28b7fd119 --- /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 . +% ========================================================================= +% 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 000000000..e108704f8 --- /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 . +% ========================================================================= + +%% 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 3de182d9f..c7acf5e4b 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 000000000..7c35456b4 --- /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 . + +[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 7e271be0b..e7925b2d4 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 8f2e01491..0c509f414 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -19,6 +19,8 @@ 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 \ 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 +385,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 +699,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 +820,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 +856,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 000000000..280ae10cc --- /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 . +% ========================================================================= + + +@#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/burnside_3_order_PertParamsDerivs.mod b/tests/analytic_derivatives/burnside_3_order_PertParamsDerivs.mod new file mode 100644 index 000000000..84b6ec7e0 --- /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 . +% ========================================================================= + + +/* + 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 a6cb0e684..000000000 --- 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 GIT binary patch literal 27186 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�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 literal 0 HcmV?d00001 diff --git a/tests/identification/as2007/as2007_QT.mod b/tests/identification/as2007/as2007_QT.mod index 8b7cfa35e..51318e1cc 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)