diff --git a/doc/manual/source/the-model-file.rst b/doc/manual/source/the-model-file.rst index 7b1a62eba4771cfd949b6cc4cc26a8d952f0bd36..8b001673b6c4c76c6f0902591c3a7eea85baab52 100644 --- a/doc/manual/source/the-model-file.rst +++ b/doc/manual/source/the-model-file.rst @@ -4668,9 +4668,9 @@ that have been left free. The ``perfect_foresight_controlled_paths`` block requires that the :opt:`stack_solve_algo <stack_solve_algo = INTEGER>` option be equal to - either ``0``, ``1``, ``2``, ``3`` or ``6``, and is incompatible with the - :opt:`block`, :opt:`linear` and :opt:`bytecode` options of the :bck:`model` - block. + either ``0``, ``1``, ``2``, ``3``, ``6`` or ``7``, and is incompatible with + the :opt:`block`, :opt:`linear` and :opt:`bytecode` options of the + :bck:`model` block. *Options* diff --git a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m index c7e376f29fdfa334efb4c6812453a09a1e60bdb8..c1977137cc03c5b745a6058cff2537351d634c9f 100644 --- a/matlab/perfect-foresight-models/perfect_foresight_solver_core.m +++ b/matlab/perfect-foresight-models/perfect_foresight_solver_core.m @@ -78,8 +78,11 @@ end if ~isempty(controlled_paths_by_period) assert(nargout >= 6); % Ensure modified exos are used - if ~ismember(options_.stack_solve_algo, [0 1 2 3 6]) - error('perfect_foresight_controlled_paths is only available with stack_solve_algo option equal to 0, 1, 2, 3 or 6') + if ~ismember(options_.stack_solve_algo, [0 1 2 3 6 7]) + error('perfect_foresight_controlled_paths is only available with stack_solve_algo option equal to 0, 1, 2, 3, 6 or 7') + end + if options_.stack_solve_algo == 7 && ismember(options_.solve_algo, [10, 11]) + error('perfect_foresight_controlled_paths is not available for mixed-complementarity problems (LMMCP or PATH solvers)') end if options_.bytecode error('perfect_foresight_controlled_paths is not available with the bytecode option') @@ -157,7 +160,7 @@ else end [y, success] = solve_stacked_linear_problem(y, exo_simul, steady_state, exo_steady_state, M_, options_); else - [y, success, maxerror] = solve_stacked_problem(y, exo_simul, steady_state, M_, options_); + [y, success, maxerror, exo_simul] = solve_stacked_problem(y, exo_simul, steady_state, controlled_paths_by_period, M_, options_); end otherwise error('Invalid value of stack_solve_algo option!') diff --git a/matlab/perfect-foresight-models/solve_stacked_problem.m b/matlab/perfect-foresight-models/solve_stacked_problem.m index 61a7b3294136de34150b71205749cdee62da3974..841b7c1ef72adbe387835905e2d9f15c781556d5 100644 --- a/matlab/perfect-foresight-models/solve_stacked_problem.m +++ b/matlab/perfect-foresight-models/solve_stacked_problem.m @@ -1,20 +1,23 @@ -function [endogenousvariables, success, maxerror] = solve_stacked_problem(endogenousvariables, exogenousvariables, steadystate, M_, options_) +function [endogenousvariables, success, maxerror, exogenousvariables] = solve_stacked_problem(endogenousvariables, exogenousvariables, steadystate, controlled_paths_by_period, M_, options_) % [endogenousvariables, success, maxerror] = solve_stacked_problem(endogenousvariables, exogenousvariables, steadystate, M_, options_) % Solves the perfect foresight model using dynare_solve % % INPUTS -% - endogenousvariables [double] N*T array, paths for the endogenous variables (initial guess). -% - exogenousvariables [double] T*M array, paths for the exogenous variables. +% - endogenousvariables [double] N*(T+M_.maximum_lag+M_.maximum_lead) array, paths for the endogenous variables (initial guess). +% - exogenousvariables [double] (T+M_.maximum_lag+M_.maximum_lead)*M array, paths for the exogenous variables. % - steadystate [double] N*1 array, steady state for the endogenous variables. +% - controlled_paths_by_period [struct] data from perfect_foresight_controlled_paths block % - M_ [struct] contains a description of the model. % - options_ [struct] contains various options. % % OUTPUTS -% - endogenousvariables [double] N*T array, paths for the endogenous variables (solution of the perfect foresight model). +% - endogenousvariables [double] N*(T+M_.maximum_lag+M_.maximum_lead) array, paths for the endogenous variables (solution of the perfect foresight model). % - success [logical] Whether a solution was found % - maxerror [double] 1-norm of the residual +% - exogenousvariables [double] (T+M_.maximum_lag+M_.maximum_lead)*M array, paths for the exogenous variables +% (may be modified if perfect_foresight_controlled_paths present) -% Copyright © 2015-2024 Dynare Team +% Copyright © 2015-2025 Dynare Team % % This file is part of Dynare. % @@ -46,6 +49,7 @@ end z = endogenousvariables(:,M_.maximum_lag+(1:periods)); if (options_.solve_algo == 10 || options_.solve_algo == 11)% mixed complementarity problem + assert(isempty(controlled_paths_by_period)) [lb, ub] = feval(sprintf('%s.dynamic_complementarity_conditions', M_.fname), M_.params); if options_.linear_approximation lb = lb - steadystate_y; @@ -70,10 +74,28 @@ if (options_.solve_algo == 10 || options_.solve_algo == 11)% mixed complementari M_.dynamic_mcp_equations_reordering); eq_to_ignore=find(isfinite(lb) | isfinite(ub)); -else +elseif isempty(controlled_paths_by_period) [y, check, res, ~, errorcode] = dynare_solve(@perfect_foresight_problem, z(:), ... options_.simul.maxit, options_.dynatol.f, options_.dynatol.x, ... options_, y0, yT, exogenousvariables, M_.params, steadystate, periods, M_, options_); +else + for p = 1:periods + if isempty(controlled_paths_by_period(p).exogenize_id) + continue + end + z(controlled_paths_by_period(p).exogenize_id,p) = exogenousvariables(p+M_.maximum_lag,controlled_paths_by_period(p).endogenize_id); + end + + % call the following in a wrapper, that is then passed to dynare_solve + % A = controlled_paths_substitute_stacked_jacobian(A, y, y0, yT, exogenousvariables, steadystate, controlled_paths_by_period, M_); + + for p = 1:periods + if isempty(controlled_paths_by_period(p).exogenize_id) + continue + end + exogenousvariables(p+M_.maximum_lag,controlled_paths_by_period(p).endogenize_id) = y(controlled_paths_by_period(p).exogenize_id+p*M_.endo_nbr); + y(controlled_paths_by_period(p).exogenize_id+p*M_.endo_nbr) = controlled_paths_by_period(p).values; + end end if all(imag(y)<.1*options_.dynatol.x) diff --git a/meson.build b/meson.build index 05a4f6b6af075b92a5a7652748d509c29d05d3ce..f52e708e87abb9d09f6ae8355d7e5c209555eb49 100644 --- a/meson.build +++ b/meson.build @@ -1627,6 +1627,7 @@ mod_and_m_tests = [ 'deprecated/ramst.mod' ] }, { 'test' : [ 'deterministic_simulations/ramst_pf_controlled_paths.mod', 'deterministic_simulations/ramst_pf_controlled_paths_lbj.mod', + 'deterministic_simulations/ramst_pf_controlled_paths_ssa7.mod', 'deterministic_simulations/ramst_pf_controlled_paths_check.mod' ], 'extra' : [ 'deterministic_simulations/ramst_pf_controlled_paths_common.inc'] }, { 'test' : [ 'deterministic_simulations/ramst_pfwee_controlled_paths.mod' ], diff --git a/tests/deterministic_simulations/ramst_pf_controlled_paths_check.mod b/tests/deterministic_simulations/ramst_pf_controlled_paths_check.mod index b370f6001d46f05df98ad52dc16b1320ed9e0a48..393e398c6fb2b90e794caabe351028f2a90faef4 100644 --- a/tests/deterministic_simulations/ramst_pf_controlled_paths_check.mod +++ b/tests/deterministic_simulations/ramst_pf_controlled_paths_check.mod @@ -1,4 +1,4 @@ -/* Checks that exogenous computed by ramst_pf_controlled_paths{,lbj}.mod actually give back the +/* Checks that exogenous computed by ramst_pf_controlled_paths{,lbj,ssa7}.mod actually give back the expected endogenous variables */ @#define shocks = false @@ -33,3 +33,18 @@ perfect_foresight_solver; if max(max(abs(oo_.endo_simul - S1.oo_.endo_simul))) > options_.dynatol.x error('perfect_foresight_controlled_paths gives wrong result with stack_solve_algo=1') end + + +// stack_solve_algo=7 + +S7 = load('ramst_pf_controlled_paths_ssa7/Output/ramst_pf_controlled_paths_ssa7_results.mat'); + +perfect_foresight_setup(periods=30); + +oo_.exo_simul = S7.oo_.exo_simul; + +perfect_foresight_solver; + +if max(max(abs(oo_.endo_simul - S7.oo_.endo_simul))) > options_.dynatol.x + error('perfect_foresight_controlled_paths gives wrong result with stack_solve_algo=7') +end diff --git a/tests/deterministic_simulations/ramst_pf_controlled_paths_ssa7.mod b/tests/deterministic_simulations/ramst_pf_controlled_paths_ssa7.mod new file mode 100644 index 0000000000000000000000000000000000000000..2fe4958a9d97373c45cc1856b947706e19e2423e --- /dev/null +++ b/tests/deterministic_simulations/ramst_pf_controlled_paths_ssa7.mod @@ -0,0 +1,17 @@ +// Performs a simulation with a perfect_foresight_controlled_paths block +// with the stack_solve_algo=7 + +@#define shocks = true +@#include "ramst_pf_controlled_paths_common.inc" + +perfect_foresight_setup(periods=30, first_simulation_period = 2001Y); +perfect_foresight_solver(stack_solve_algo = 7); + +if ~oo_.deterministic_simulation.status + error('Perfect foresight simulation failed') +end + +if oo_.endo_simul(1, 3) ~= 1.6 || any(oo_.endo_simul(1, 5:6) ~= 1.7) || any(oo_.endo_simul(2, 8:10) ~= 13) ... + || any(oo_.endo_simul(3, 4:6) ~= 0.5) || oo_.exo_simul(2, 1) ~= 1.2 + error('Perfect foresight with controlled paths failed') +end