2012-06-08 19:10:19 +02:00
|
|
|
|
function [H,G,retcode]=discretionary_policy_engine(AAlag,AA0,AAlead,BB,bigw,instr_id,beta,solve_maxit,discretion_tol,qz_criterium,H00,verbose)
|
|
|
|
|
|
|
|
|
|
% Solves the discretionary problem for a model of the form:
|
2015-08-30 11:14:35 +02:00
|
|
|
|
%
|
|
|
|
|
% Loss=E_0 sum_{t=0}^{\infty} beta^t [y_t'*W*y+x_t'*Q*x_t]
|
|
|
|
|
% subject to
|
|
|
|
|
% AAlag*yy_{t-1}+AA0*yy_t+AAlead*yy_{t+1}+BB*e=0
|
|
|
|
|
%
|
|
|
|
|
% with W the weight on the variables in vector y_t.
|
|
|
|
|
%
|
|
|
|
|
% The solution takes the form
|
|
|
|
|
% y_t=H*y_{t-1}+G*e_t
|
|
|
|
|
% where H=[H1;F1] and G=[H2;F2].
|
|
|
|
|
%
|
2012-06-08 19:10:19 +02:00
|
|
|
|
% We use the Dennis (2007, Macroeconomic Dynamics) algorithm and so we need
|
|
|
|
|
% to re-write the model in the form
|
|
|
|
|
% A0*y_t=A1*y_{t-1}+A2*y_{t+1}+A3*x_t+A4*x_{t+1}+A5*e_t, with W the
|
|
|
|
|
% weight on the y_t vector and Q the weight on the x_t vector of
|
|
|
|
|
% instruments.
|
2015-08-30 11:14:35 +02:00
|
|
|
|
%
|
|
|
|
|
% Inputs:
|
|
|
|
|
% AAlag [double] matrix of coefficients on lagged
|
|
|
|
|
% variables
|
|
|
|
|
% AA0 [double] matrix of coefficients on
|
|
|
|
|
% contemporaneous variables
|
|
|
|
|
% AAlead [double] matrix of coefficients on
|
|
|
|
|
% leaded variables
|
|
|
|
|
% BB [double] matrix of coefficients on
|
|
|
|
|
% shocks
|
|
|
|
|
% bigw [double] matrix of coefficients on variables in
|
|
|
|
|
% loss/objective function; stacks [W and Q]
|
|
|
|
|
% instr_id [double] location vector of the instruments in the yy_t vector.
|
|
|
|
|
% beta [scalar] planner discount factor
|
|
|
|
|
% solve_maxit [scalar] maximum number of iterations
|
|
|
|
|
% discretion_tol [scalar] convergence criterion for solution
|
|
|
|
|
% qz_criterium [scalar] tolerance for QZ decomposition
|
|
|
|
|
% H00
|
|
|
|
|
% verbose [scalar] dummy to control verbosity
|
|
|
|
|
%
|
|
|
|
|
% Outputs:
|
|
|
|
|
% H [double] (endo_nbr*endo_nbr) solution matrix for endogenous
|
|
|
|
|
% variables, stacks [H1 and H1]
|
|
|
|
|
% G [double] (endo_nbr*exo_nbr) solution matrix for shocks, stacks [H2 and F2]
|
|
|
|
|
%
|
|
|
|
|
% retcode [scalar] return code
|
|
|
|
|
%
|
|
|
|
|
% Algorithm:
|
|
|
|
|
% Dennis, Richard (2007): Optimal policy in rational expectations models: new solution algorithms,
|
|
|
|
|
% Macroeconomic Dynamics, 11, 31<33>55.
|
2012-06-08 19:10:19 +02:00
|
|
|
|
|
2015-08-30 11:14:35 +02:00
|
|
|
|
% Copyright (C) 2007-2015 Dynare Team
|
2012-06-08 19:10:19 +02: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/>.
|
|
|
|
|
|
|
|
|
|
if nargin<12
|
|
|
|
|
verbose=0;
|
|
|
|
|
if nargin<11
|
|
|
|
|
H00=[];
|
|
|
|
|
if nargin<10
|
|
|
|
|
qz_criterium=1.000001;
|
|
|
|
|
if nargin<9
|
|
|
|
|
discretion_tol=sqrt(eps);
|
|
|
|
|
if nargin<8
|
|
|
|
|
solve_maxit=3000;
|
|
|
|
|
if nargin<7
|
|
|
|
|
beta=.99;
|
|
|
|
|
if nargin<6
|
|
|
|
|
error([mfilename,':: Insufficient number of input arguments'])
|
|
|
|
|
elseif nargin>12
|
|
|
|
|
error([mfilename,':: Number of input arguments cannot exceed 12'])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
[A0,A1,A2,A3,A4,A5,W,Q,endo_nbr,exo_nbr,aux,endo_augm_id]=GetDennisMatrices(AAlag,AA0,AAlead,BB,bigw,instr_id);
|
|
|
|
|
% aux is a logical index of the instruments which appear with lags in the
|
2015-08-30 11:14:35 +02:00
|
|
|
|
% model. Their location in the state vector is instr_id(aux);
|
2012-06-08 19:10:19 +02:00
|
|
|
|
% endo_augm_id is index (not logical) of locations of the augmented vector
|
|
|
|
|
% of non-instrumental variables
|
|
|
|
|
|
|
|
|
|
AuxiliaryVariables_nbr=sum(aux);
|
|
|
|
|
H0=zeros(endo_nbr+AuxiliaryVariables_nbr);
|
|
|
|
|
if ~isempty(H00)
|
2015-08-30 11:14:35 +02:00
|
|
|
|
H0(1:endo_nbr,1:endo_nbr)=H00;
|
|
|
|
|
clear H00
|
2012-06-08 19:10:19 +02:00
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
H10=H0(endo_augm_id,endo_augm_id);
|
|
|
|
|
F10=H0(instr_id,endo_augm_id);
|
|
|
|
|
|
|
|
|
|
iter=0;
|
|
|
|
|
H1=H10;
|
|
|
|
|
F1=F10;
|
2015-08-30 11:14:35 +02:00
|
|
|
|
%solve equations (20) and (22) via fixed point iteration
|
2012-06-08 19:10:19 +02:00
|
|
|
|
while 1
|
|
|
|
|
iter=iter+1;
|
|
|
|
|
P=SylvesterDoubling(W+beta*F1'*Q*F1,beta*H1',H1,discretion_tol,solve_maxit);
|
|
|
|
|
if any(any(isnan(P)))
|
|
|
|
|
P=SylvesterHessenbergSchur(W+beta*F1'*Q*F1,beta*H1',H1);
|
|
|
|
|
if any(any(isnan(P)))
|
|
|
|
|
retcode=2;
|
|
|
|
|
return
|
|
|
|
|
end
|
|
|
|
|
end
|
2015-08-30 11:14:35 +02:00
|
|
|
|
D=A0-A2*H1-A4*F1; %equation (20)
|
2012-06-08 19:10:19 +02:00
|
|
|
|
Dinv=inv(D);
|
2015-08-30 11:14:35 +02:00
|
|
|
|
A3DPD=A3'*Dinv'*P*Dinv;
|
|
|
|
|
F1=-(Q+A3DPD*A3)\(A3DPD*A1); %component of (26)
|
|
|
|
|
H1=Dinv*(A1+A3*F1); %component of (27)
|
2012-06-08 19:10:19 +02:00
|
|
|
|
|
|
|
|
|
[rcode,NQ]=CheckConvergence([H1;F1]-[H10;F10],iter,solve_maxit,discretion_tol);
|
|
|
|
|
if rcode
|
|
|
|
|
break
|
|
|
|
|
else
|
|
|
|
|
if verbose
|
|
|
|
|
disp(NQ)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
H10=H1;
|
|
|
|
|
F10=F1;
|
|
|
|
|
end
|
|
|
|
|
|
2015-08-30 11:14:35 +02:00
|
|
|
|
%check if successful
|
2012-06-08 19:10:19 +02:00
|
|
|
|
retcode = 0;
|
|
|
|
|
switch rcode
|
|
|
|
|
case 3 % nan
|
|
|
|
|
retcode=63;
|
|
|
|
|
retcode(2)=10000;
|
|
|
|
|
if verbose
|
2015-08-30 11:14:35 +02:00
|
|
|
|
disp([mfilename,':: NaN elements in the solution'])
|
2012-06-08 19:10:19 +02:00
|
|
|
|
end
|
|
|
|
|
case 2% maxiter
|
2015-08-30 11:14:35 +02:00
|
|
|
|
retcode = 61;
|
2012-06-08 19:10:19 +02:00
|
|
|
|
if verbose
|
|
|
|
|
disp([mfilename,':: Maximum Number of Iterations reached'])
|
|
|
|
|
end
|
|
|
|
|
case 1
|
|
|
|
|
BadEig=max(abs(eig(H1)))>qz_criterium;
|
|
|
|
|
if BadEig
|
|
|
|
|
retcode=62;
|
|
|
|
|
retcode(2)=100*max(abs(eig(H1)));
|
|
|
|
|
if verbose
|
|
|
|
|
disp([mfilename,':: Some eigenvalues greater than qz_criterium, Model potentially unstable'])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if retcode(1)
|
|
|
|
|
H=[];
|
|
|
|
|
G=[];
|
|
|
|
|
else
|
2015-08-30 11:14:35 +02:00
|
|
|
|
F2=-(Q+A3DPD*A3)\(A3DPD*A5); %equation (29)
|
|
|
|
|
H2=Dinv*(A5+A3*F2); %equation (31)
|
2012-06-08 19:10:19 +02:00
|
|
|
|
H=zeros(endo_nbr+AuxiliaryVariables_nbr);
|
|
|
|
|
G=zeros(endo_nbr+AuxiliaryVariables_nbr,exo_nbr);
|
|
|
|
|
H(endo_augm_id,endo_augm_id)=H1;
|
|
|
|
|
H(instr_id,endo_augm_id)=F1;
|
|
|
|
|
G(endo_augm_id,:)=H2;
|
|
|
|
|
G(instr_id,:)=F2;
|
|
|
|
|
|
|
|
|
|
% Account for auxilliary variables
|
|
|
|
|
H(:,instr_id(aux))=H(:,end-(AuxiliaryVariables_nbr-1:-1:0));
|
|
|
|
|
H=H(1:endo_nbr,1:endo_nbr);
|
|
|
|
|
G=G(1:endo_nbr,:);
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function [rcode,NQ]=CheckConvergence(Q,iter,MaxIter,crit)
|
|
|
|
|
|
|
|
|
|
NQ=max(max(abs(Q)));% norm(Q); seems too costly
|
|
|
|
|
if isnan(NQ)
|
|
|
|
|
rcode=3;
|
|
|
|
|
elseif iter>MaxIter;
|
|
|
|
|
rcode=2;
|
|
|
|
|
elseif NQ<crit
|
|
|
|
|
rcode=1;
|
|
|
|
|
else
|
|
|
|
|
rcode=0;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function [A00,A11,A22,A33,A44,A55,WW,Q,endo_nbr,exo_nbr,aux,endo_augm_id]=GetDennisMatrices(AAlag,AA0,AAlead,BB,bigw,instr_id)
|
2015-08-30 11:14:35 +02:00
|
|
|
|
%get the matrices to use the Dennis (2007) algorithm
|
2012-06-08 19:10:19 +02:00
|
|
|
|
[eq_nbr,endo_nbr]=size(AAlag);
|
|
|
|
|
exo_nbr=size(BB,2);
|
|
|
|
|
y=setdiff(1:endo_nbr,instr_id);
|
|
|
|
|
instr_nbr=numel(instr_id);
|
|
|
|
|
|
|
|
|
|
A0=AA0(:,y);
|
|
|
|
|
A1=-AAlag(:,y);
|
|
|
|
|
A2=-AAlead(:,y);
|
|
|
|
|
A3=-AA0(:,instr_id);
|
|
|
|
|
A4=-AAlead(:,instr_id);
|
|
|
|
|
A5=-BB;
|
|
|
|
|
W=bigw(y,y);
|
|
|
|
|
Q=bigw(instr_id,instr_id);
|
|
|
|
|
% Adjust for possible lags in instruments by creating auxiliary equations
|
|
|
|
|
A6=-AAlag(:,instr_id);
|
|
|
|
|
aux=any(A6);
|
|
|
|
|
AuxiliaryVariables_nbr=sum(aux);
|
|
|
|
|
ny=eq_nbr;
|
|
|
|
|
m=eq_nbr+AuxiliaryVariables_nbr;
|
|
|
|
|
A00=zeros(m);A00(1:ny,1:ny)=A0;A00(ny+1:end,ny+1:end)=eye(AuxiliaryVariables_nbr);
|
|
|
|
|
A11=zeros(m);A11(1:ny,1:ny)=A1;A11(1:ny,ny+1:end)=A6(:,aux);
|
|
|
|
|
A22=zeros(m);A22(1:ny,1:ny)=A2;
|
|
|
|
|
A33=zeros(m,instr_nbr);A33(1:ny,1:end)=A3;A33(ny+1:end,aux)=eye(AuxiliaryVariables_nbr);
|
|
|
|
|
A44=zeros(m,instr_nbr);A44(1:ny,1:end)=A4;
|
|
|
|
|
A55=zeros(m,exo_nbr);A55(1:ny,1:end)=A5;
|
|
|
|
|
WW=zeros(m);WW(1:ny,1:ny)=W;
|
|
|
|
|
endo_augm_id=setdiff(1:endo_nbr+AuxiliaryVariables_nbr,instr_id);
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function v= SylvesterDoubling (d,g,h,tol,maxit)
|
|
|
|
|
|
|
|
|
|
% DOUBLES Solves a Sylvester equation using doubling
|
|
|
|
|
%
|
|
|
|
|
% [v,info] = doubles (g,d,h,tol,maxit) uses a doubling algorithm
|
|
|
|
|
% to solve the Sylvester equation v = d + g v h
|
|
|
|
|
|
|
|
|
|
v = d;
|
|
|
|
|
for i =1:maxit,
|
|
|
|
|
vadd = g*v*h;
|
|
|
|
|
v = v+vadd;
|
|
|
|
|
if norm (vadd,1) <= (tol*norm(v,1))
|
|
|
|
|
break;
|
|
|
|
|
end
|
|
|
|
|
g = g*g;
|
|
|
|
|
h = h*h;
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
function v = SylvesterHessenbergSchur(d,g,h)
|
|
|
|
|
%
|
2015-08-30 11:14:35 +02:00
|
|
|
|
% DSYLHS Solves a discrete time sylvester equation using the
|
2012-06-08 19:10:19 +02:00
|
|
|
|
% Hessenberg-Schur algorithm
|
|
|
|
|
%
|
|
|
|
|
% v = DSYLHS(g,d,h) computes the matrix v that satisfies the
|
|
|
|
|
% discrete time sylvester equation
|
|
|
|
|
%
|
|
|
|
|
% v = d + g'vh
|
|
|
|
|
|
|
|
|
|
if size(g,1) >= size(h,1)
|
|
|
|
|
[u,gbarp] = hess(g');
|
|
|
|
|
[t,hbar] = schur(h);
|
|
|
|
|
[vbar] = sylvest_private(gbarp,u'*d*t,hbar,1e-15);
|
|
|
|
|
v = u*vbar*t';
|
|
|
|
|
else
|
|
|
|
|
[u,gbar] = schur(g);
|
|
|
|
|
[t,hbarp] = hess(h');
|
|
|
|
|
[vbar] = sylvest_private(hbarp,t'*d'*u,gbar,1e-15);
|
|
|
|
|
v = u*vbar'*t';
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function v = sylvest_private(g,d,h,tol)
|
|
|
|
|
%
|
|
|
|
|
% SYLVEST Solves a Sylvester equation
|
|
|
|
|
%
|
|
|
|
|
% solves the Sylvester equation
|
|
|
|
|
% v = d + g v h
|
|
|
|
|
% for v where both g and h must be upper block triangular.
|
|
|
|
|
% The output info is zero on a successful return.
|
|
|
|
|
% The input tol indicates when an element of g or h should be considered
|
|
|
|
|
% zero.
|
|
|
|
|
|
|
|
|
|
[m,n] = size(d);
|
|
|
|
|
v = zeros(m,n);
|
|
|
|
|
w = eye(m);
|
|
|
|
|
i = 1;
|
|
|
|
|
temp = [];
|
|
|
|
|
|
|
|
|
|
%First handle the i = 1 case outside the loop
|
|
|
|
|
|
|
|
|
|
if i< n,
|
|
|
|
|
if abs(h(i+1,i)) < tol,
|
|
|
|
|
v(:,i)= (w - g*h(i,i))\d(:,i);
|
|
|
|
|
i = i+1;
|
|
|
|
|
else
|
|
|
|
|
A = [w-g*h(i,i) (-g*h(i+1,i));...
|
|
|
|
|
-g*h(i,i+1) w-g*h(i+1,i+1)];
|
|
|
|
|
C = [d(:,i); d(:,i+1)];
|
|
|
|
|
X = A\C;
|
|
|
|
|
v(:,i) = X(1:m,:);
|
|
|
|
|
v(:,i+1) = X(m+1:2*m, :);
|
|
|
|
|
i = i+2;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
%Handle the rest of the matrix with the possible exception of i=n
|
|
|
|
|
|
|
|
|
|
while i<n,
|
|
|
|
|
b= i-1;
|
|
|
|
|
temp = [temp g*v(:,size(temp,2)+1:b)]; %#ok<AGROW>
|
|
|
|
|
if abs(h(i+1,i)) < tol,
|
|
|
|
|
v(:,i) = (w - g*h(i,i))\(d(:,i) + temp*h(1:b,i));
|
|
|
|
|
i = i+1;
|
|
|
|
|
else
|
|
|
|
|
A = [w - g*h(i,i) (-g*h(i+1,i)); ...
|
|
|
|
|
-g*h(i,i+1) w - g*h(i+1,i+1)];
|
|
|
|
|
C = [d(:,i) + temp*h(1:b,i); ...
|
|
|
|
|
d(:,i+1) + temp*h(1:b,i+1)];
|
|
|
|
|
X = A\C;
|
|
|
|
|
v(:,i) = X(1:m,:);
|
|
|
|
|
v(:,i+1) = X(m+1:2*m, :);
|
|
|
|
|
i = i+2;
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
%Handle the i = n case if i=n was not in a 2-2 block
|
|
|
|
|
|
|
|
|
|
if i==n,
|
|
|
|
|
b = i-1;
|
|
|
|
|
temp = [temp g*v(:,size(temp,2)+1:b)];
|
|
|
|
|
v(:,i) = (w-g*h(i,i))\(d(:,i) + temp*h(1:b,i));
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|