2018-05-05 10:24:01 +02:00
|
|
|
function [dr, info] = dyn_first_order_solver(jacobia, DynareModel, dr, DynareOptions, task)
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2018-05-05 10:24:01 +02:00
|
|
|
% Computes the first order reduced form of a DSGE model.
|
|
|
|
%
|
|
|
|
% INPUTS
|
|
|
|
% - jacobia [double] matrix, the jacobian of the dynamic model.
|
|
|
|
% - DynareModel [struct] Matlab's structre describing the model, M_ global.
|
|
|
|
% - dr [struct] Matlab's structure describing the reduced form model.
|
|
|
|
% - DynareOptions [struct] Matlab's structure containing the current state of the options, oo_ global.
|
|
|
|
% - task [integer] scalar, if task = 0 then decision rules are computed and if task = 1 then only eigenvales are computed.
|
|
|
|
%
|
|
|
|
% OUTPUTS
|
|
|
|
% - dr [struct] Matlab's structure describing the reduced form model.
|
|
|
|
% - info [integer] scalar, error code. Possible values are:
|
|
|
|
%
|
|
|
|
% info=0 -> no error,
|
|
|
|
% info=1 -> the model doesn't determine the current variables uniquely,
|
|
|
|
% info=2 -> mjdgges dll returned an error,
|
|
|
|
% info=3 -> Blanchard and Kahn conditions are not satisfied: no stable equilibrium,
|
|
|
|
% info=4 -> Blanchard and Kahn conditions are not satisfied: indeterminacy,
|
|
|
|
% info=5 -> Blanchard and Kahn conditions are not satisfied: indeterminacy due to rank failure,
|
|
|
|
% info=7 -> One of the eigenvalues is close to 0/0 (infinity of complex solutions)
|
2011-12-20 16:34:30 +01:00
|
|
|
|
2020-01-10 17:55:57 +01:00
|
|
|
% Copyright (C) 2001-2020 Dynare Team
|
2011-12-20 16:34:30 +01:00
|
|
|
%
|
|
|
|
% This file is part of Dynare.
|
|
|
|
%
|
|
|
|
% Dynare is free software: you can redistribute it and/or modify
|
|
|
|
% it under the terms of the GNU General Public License as published by
|
|
|
|
% the Free Software Foundation, either version 3 of the License, or
|
|
|
|
% (at your option) any later version.
|
|
|
|
%
|
|
|
|
% Dynare is distributed in the hope that it will be useful,
|
|
|
|
% but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
% GNU General Public License for more details.
|
|
|
|
%
|
|
|
|
% You should have received a copy of the GNU General Public License
|
|
|
|
% along with Dynare. If not, see <http://www.gnu.org/licenses/>.
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
persistent reorder_jacobian_columns innovations_idx index_s index_m index_c
|
|
|
|
persistent index_p row_indx index_0m index_0p k1 k2 state_var
|
2017-05-16 15:10:20 +02:00
|
|
|
persistent ndynamic nstatic nfwrd npred nboth nd nsfwrd n_current index_d
|
|
|
|
persistent index_e index_d1 index_d2 index_e1 index_e2 row_indx_de_1
|
2012-07-16 15:52:36 +02:00
|
|
|
persistent row_indx_de_2 cols_b
|
2012-07-11 17:04:20 +02:00
|
|
|
|
|
|
|
|
|
|
|
if ~nargin
|
2012-07-12 09:18:04 +02:00
|
|
|
if nargout
|
|
|
|
error('dyn_first_order_solver:: Initialization mode returns zero argument!')
|
|
|
|
end
|
2012-07-11 17:04:20 +02:00
|
|
|
reorder_jacobian_columns = [];
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
exo_nbr = DynareModel.exo_nbr;
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
if isempty(reorder_jacobian_columns)
|
2017-05-16 15:10:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
maximum_lag = DynareModel.maximum_endo_lag;
|
2012-07-11 17:04:20 +02:00
|
|
|
kstate = dr.kstate;
|
2012-11-16 20:05:13 +01:00
|
|
|
nfwrd = DynareModel.nfwrd;
|
|
|
|
nboth = DynareModel.nboth;
|
|
|
|
npred = DynareModel.npred;
|
|
|
|
nstatic = DynareModel.nstatic;
|
|
|
|
ndynamic = DynareModel.ndynamic;
|
|
|
|
nsfwrd = DynareModel.nsfwrd;
|
2012-07-16 15:52:36 +02:00
|
|
|
n = DynareModel.endo_nbr;
|
2012-07-11 17:04:20 +02:00
|
|
|
|
|
|
|
k1 = 1:(npred+nboth);
|
|
|
|
k2 = 1:(nfwrd+nboth);
|
|
|
|
|
2011-12-17 17:35:42 +01:00
|
|
|
order_var = dr.order_var;
|
|
|
|
nd = size(kstate,1);
|
2012-07-11 17:04:20 +02:00
|
|
|
lead_lag_incidence = DynareModel.lead_lag_incidence;
|
2011-12-17 17:35:42 +01:00
|
|
|
nz = nnz(lead_lag_incidence);
|
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
lead_id = find(lead_lag_incidence(maximum_lag+2,:));
|
|
|
|
lead_idx = lead_lag_incidence(maximum_lag+2,lead_id);
|
|
|
|
if maximum_lag
|
|
|
|
lag_id = find(lead_lag_incidence(1,:));
|
|
|
|
lag_idx = lead_lag_incidence(1,lag_id);
|
|
|
|
static_id = find((lead_lag_incidence(1,:) == 0) & ...
|
|
|
|
(lead_lag_incidence(3,:) == 0));
|
|
|
|
else
|
|
|
|
lag_id = [];
|
|
|
|
lag_idx = [];
|
|
|
|
static_id = find(lead_lag_incidence(2,:)==0);
|
2011-12-17 17:35:42 +01:00
|
|
|
end
|
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
both_id = intersect(lead_id,lag_id);
|
|
|
|
if maximum_lag
|
|
|
|
no_both_lag_id = setdiff(lag_id,both_id);
|
|
|
|
else
|
2012-10-14 22:54:49 +02:00
|
|
|
no_both_lag_id = lag_id;
|
2012-07-16 15:52:36 +02:00
|
|
|
end
|
|
|
|
innovations_idx = nz+(1:exo_nbr);
|
2012-10-14 22:54:49 +02:00
|
|
|
state_var = [no_both_lag_id, both_id];
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
index_c = nonzeros(lead_lag_incidence(maximum_lag+1,:)); % Index of all endogenous variables present at time=t
|
|
|
|
n_current = length(index_c);
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
index_s = npred+nboth+(1:nstatic); % Index of all static
|
|
|
|
% endogenous variables
|
|
|
|
% present at time=t
|
|
|
|
indexi_0 = npred+nboth;
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
npred0 = nnz(lead_lag_incidence(maximum_lag+1,no_both_lag_id));
|
|
|
|
index_0m = indexi_0+nstatic+(1:npred0);
|
2019-03-08 15:54:10 +01:00
|
|
|
nfwrd0 = nnz(lead_lag_incidence(maximum_lag+1,lead_id));
|
2012-07-16 15:52:36 +02:00
|
|
|
index_0p = indexi_0+nstatic+npred0+(1:nfwrd0);
|
|
|
|
index_m = 1:(npred+nboth);
|
2012-07-17 10:07:09 +02:00
|
|
|
index_p = npred+nboth+n_current+(1:nfwrd+nboth);
|
2012-07-16 15:52:36 +02:00
|
|
|
row_indx_de_1 = 1:ndynamic;
|
2012-07-17 10:07:09 +02:00
|
|
|
row_indx_de_2 = ndynamic+(1:nboth);
|
2012-07-16 15:52:36 +02:00
|
|
|
row_indx = nstatic+row_indx_de_1;
|
|
|
|
index_d = [index_0m index_p];
|
|
|
|
llx = lead_lag_incidence(:,order_var);
|
2012-11-16 20:05:13 +01:00
|
|
|
index_d1 = [find(llx(maximum_lag+1,nstatic+(1:npred))), npred+nboth+(1:nsfwrd) ];
|
2012-07-17 10:07:09 +02:00
|
|
|
index_d2 = npred+(1:nboth);
|
2012-07-16 15:52:36 +02:00
|
|
|
|
|
|
|
index_e = [index_m index_0p];
|
2012-07-17 10:07:09 +02:00
|
|
|
index_e1 = [1:npred+nboth, npred+nboth+find(llx(maximum_lag+1,nstatic+npred+(1: ...
|
2012-11-16 20:05:13 +01:00
|
|
|
nsfwrd)))];
|
2012-10-31 17:56:20 +01:00
|
|
|
index_e2 = npred+nboth+(1:nboth);
|
2017-05-16 15:10:20 +02:00
|
|
|
|
2018-11-13 17:58:42 +01:00
|
|
|
[~,cols_b] = find(lead_lag_incidence(maximum_lag+1, order_var));
|
2012-07-16 15:52:36 +02:00
|
|
|
|
|
|
|
reorder_jacobian_columns = [nonzeros(lead_lag_incidence(:,order_var)'); ...
|
|
|
|
nz+(1:exo_nbr)'];
|
|
|
|
end
|
2012-07-11 17:04:20 +02:00
|
|
|
|
|
|
|
dr.ghx = [];
|
|
|
|
dr.ghu = [];
|
|
|
|
|
2012-07-12 09:18:04 +02:00
|
|
|
dr.state_var = state_var;
|
|
|
|
|
2012-07-11 17:04:20 +02:00
|
|
|
jacobia = jacobia(:,reorder_jacobian_columns);
|
|
|
|
|
|
|
|
if nstatic > 0
|
2018-11-13 17:58:42 +01:00
|
|
|
[Q, ~] = qr(jacobia(:,index_s));
|
2012-07-11 17:04:20 +02:00
|
|
|
aa = Q'*jacobia;
|
|
|
|
else
|
|
|
|
aa = jacobia;
|
|
|
|
end
|
|
|
|
|
|
|
|
A = aa(:,index_m); % Jacobain matrix for lagged endogeneous variables
|
2012-07-16 15:52:36 +02:00
|
|
|
B(:,cols_b) = aa(:,index_c); % Jacobian matrix for contemporaneous endogeneous variables
|
2012-07-11 17:04:20 +02:00
|
|
|
C = aa(:,index_p); % Jacobain matrix for led endogeneous variables
|
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
info = 0;
|
2012-07-11 18:25:04 +02:00
|
|
|
if task ~= 1 && (DynareOptions.dr_cycle_reduction || DynareOptions.dr_logarithmic_reduction)
|
2012-07-16 15:52:36 +02:00
|
|
|
if n_current < DynareModel.endo_nbr
|
|
|
|
if DynareOptions.dr_cycle_reduction
|
|
|
|
error(['The cycle reduction algorithme can''t be used when the ' ...
|
2017-05-16 15:10:20 +02:00
|
|
|
'coefficient matrix for current variables isn''t invertible'])
|
2012-07-16 15:52:36 +02:00
|
|
|
elseif DynareOptions.dr_logarithmic_reduction
|
|
|
|
error(['The logarithmic reduction algorithme can''t be used when the ' ...
|
2012-07-22 12:56:51 +02:00
|
|
|
'coefficient matrix for current variables isn''t invertible'])
|
2012-07-16 15:52:36 +02:00
|
|
|
end
|
2017-05-16 15:10:20 +02:00
|
|
|
end
|
2012-07-20 17:06:12 +02:00
|
|
|
if DynareOptions.gpu
|
|
|
|
gpuArray(A1);
|
|
|
|
gpuArray(B1);
|
|
|
|
gpuArray(C1);
|
|
|
|
end
|
2012-07-11 17:04:20 +02:00
|
|
|
A1 = [aa(row_indx,index_m ) zeros(ndynamic,nfwrd)];
|
|
|
|
B1 = [aa(row_indx,index_0m) aa(row_indx,index_0p) ];
|
|
|
|
C1 = [zeros(ndynamic,npred) aa(row_indx,index_p)];
|
2019-03-19 14:26:16 +01:00
|
|
|
if DynareOptions.dr_cycle_reduction
|
2012-07-22 12:56:51 +02:00
|
|
|
[ghx, info] = cycle_reduction(A1, B1, C1, DynareOptions.dr_cycle_reduction_tol);
|
2012-07-11 18:25:04 +02:00
|
|
|
else
|
2012-07-22 12:56:51 +02:00
|
|
|
[ghx, info] = logarithmic_reduction(C1, B1, A1, DynareOptions.dr_logarithmic_reduction_tol, DynareOptions.dr_logarithmic_reduction_maxiter);
|
|
|
|
end
|
|
|
|
if info
|
|
|
|
% cycle_reduction or logarithmic redution failed and set info
|
|
|
|
return
|
2012-07-11 18:25:04 +02:00
|
|
|
end
|
2012-07-11 17:04:20 +02:00
|
|
|
ghx = ghx(:,index_m);
|
|
|
|
hx = ghx(1:npred+nboth,:);
|
|
|
|
gx = ghx(1+npred:end,:);
|
2012-07-22 12:56:51 +02:00
|
|
|
else
|
2012-07-16 15:52:36 +02:00
|
|
|
D = zeros(ndynamic+nboth);
|
|
|
|
E = zeros(ndynamic+nboth);
|
|
|
|
D(row_indx_de_1,index_d1) = aa(row_indx,index_d);
|
|
|
|
D(row_indx_de_2,index_d2) = eye(nboth);
|
|
|
|
E(row_indx_de_1,index_e1) = -aa(row_indx,index_e);
|
|
|
|
E(row_indx_de_2,index_e2) = eye(nboth);
|
2017-05-16 15:10:20 +02:00
|
|
|
|
2020-01-10 17:55:57 +01:00
|
|
|
[ss, tt, w, sdim, dr.eigval, info1] = mjdgges(E, D, DynareOptions.qz_criterium, DynareOptions.qz_zero_threshold);
|
2011-12-17 17:35:42 +01:00
|
|
|
|
2012-07-22 12:56:51 +02:00
|
|
|
if info1
|
|
|
|
if info1 == -30
|
2012-04-23 11:45:44 +02:00
|
|
|
% one eigenvalue is close to 0/0
|
2011-12-17 17:35:42 +01:00
|
|
|
info(1) = 7;
|
|
|
|
else
|
|
|
|
info(1) = 2;
|
|
|
|
info(2) = info1;
|
2012-07-11 17:04:20 +02:00
|
|
|
info(3) = size(E,2);
|
2011-12-17 17:35:42 +01:00
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
|
2018-05-05 16:36:50 +02:00
|
|
|
dr.sdim = sdim; % Number of stable eigenvalues.
|
|
|
|
dr.edim = length(dr.eigval)-sdim; % Number of exposive eigenvalues.
|
|
|
|
|
2011-12-17 17:35:42 +01:00
|
|
|
nba = nd-sdim;
|
|
|
|
|
2018-05-05 10:29:37 +02:00
|
|
|
if task==1
|
2012-09-10 13:25:31 +02:00
|
|
|
if rcond(w(npred+nboth+1:end,npred+nboth+1:end)) < 1e-9
|
|
|
|
dr.full_rank = 0;
|
|
|
|
else
|
|
|
|
dr.full_rank = 1;
|
2017-05-16 15:10:20 +02:00
|
|
|
end
|
2011-12-17 17:35:42 +01:00
|
|
|
end
|
|
|
|
|
2012-11-16 20:05:13 +01:00
|
|
|
if nba ~= nsfwrd
|
2011-12-17 17:35:42 +01:00
|
|
|
temp = sort(abs(dr.eigval));
|
2012-11-16 20:05:13 +01:00
|
|
|
if nba > nsfwrd
|
|
|
|
temp = temp(nd-nba+1:nd-nsfwrd)-1-DynareOptions.qz_criterium;
|
2011-12-17 17:35:42 +01:00
|
|
|
info(1) = 3;
|
2017-05-16 12:42:01 +02:00
|
|
|
elseif nba < nsfwrd
|
2012-11-16 20:05:13 +01:00
|
|
|
temp = temp(nd-nsfwrd+1:nd-nba)-1-DynareOptions.qz_criterium;
|
2011-12-17 17:35:42 +01:00
|
|
|
info(1) = 4;
|
|
|
|
end
|
|
|
|
info(2) = temp'*temp;
|
|
|
|
return
|
|
|
|
end
|
2018-05-05 10:29:37 +02:00
|
|
|
|
|
|
|
if task==1, return, end
|
|
|
|
|
2012-07-11 17:04:20 +02:00
|
|
|
%First order approximation
|
2018-05-05 10:29:37 +02:00
|
|
|
indx_stable_root = 1: (nd - nsfwrd); %=> index of stable roots
|
2012-07-16 15:52:36 +02:00
|
|
|
indx_explosive_root = npred + nboth + 1:nd; %=> index of explosive roots
|
|
|
|
% derivatives with respect to dynamic state variables
|
|
|
|
% forward variables
|
|
|
|
Z = w';
|
2012-07-22 12:56:51 +02:00
|
|
|
Z11 = Z(indx_stable_root, indx_stable_root);
|
2012-07-16 15:52:36 +02:00
|
|
|
Z21 = Z(indx_explosive_root, indx_stable_root);
|
|
|
|
Z22 = Z(indx_explosive_root, indx_explosive_root);
|
2015-07-31 11:25:22 +02:00
|
|
|
opts.TRANSA = false; % needed by Octave 4.0.0
|
|
|
|
[minus_gx,rc] = linsolve(Z22,Z21,opts);
|
2012-07-22 12:56:51 +02:00
|
|
|
if rc < 1e-9
|
|
|
|
% Z22 is near singular
|
2012-07-16 15:52:36 +02:00
|
|
|
info(1) = 5;
|
2012-07-22 12:56:51 +02:00
|
|
|
info(2) = -log(rc);
|
2017-05-16 12:42:01 +02:00
|
|
|
return
|
2012-07-16 15:52:36 +02:00
|
|
|
end
|
2012-07-22 12:56:51 +02:00
|
|
|
gx = -minus_gx;
|
2012-07-16 15:52:36 +02:00
|
|
|
% predetermined variables
|
2012-07-22 12:56:51 +02:00
|
|
|
opts.UT = true;
|
|
|
|
opts.TRANSA = true;
|
|
|
|
hx1 = linsolve(tt(indx_stable_root, indx_stable_root),Z11,opts)';
|
2015-07-31 19:37:02 +02:00
|
|
|
opts.UT = false; % needed by Octave 4.0.0
|
|
|
|
opts.TRANSA = false; % needed by Octave 4.0.0
|
2015-07-31 11:25:22 +02:00
|
|
|
hx2 = linsolve(Z11,ss(indx_stable_root, indx_stable_root)',opts)';
|
2012-07-22 12:56:51 +02:00
|
|
|
hx = hx1*hx2;
|
2012-07-16 15:52:36 +02:00
|
|
|
ghx = [hx(k1,:); gx(k2(nboth+1:end),:)];
|
|
|
|
end
|
2011-12-17 17:35:42 +01:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
if nstatic > 0
|
|
|
|
B_static = B(:,1:nstatic); % submatrix containing the derivatives w.r. to static variables
|
|
|
|
else
|
|
|
|
B_static = [];
|
2017-05-16 12:42:01 +02:00
|
|
|
end
|
2012-07-16 15:52:36 +02:00
|
|
|
%static variables, backward variable, mixed variables and forward variables
|
|
|
|
B_pred = B(:,nstatic+1:nstatic+npred+nboth);
|
|
|
|
B_fyd = B(:,nstatic+npred+nboth+1:end);
|
2011-12-17 17:35:42 +01:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
% static variables
|
|
|
|
if nstatic > 0
|
|
|
|
temp = - C(1:nstatic,:)*gx*hx;
|
|
|
|
b(:,cols_b) = aa(:,index_c);
|
|
|
|
b10 = b(1:nstatic, 1:nstatic);
|
|
|
|
b11 = b(1:nstatic, nstatic+1:end);
|
|
|
|
temp(:,index_m) = temp(:,index_m)-A(1:nstatic,:);
|
|
|
|
temp = b10\(temp-b11*ghx);
|
|
|
|
ghx = [temp; ghx];
|
|
|
|
temp = [];
|
|
|
|
end
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
A_ = real([B_static C*gx+B_pred B_fyd]); % The state_variable of the block are located at [B_pred B_both]
|
2012-07-11 17:04:20 +02:00
|
|
|
|
2012-07-16 15:52:36 +02:00
|
|
|
if exo_nbr
|
|
|
|
if nstatic > 0
|
|
|
|
fu = Q' * jacobia(:,innovations_idx);
|
2012-07-11 17:04:20 +02:00
|
|
|
else
|
2012-07-16 15:52:36 +02:00
|
|
|
fu = jacobia(:,innovations_idx);
|
2017-05-16 12:42:01 +02:00
|
|
|
end
|
2012-07-16 15:52:36 +02:00
|
|
|
|
|
|
|
ghu = - A_ \ fu;
|
|
|
|
else
|
|
|
|
ghu = [];
|
2017-05-16 12:42:01 +02:00
|
|
|
end
|
2012-07-16 15:52:36 +02:00
|
|
|
|
2012-07-11 17:04:20 +02:00
|
|
|
dr.ghx = ghx;
|
|
|
|
dr.ghu = ghu;
|
|
|
|
|
2018-05-16 17:06:36 +02:00
|
|
|
if DynareOptions.aim_solver ~= 1
|
2012-07-11 17:04:20 +02:00
|
|
|
% Necessary when using Sims' routines for QZ
|
|
|
|
dr.ghx = real(ghx);
|
|
|
|
dr.ghu = real(ghu);
|
|
|
|
hx = real(hx);
|
|
|
|
end
|
2011-12-17 17:35:42 +01:00
|
|
|
|
2012-09-19 16:59:19 +02:00
|
|
|
% non-predetermined variables
|
|
|
|
dr.gx = gx;
|
|
|
|
%predetermined (endogenous state) variables, square transition matrix
|
2012-11-16 20:05:13 +01:00
|
|
|
dr.Gy = hx;
|