Much faster .m implementation of LBJ with block option
parent
0839ff78ae
commit
be648d350b
|
@ -0,0 +1,43 @@
|
|||
function dy = back_subst_lbj(c,ny,iyf,periods)
|
||||
% Computes backward substitution in LBJ
|
||||
%
|
||||
% INPUTS
|
||||
% c: matrix containing the D and d for Sébastien’s presentation
|
||||
% ny: number of endogenous variables
|
||||
% iyf: indices of forward variables inside the list of all endogenous variables
|
||||
% periods: number of simulation periods
|
||||
%
|
||||
% OUTPUTS
|
||||
% dy: vector of backsubstitution results
|
||||
|
||||
% Copyright © 2023 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
ir = (periods-2)*ny+(1:ny);
|
||||
irf = iyf+(periods-1)*ny;
|
||||
icf = 1:size(iyf,2);
|
||||
nrc = length(iyf)+1;
|
||||
|
||||
for i = 2:periods
|
||||
c(ir,nrc) = c(ir,nrc)-c(ir,icf)*c(irf,nrc);
|
||||
ir = ir-ny;
|
||||
irf = irf-ny;
|
||||
end
|
||||
|
||||
dy = reshape(c(:,nrc), ny, periods);
|
||||
|
||||
end
|
|
@ -94,8 +94,7 @@ for iter = 1:options_.simul.maxit
|
|||
icp = icp + ny;
|
||||
c (ic,:) = jacobian(:,is)\jacobian(:,isf1);
|
||||
end
|
||||
c = bksup1(c, ny, nrc, iyf, options_.periods);
|
||||
c = reshape(c, ny, options_.periods);
|
||||
c = back_subst_lbj(c, ny, iyf, options_.periods);
|
||||
endogenousvariables(:,M_.maximum_lag+(1:options_.periods)) = endogenousvariables(:,M_.maximum_lag+(1:options_.periods))+c;
|
||||
err = max(max(abs(c)));
|
||||
if verbose
|
||||
|
@ -119,27 +118,3 @@ if verbose
|
|||
end
|
||||
|
||||
end
|
||||
|
||||
function d = bksup1(c,ny,jcf,iyf,periods)
|
||||
% Solves deterministic models recursively by backsubstitution for one lead/lag
|
||||
%
|
||||
% INPUTS
|
||||
% ny: number of endogenous variables
|
||||
% jcf: variables index forward
|
||||
%
|
||||
% OUTPUTS
|
||||
% d: vector of backsubstitution results
|
||||
|
||||
ir = [(periods-2)*ny+1:ny+(periods-2)*ny];
|
||||
irf = iyf+(periods-1)*ny;
|
||||
icf = [1:size(iyf,2)];
|
||||
|
||||
for i = 2:periods
|
||||
c(ir,jcf) = c(ir,jcf)-c(ir,icf)*c(irf,jcf);
|
||||
ir = ir-ny;
|
||||
irf = irf-ny;
|
||||
end
|
||||
|
||||
d = c(:,jcf);
|
||||
|
||||
end
|
||||
|
|
|
@ -92,7 +92,11 @@ for blk = 1:nblocks
|
|||
y_index = M_.block_structure.block(blk).variable(end-M_.block_structure.block(blk).mfs+1:end);
|
||||
[y, T, success, maxblkerror, iter] = solve_one_boundary(fh_dynamic, y, exo_simul, M_.params, steady_state, T, y_index, M_.block_structure.block(blk).NNZDerivatives, options_.periods, M_.block_structure.block(blk).is_linear, blk, M_.maximum_lag, options_.simul.maxit, options_.dynatol.f, cutoff, options_.stack_solve_algo, is_forward, true, false, M_, options_);
|
||||
case {5, 8} % solveTwoBoundaries{Simple,Complete}
|
||||
[y, T, success, maxblkerror, iter] = solve_two_boundaries(fh_dynamic, y, exo_simul, steady_state, T, blk, cutoff, options_, M_);
|
||||
if ismember(options_.stack_solve_algo, [1 6])
|
||||
[y, T, success, maxblkerror, iter] = solve_two_boundaries_lbj(fh_dynamic, y, exo_simul, steady_state, T, blk, options_, M_);
|
||||
else
|
||||
[y, T, success, maxblkerror, iter] = solve_two_boundaries_stacked(fh_dynamic, y, exo_simul, steady_state, T, blk, cutoff, options_, M_);
|
||||
end
|
||||
end
|
||||
|
||||
tmp = y(M_.block_structure.block(blk).variable, :);
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
function [y, T, success, err, iter] = solve_two_boundaries_lbj(fh, y, x, steady_state, T, blk, options_, M_)
|
||||
% Computes the deterministic simulation of a block of equations containing
|
||||
% both lead and lag variables, using the LBJ algorithm.
|
||||
%
|
||||
% INPUTS
|
||||
% fh [handle] function handle to the dynamic file for the block
|
||||
% y [matrix] All the endogenous variables of the model
|
||||
% x [matrix] All the exogenous variables of the model
|
||||
% steady_state [vector] steady state of the model
|
||||
% T [matrix] Temporary terms
|
||||
% blk [integer] block number
|
||||
% options_ [structure] storing the options
|
||||
% M_ [structure] Model description
|
||||
%
|
||||
% OUTPUTS
|
||||
% y [matrix] All endogenous variables of the model
|
||||
% T [matrix] Temporary terms
|
||||
% success [logical] Whether a solution was found
|
||||
% err [double] ∞-norm of Δy
|
||||
% iter [integer] Number of iterations
|
||||
%
|
||||
% ALGORITHM
|
||||
% Laffargue, Boucekkine, Juillard (LBJ)
|
||||
% see Juillard (1996) Dynare: A program for the resolution and
|
||||
% simulation of dynamic models with forward variables through the use
|
||||
% of a relaxation algorithm. CEPREMAP. Couverture Orange. 9602.
|
||||
|
||||
% Copyright © 2023 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
sparse_rowval = M_.block_structure.block(blk).g1_sparse_rowval;
|
||||
sparse_colval = M_.block_structure.block(blk).g1_sparse_colval;
|
||||
sparse_colptr = M_.block_structure.block(blk).g1_sparse_colptr;
|
||||
|
||||
periods = options_.periods;
|
||||
|
||||
% NB: notations are deliberately similar to those of sim1_lbj.m
|
||||
|
||||
ny = M_.block_structure.block(blk).mfs;
|
||||
|
||||
% Compute which columns, in the 3×n-wide Jacobian, have non-zero elements
|
||||
% corresponding to the forward (iyf) or backward (iyp) variables
|
||||
iyp = find(sparse_colptr(2:ny+1)-sparse_colptr(1:ny));
|
||||
iyf = find(sparse_colptr(2*ny+2:end)-sparse_colptr(2*ny+1:end-1));
|
||||
|
||||
y_index = M_.block_structure.block(blk).variable(end-ny+1:end);
|
||||
|
||||
success = false;
|
||||
|
||||
for iter = 1:options_.simul.maxit
|
||||
h = clock;
|
||||
|
||||
c = zeros(ny*periods, length(iyf)+1); % Stores the D and d of Sébastien’s presentation
|
||||
it_ = M_.maximum_lag+1;
|
||||
[yy, T(:, it_), r, g1] = fh(dynendo(y, it_, M_), x(it_, :), M_.params, steady_state, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T(:, it_));
|
||||
y(:, it_) = yy(M_.endo_nbr+(1:M_.endo_nbr));
|
||||
ic = 1:ny;
|
||||
icp = iyp;
|
||||
c(ic, :) = full(g1(:, ny+(1:ny))) \ [ full(g1(:, 2*ny+iyf)) -r ];
|
||||
for it_ = M_.maximum_lag+(2:periods)
|
||||
[yy, T(:, it_), r, g1] = fh(dynendo(y, it_, M_), x(it_, :), M_.params, steady_state, ...
|
||||
sparse_rowval, sparse_colval, sparse_colptr, T(:, it_));
|
||||
y(:, it_) = yy(M_.endo_nbr+(1:M_.endo_nbr));
|
||||
j = [ full(g1(:, ny+(1:ny))) -r ];
|
||||
j(:, [ iyf ny+1 ]) = j(:, [ iyf ny+1 ]) - full(g1(:, iyp)) * c(icp, :);
|
||||
ic = ic + ny;
|
||||
icp = icp + ny;
|
||||
c(ic, :) = j(:, 1:ny) \ [ full(g1(:, 2*ny+iyf)) j(:, ny+1) ];
|
||||
end
|
||||
|
||||
dy = back_subst_lbj(c, ny, iyf, periods);
|
||||
|
||||
y(y_index, M_.maximum_lag+(1:periods)) = y(y_index, M_.maximum_lag+(1:periods)) + dy;
|
||||
err = max(max(abs(dy)));
|
||||
|
||||
if options_.verbosity
|
||||
fprintf('Iter: %s,\t err. = %s, \t time = %s\n', num2str(iter), num2str(err), num2str(etime(clock, h)));
|
||||
end
|
||||
if err < options_.dynatol.x
|
||||
success = true;
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function y3n = dynendo(y, it_, M_)
|
||||
y3n = reshape(y(:, it_+(-1:1)), 3*M_.endo_nbr, 1);
|
|
@ -1,6 +1,7 @@
|
|||
function [y, T, success, max_res, iter] = solve_two_boundaries(fh, y, x, steady_state, T, Block_Num, cutoff, options_, M_)
|
||||
% Computes the deterministic simulation of a block of equation containing
|
||||
% both lead and lag variables using relaxation methods
|
||||
function [y, T, success, max_res, iter] = solve_two_boundaries_stacked(fh, y, x, steady_state, T, Block_Num, cutoff, options_, M_)
|
||||
% Computes the deterministic simulation of a block of equations containing
|
||||
% both lead and lag variables, using a Newton method over the stacked Jacobian
|
||||
% (in particular, this excludes LBJ).
|
||||
%
|
||||
% INPUTS
|
||||
% fh [handle] function handle to the dynamic file for the block
|
||||
|
@ -47,6 +48,10 @@ periods = options_.periods;
|
|||
y_kmin = M_.maximum_lag;
|
||||
stack_solve_algo = options_.stack_solve_algo;
|
||||
|
||||
if ~ismember(stack_solve_algo, [0 2 3 4])
|
||||
error('Unsupported stack_solve_algo value')
|
||||
end
|
||||
|
||||
verbose = options_.verbosity;
|
||||
|
||||
cvg=false;
|
||||
|
@ -158,46 +163,6 @@ while ~(cvg || iter > options_.simul.maxit)
|
|||
dx = g1a\b- ya;
|
||||
ya = ya + lambda*dx;
|
||||
y(y_index, y_kmin+(1:periods))=reshape(ya',length(y_index),periods);
|
||||
elseif stack_solve_algo==1 || stack_solve_algo==6
|
||||
for t=1:periods
|
||||
first_elem = (t-1)*Blck_size+1;
|
||||
last_elem = t*Blck_size;
|
||||
next_elem = (t+1)*Blck_size;
|
||||
Elem = first_elem:last_elem;
|
||||
Elem_1 = last_elem+1:next_elem;
|
||||
B1_inv = inv(g1a(Elem, Elem));
|
||||
if (t < periods)
|
||||
S1 = B1_inv * g1a(Elem, Elem_1);
|
||||
g1a(Elem, Elem_1) = S1;
|
||||
end
|
||||
b(Elem) = B1_inv * b(Elem);
|
||||
g1a(Elem, Elem) = ones(Blck_size, Blck_size);
|
||||
if t<periods
|
||||
g1a(Elem_1, Elem_1) = g1a(Elem_1, Elem_1) - g1a(Elem_1, Elem) * S1;
|
||||
b(Elem_1) = b(Elem_1) - g1a(Elem_1, Elem) * b(Elem);
|
||||
g1a(Elem_1, Elem) = zeros(Blck_size, Blck_size);
|
||||
end
|
||||
end
|
||||
za = b(Elem);
|
||||
zaa = za;
|
||||
y_Elem = (periods - 1) * Blck_size + 1:(periods) * Blck_size;
|
||||
dx = ya;
|
||||
dx(y_Elem) = za - ya(y_Elem);
|
||||
ya(y_Elem) = ya(y_Elem) + lambda*dx(y_Elem);
|
||||
y(y_index, y_kmin + periods) = ya(y_Elem);
|
||||
for t=periods-1:-1:1
|
||||
first_elem = (t-1)*Blck_size+1;
|
||||
last_elem = t*Blck_size;
|
||||
next_elem = (t+1)*Blck_size;
|
||||
Elem_1 = last_elem+1:next_elem;
|
||||
Elem = first_elem:last_elem;
|
||||
za = b(Elem) - g1a(Elem, Elem_1) * zaa;
|
||||
zaa = za;
|
||||
y_Elem = Blck_size * (t-1)+1:Blck_size * (t);
|
||||
dx(y_Elem) = za - ya(y_Elem);
|
||||
ya(y_Elem) = ya(y_Elem) + lambda*dx(y_Elem);
|
||||
y(y_index, y_kmin + t) = ya(y_Elem);
|
||||
end
|
||||
elseif stack_solve_algo==2
|
||||
flag1=1;
|
||||
while flag1>0
|
Loading…
Reference in New Issue