diff --git a/matlab/perfect-foresight-models/sim1_linear.m b/matlab/perfect-foresight-models/sim1_linear.m index 0cf316034b34e255ef5aa21cb9c4afc25279472c..26c52184cb3330231c53b0bc1700f3d377a9e30b 100644 --- a/matlab/perfect-foresight-models/sim1_linear.m +++ b/matlab/perfect-foresight-models/sim1_linear.m @@ -39,7 +39,7 @@ function [endogenousvariables, success, ERR] = sim1_linear(endogenousvariables, % to center the variables around the deterministic steady state to solve the % perfect foresight model. -% Copyright © 2015-2023 Dynare Team +% Copyright © 2015-2024 Dynare Team % % This file is part of Dynare. % @@ -58,49 +58,15 @@ function [endogenousvariables, success, ERR] = sim1_linear(endogenousvariables, verbose = options_.verbosity; -lead_lag_incidence = M_.lead_lag_incidence; - ny = M_.endo_nbr; nx = M_.exo_nbr; maximum_lag = M_.maximum_lag; -max_lag = M_.maximum_endo_lag; - -nyp = nnz(lead_lag_incidence(1,:)); -ny0 = nnz(lead_lag_incidence(2,:)); -nyf = nnz(lead_lag_incidence(3,:)); - -nd = nyp+ny0+nyf; % size of y (first argument passed to the dynamic file). periods = options_.periods; params = M_.params; -% Indices in A. -ip = find(lead_lag_incidence(1,:)'); -ic = find(lead_lag_incidence(2,:)'); -in = find(lead_lag_incidence(3,:)'); -icn = find(lead_lag_incidence(2:3,:)'); -ipcn = find(lead_lag_incidence'); - -% Indices in y. -jp = nonzeros(lead_lag_incidence(1,:)'); -jc = nonzeros(lead_lag_incidence(2,:)'); -jn = nonzeros(lead_lag_incidence(3,:)'); -jpc = [jp; jc]; -jcn = [jc; jn]; - -jexog = transpose(nd+(1:nx)); -jendo = transpose(1:nd); - -i_upd = maximum_lag*ny+(1:periods*ny); - -% Center the endogenous and exogenous variables around the deterministic steady state. -endogenousvariables = bsxfun(@minus, endogenousvariables, steadystate_y); -exogenousvariables = bsxfun(@minus, exogenousvariables, transpose(steadystate_x)); - -Y = endogenousvariables(:); - if verbose skipline() printline(80) @@ -108,24 +74,26 @@ if verbose skipline() end -dynamicmodel = str2func([M_.fname,'.dynamic']); - -z = steadystate_y([ip; ic; in]); -x = repmat(transpose(steadystate_x), 1+M_.maximum_exo_lag+M_.maximum_exo_lead, 1); - % Evaluate the Jacobian of the dynamic model at the deterministic steady state. -[d1, jacobian] = dynamicmodel(z, x, params, steadystate_y, M_.maximum_exo_lag+1); +y3n = repmat(steadystate_y, 3, 1); +[d1, TT_order, TT] = feval([M_.fname,'.sparse.dynamic_resid'], y3n, steadystate_x', params, ... + steadystate_y); +jacobian = feval([M_.fname,'.sparse.dynamic_g1'], y3n, steadystate_x', params, steadystate_y, ... + M_.dynamic_g1_sparse_rowval, M_.dynamic_g1_sparse_colval, ... + M_.dynamic_g1_sparse_colptr, TT_order, TT); + if options_.debug - column=find(all(jacobian==0,1)); + column=find(all(jacobian(:, 1:3*ny)==0,1)); if ~isempty(column) fprintf('The dynamic Jacobian is singular. The problem derives from:\n') for iter=1:length(column) - [var_row,var_index]=find(M_.lead_lag_incidence==column(iter)); - if var_row==2 + var_index = mod(column(iter)-1, ny)+1; + lead_lag = floor((column(iter)-1)/ny)-1; + if lead_lag == 0 fprintf('The derivative with respect to %s being 0 for all equations.\n',M_.endo_names{var_index}) - elseif var_row==1 + elseif lead_lag == -1 fprintf('The derivative with respect to the lag of %s being 0 for all equations.\n',M_.endo_names{var_index}) - elseif var_row==3 + elseif lead_lag == 1 fprintf('The derivative with respect to the lead of %s being 0 for all equations.\n',M_.endo_names{var_index}) end end @@ -137,55 +105,25 @@ if ~options_.steadystate.nocheck && max(abs(d1))>options_.solve_tolf error('Jacobian is not evaluated at the steady state!') end -% current variables -[r0,c0,v0] = find(jacobian(:,jc)); -% current and predetermined -[rT,cT,vT] = find(jacobian(:,jpc)); -% current and jump variables -[r1,c1,v1] = find(jacobian(:,jcn)); -% all endogenous variables -[rr,cc,vv] = find(jacobian(:,jendo)); - -iv0 = 1:length(v0); -ivT = 1:length(vT); -iv1 = 1:length(v1); -iv = 1:length(vv); - -% Initialize the vector of residuals. -res = zeros(periods*ny, 1); +% Center the endogenous and exogenous variables around the deterministic steady state. +endogenousvariables = bsxfun(@minus, endogenousvariables, steadystate_y); +exogenousvariables = bsxfun(@minus, exogenousvariables, transpose(steadystate_x)); -% Initialize the sparse Jacobian. -iA = zeros(periods*M_.NNZDerivatives(1), 3); +if M_.maximum_lag > 0 + y0 = endogenousvariables(:, maximum_lag); +else + y0 = NaN(M_.endo_nbr, 1); +end +if M_.maximum_lead > 0 + yT = endogenousvariables(:, maximum_lag+periods+1); +else + yT = NaN(M_.endo_nbr, 1); +end +Y = vec(endogenousvariables(:,maximum_lag+(1:periods))); h2 = clock; -i_rows = (1:ny)'; -i_cols_A = ipcn; -i_cols = ipcn+(maximum_lag-1)*ny; -m = 0; -for it = (maximum_lag+1):(maximum_lag+periods) - if periods==1 && isequal(it, maximum_lag+1) - nv = length(v0); - iA(iv0+m,:) = [i_rows(r0),ic(c0),v0]; - elseif isequal(it, maximum_lag+periods) - nv = length(vT); - iA(ivT+m,:) = [i_rows(rT), i_cols_A(jpc(cT)), vT]; - elseif isequal(it, maximum_lag+1) - nv = length(v1); - iA(iv1+m,:) = [i_rows(r1), icn(c1), v1]; - else - nv = length(vv); - iA(iv+m,:) = [i_rows(rr),i_cols_A(cc),vv]; - end - z(jendo) = Y(i_cols); - z(jexog) = transpose(exogenousvariables(it,:)); - res(i_rows) = jacobian*z; - m = m + nv; - i_rows = i_rows + ny; - i_cols = i_cols + ny; - if it > maximum_lag+1 - i_cols_A = i_cols_A + ny; - end -end + +[res, A] = linear_perfect_foresight_problem(Y, jacobian, y0, yT, exogenousvariables, params, steadystate_y, maximum_lag, periods, ny); % Evaluation of the maximum residual at the initial guess (steady state for the endogenous variables). err = max(abs(res)); @@ -201,12 +139,9 @@ if options_.debug skipline() end -iA = iA(1:m,:); -A = sparse(iA(:,1), iA(:,2), iA(:,3), periods*ny, periods*ny); - % Try to update the vector of endogenous variables. try - Y(i_upd) = Y(i_upd) - A\res; + Y = Y - A\res; catch % Normally, because the model is linear, the solution of the perfect foresight model should % be obtained in one Newton step. This is not the case if the model is singular. @@ -219,15 +154,13 @@ catch return end -i_cols = ipcn+(maximum_lag-1)*ny; +YY = reshape([y0; Y; yT], ny, periods+2); + i_rows = (1:ny)'; -for it = (maximum_lag+1):(maximum_lag+periods) - z(jendo) = Y(i_cols); - z(jexog) = transpose(exogenousvariables(it,:)); - m = m + nv; +for t = 1:periods + z = [ vec(YY(:,t+(0:2))); transpose(exogenousvariables(t+maximum_lag, :))]; res(i_rows) = jacobian*z; i_rows = i_rows + ny; - i_cols = i_cols + ny; end ERR = max(abs(res)); @@ -239,7 +172,6 @@ end if any(isnan(res)) || any(isinf(res)) || any(isnan(Y)) || any(isinf(Y)) || ~isreal(res) || ~isreal(Y) success = false; % NaN or Inf occurred - endogenousvariables = reshape(Y, ny, periods+maximum_lag+M_.maximum_lead); if verbose skipline() if ~isreal(res) || ~isreal(Y) @@ -251,9 +183,11 @@ if any(isnan(res)) || any(isinf(res)) || any(isnan(Y)) || any(isinf(Y)) || ~isre end else success = true; % Convergency obtained. - endogenousvariables = bsxfun(@plus, reshape(Y, ny, periods+maximum_lag+M_.maximum_lead), steadystate_y); end +endogenousvariables(:,maximum_lag+(1:periods)) = reshape(Y, ny, periods); +endogenousvariables = bsxfun(@plus, endogenousvariables, steadystate_y); + if verbose skipline(); end diff --git a/tests/deterministic_simulations/linear_approximation/sw.mod b/tests/deterministic_simulations/linear_approximation/sw.mod index 949d427267a11f585f9621878ffaa10869e4d1ff..a4767a8b00d611138789add269ad1ed0b2411f01 100644 --- a/tests/deterministic_simulations/linear_approximation/sw.mod +++ b/tests/deterministic_simulations/linear_approximation/sw.mod @@ -133,3 +133,15 @@ end if max(abs(endo_simul_0(:)-endo_simul_1(:)))>.01*options_.dynatol.f error('Something is wrong!') end + +// Test stack_solve_algo=0+linear_approximation, which uses a different codepath than stack_solve_algo=7 +perfect_foresight_setup(periods=300); +perfect_foresight_solver(linear_approximation, stack_solve_algo=0); +endo_simul_2 = oo_.endo_simul; +if ~oo_.deterministic_simulation.status + error('Perfect foresight simulation failed') +end + +if max(abs(endo_simul_0(:)-endo_simul_2(:)))>.01*options_.dynatol.f + error('Something is wrong!') +end