From 8488674ce4d2fb2ec7c05232894490274565811a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= Date: Thu, 21 Apr 2022 17:09:27 +0200 Subject: [PATCH] =?UTF-8?q?New=20shocks(learnt=5Fin=3D=E2=80=A6)=20and=20e?= =?UTF-8?q?ndval(learnt=5Fin=3D=E2=80=A6)=20blocks?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For use with perfect_foresight_with_expectation_errors_setup. --- ..._foresight_with_expectation_errors_setup.m | 117 ++++++++++---- ...foresight_with_expectation_errors_solver.m | 17 +- preprocessor | 2 +- tests/Makefile.am | 1 + tests/deterministic_simulations/pfwee.mod | 3 +- .../pfwee_learnt_in.mod | 149 ++++++++++++++++++ 6 files changed, 247 insertions(+), 42 deletions(-) create mode 100644 tests/deterministic_simulations/pfwee_learnt_in.mod diff --git a/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_setup.m b/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_setup.m index 6724545c6..9871fae48 100644 --- a/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_setup.m +++ b/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_setup.m @@ -17,11 +17,7 @@ function perfect_foresight_with_expectation_errors_setup % You should have received a copy of the GNU General Public License % along with Dynare. If not, see . -global M_ oo_ options_ ys0_ - -if ~isempty(ys0_) - error('perfect_foresight_with_expectation_errors_setup: cannot be used in conjunction with endval') -end +global M_ oo_ options_ ys0_ ex0_ if ~isempty(M_.endo_histval) error('perfect_foresight_with_expectation_errors_setup: cannot be used in conjunction with histval') @@ -32,37 +28,90 @@ end periods = options_.periods; -%% Read CSV file -if ~exist(options_.datafile, 'file') - error(['perfect_foresight_with_expectation_errors_setup: cannot find ' options_.datafile ]) -end -%% We can’t use readcell (only in MATLAB ≥ R2019a), so instead rely on csvread and manual hacks -% Read numeric data, skipping first row and first column -raw_csv = csvread(options_.datafile, 1, 1); -if size(raw_csv, 1)-2 ~= periods - error(['perfect_foresight_with_expectation_errors_setup: the number of rows in ' options_.datafile ' does not match the periods setting']) -end -% Read first line (exogenous variable names) -fid = fopen(options_.datafile); -csv_first_line = fgetl(fid); -fclose(fid); -exo_header_names = strsplit(csv_first_line, ','); -exo_header_names = exo_header_names(2:end); % Remove first column -if numel(exo_header_names) ~= size(raw_csv, 2) - error(['perfect_foresight_with_expectation_errors_setup: first line malformed in ' options_.datafile]) -end - -%% Create and fill structures containing information sets +%% Initialize informational structures oo_.pfwee.terminal_info = NaN(M_.exo_nbr, periods); % 2nd dimension is informational time oo_.pfwee.shocks_info = NaN(M_.exo_nbr, periods, periods); % 2nd dimension is real time, 3rd dimension is informational time -for i = 1:size(raw_csv, 2) - exo_id = strmatch(exo_header_names{i}, M_.exo_names, 'exact'); - period_id = raw_csv(1, i); - % Ignore irrelevant periods when copying shocks information - oo_.pfwee.shocks_info(exo_id, period_id:end, period_id) = raw_csv(1+period_id:end-1, i); - oo_.pfwee.terminal_info(exo_id, period_id) = raw_csv(end, i); + +if exist(options_.datafile, 'file') + if ~isempty(M_.det_shocks) || ~isempty(M_.learnt_shocks) || ~isempty(ys0_) || ~isempty(M_.learnt_endval) + warning('perfect_foresight_with_expectation_errors_setup: since you passed the datafile option, the contents of shocks and endval blocks will be ignored') + end + %% Read CSV file + %% We can’t use readcell (only in MATLAB ≥ R2019a), so instead rely on csvread and manual hacks + % Read numeric data, skipping first row and first column + raw_csv = csvread(options_.datafile, 1, 1); + if size(raw_csv, 1)-2 ~= periods + error(['perfect_foresight_with_expectation_errors_setup: the number of rows in ' options_.datafile ' does not match the periods setting']) + end + % Read first line (exogenous variable names) + fid = fopen(options_.datafile); + csv_first_line = fgetl(fid); + fclose(fid); + exo_header_names = strsplit(csv_first_line, ','); + exo_header_names = exo_header_names(2:end); % Remove first column + if numel(exo_header_names) ~= size(raw_csv, 2) + error(['perfect_foresight_with_expectation_errors_setup: first line malformed in ' options_.datafile]) + end + + %% Create and fill structures containing information sets + for i = 1:size(raw_csv, 2) + exo_id = strmatch(exo_header_names{i}, M_.exo_names, 'exact'); + period_id = raw_csv(1, i); + % Ignore irrelevant periods when copying shocks information + oo_.pfwee.shocks_info(exo_id, period_id:end, period_id) = raw_csv(1+period_id:end-1, i); + oo_.pfwee.terminal_info(exo_id, period_id) = raw_csv(end, i); + end +else + %% No datafile option given, use the contents of shocks and endval blocks + if isempty(M_.learnt_shocks) && isempty(M_.learnt_endval) + warning('perfect_foresight_with_expectation_errors_setup: there is no shocks(learnt_in=...) or endval(learnt_in=...) block, and you did not pass the datafile option, so there is no point in using this command') + end + + %% Initialize information set at period 1 using “bare” shocks and endval blocks (or initval if there is no endval) + oo_.pfwee.terminal_info(:, 1) = oo_.exo_steady_state; + oo_.pfwee.shocks_info(:, :, 1) = oo_.exo_steady_state; + for i = 1:length(M_.det_shocks) + prds = M_.det_shocks(i).periods; + exo_id = M_.det_shocks(i).exo_id; + v = M_.det_shocks(i).value; + if ~M_.det_shocks(i).exo_det + if ~M_.det_shocks(i).multiplicative + oo_.pfwee.shocks_info(exo_id, prds, 1) = v; + else + oo_.pfwee.shocks_info(exo_id, prds, 1) = oo_.pfwee.shocks_info(exo_id, prds, 1) .* v; + end + end + end + + %% Construct information sets for subsequent informational periods + for p = 2:periods + oo_.pfwee.terminal_info(:, p) = oo_.pfwee.terminal_info(:, p-1); + if ~isempty(M_.learnt_endval) + idx = find([M_.learnt_endval.learnt_in] == p); + for i = 1:length(idx) + j = idx(i); + oo_.pfwee.terminal_info(M_.learnt_endval(j).exo_id, p) = M_.learnt_endval(j).value; + end + end + oo_.pfwee.shocks_info(:, :, p) = oo_.pfwee.shocks_info(:, :, p-1); + if ~isempty(M_.learnt_shocks) + idx = find([M_.learnt_shocks.learnt_in] == p); + for i = 1:length(idx) + j = idx(i); + oo_.pfwee.shocks_info(M_.learnt_shocks(j).exo_id, M_.learnt_shocks(j).periods, p) = M_.learnt_shocks(j).value; + end + end + end end % Build initial paths for endos and exos (only initial conditions are set, the rest is NaN) -oo_.endo_simul = [repmat(oo_.steady_state, 1, M_.maximum_lag) NaN(M_.endo_nbr, periods+M_.maximum_lead)]; -oo_.exo_simul = [repmat(oo_.exo_steady_state',M_.maximum_lag,1); NaN(periods+M_.maximum_lead,M_.exo_nbr)]; +if isempty(ys0_) + oo_.endo_simul = [repmat(oo_.steady_state, 1, M_.maximum_lag) NaN(M_.endo_nbr, periods+M_.maximum_lead)]; +else + oo_.endo_simul = [repmat(ys0_, 1, M_.maximum_lag) NaN(M_.endo_nbr, periods+M_.maximum_lead)]; +end +if isempty(ex0_) + oo_.exo_simul = [repmat(oo_.exo_steady_state',M_.maximum_lag,1); NaN(periods+M_.maximum_lead,M_.exo_nbr)]; +else + oo_.exo_simul = [repmat(ex0_',M_.maximum_lag,1); NaN(periods+M_.maximum_lead,M_.exo_nbr)]; +end diff --git a/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_solver.m b/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_solver.m index acb98c154..8deee7efb 100644 --- a/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_solver.m +++ b/matlab/perfect-foresight-models/perfect_foresight_with_expectation_errors_solver.m @@ -17,11 +17,11 @@ function perfect_foresight_with_expectation_errors_solver % You should have received a copy of the GNU General Public License % along with Dynare. If not, see . -global M_ oo_ options_ +global M_ oo_ options_ ys0_ -% Save initial steady state, for restoring it at the end -initial_steady_state = oo_.steady_state; -initial_exo_steady_state = oo_.exo_steady_state; +% Save original steady state, for restoring it at the end +orig_steady_state = oo_.steady_state; +orig_exo_steady_state = oo_.exo_steady_state; % Same for periods (it will be modified before calling perfect_foresight_solver if constants_simulation_length option is false) periods = options_.periods; @@ -34,6 +34,11 @@ exo_simul = oo_.exo_simul; % Start main loop around informational periods info_period = 1; increment = 0; +if isempty(ys0_) + initial_steady_state = oo_.steady_state; +else + initial_steady_state = ys0_; +end while info_period <= periods % Compute terminal steady state as anticipated oo_.exo_steady_state = oo_.pfwee.terminal_info(:, info_period); @@ -88,6 +93,6 @@ oo_.endo_simul = endo_simul; oo_.exo_simul = exo_simul; % Restore some values -oo_.steady_state = initial_steady_state; -oo_.exo_steady_state = initial_exo_steady_state; +oo_.steady_state = orig_steady_state; +oo_.exo_steady_state = orig_exo_steady_state; options_.periods = periods; diff --git a/preprocessor b/preprocessor index 54ca5d9cc..b5a4df160 160000 --- a/preprocessor +++ b/preprocessor @@ -1 +1 @@ -Subproject commit 54ca5d9cc08f6f2a3bec9ff57a3808f988e9b397 +Subproject commit b5a4df16088d9d3c1f77db0aaa5bed4f4ee32354 diff --git a/tests/Makefile.am b/tests/Makefile.am index 21bfa3c5b..864b0f9fd 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -390,6 +390,7 @@ MODFILES = \ deterministic_simulations/rbc_det_stack_solve_algo_7_exo_lead.mod \ deterministic_simulations/pfwee.mod \ deterministic_simulations/pfwee_constant_sim_length.mod \ + deterministic_simulations/pfwee_learnt_in.mod \ lmmcp/rbc.mod \ lmmcp/sw_lmmcp.mod \ lmmcp/sw_newton.mod \ diff --git a/tests/deterministic_simulations/pfwee.mod b/tests/deterministic_simulations/pfwee.mod index dba0cc907..adfe55079 100644 --- a/tests/deterministic_simulations/pfwee.mod +++ b/tests/deterministic_simulations/pfwee.mod @@ -1,4 +1,5 @@ -// Tests perfect_foresight_with_expectation_errors_{setup,solver} +/* Tests perfect_foresight_with_expectation_errors_{setup,solver} + using a CSV datafile */ var c k; varexo x; diff --git a/tests/deterministic_simulations/pfwee_learnt_in.mod b/tests/deterministic_simulations/pfwee_learnt_in.mod new file mode 100644 index 000000000..e37a7ec7e --- /dev/null +++ b/tests/deterministic_simulations/pfwee_learnt_in.mod @@ -0,0 +1,149 @@ +/* Tests perfect_foresight_with_expectation_errors_{setup,solver} + using the shocks(learnt_in=…) and endval(learnt_in=…) syntax */ + +var c k; +varexo x; + +parameters alph gam delt bet aa; +alph=0.5; +gam=0.5; +delt=0.02; +bet=0.05; +aa=0.5; + + +model; +c + k - aa*x*k(-1)^alph - (1-delt)*k(-1); +c^(-gam) - (1+bet)^(-1)*(aa*alph*x(+1)*k^(alph-1) + 1 - delt)*c(+1)^(-gam); +end; + +initval; +x = 1; +k = ((delt+bet)/(1.0*aa*alph))^(1/(alph-1)); +c = aa*k^alph-delt*k; +end; + +steady; + +check; + +// Describe the same scenario as in pfwee.csv, but using the Dynare syntax + +shocks; + var x; + periods 1; + values 1.2; +end; + +shocks(learnt_in = 2); + var x; + periods 2; + values 1.3; +end; + +endval(learnt_in = 2); + x = 1.1; +end; + +shocks(learnt_in = 3); + var x; + periods 3; + values 1.4; +end; + +endval(learnt_in = 3); + x = 1.2; +end; + +// Dummy block, that will be overwritten by the next one +shocks(learnt_in = 6); + var x; + periods 6:8; + values 10; +end; + +shocks(learnt_in = 6, overwrite); + var x; + periods 6:7; + values 1.1; +end; + +endval(learnt_in = 6); + x = 1.1; +end; + +perfect_foresight_with_expectation_errors_setup(periods = 7); + +// First simulation with default options +perfect_foresight_with_expectation_errors_solver; +pfwee1 = oo_.endo_simul; + +// Second simulation with alternative guess values +perfect_foresight_with_expectation_errors_solver(terminal_steady_state_as_guess_value); +pfwee2 = oo_.endo_simul; + +// Now compute the solution by hand to verify the results + +perfect_foresight_setup; + +// Information arriving in period 1 (temp shock now) +oo_.exo_simul(2,1) = 1.2; +perfect_foresight_solver; + +// Information arriving in period 2 (temp shock now + permanent shock in future) +oo_.exo_simul(3,1) = 1.3; +oo_.exo_steady_state = 1.1; +oo_.exo_simul(end, 1) = oo_.exo_steady_state; +oo_.steady_state = evaluate_steady_state(oo_.steady_state, M_, options_, oo_, true); +oo_.endo_simul(:, end) = oo_.steady_state; +periods 6; +saved_endo = oo_.endo_simul(:, 1); +saved_exo = oo_.exo_simul(1, :); +oo_.endo_simul = oo_.endo_simul(:, 2:end); +oo_.exo_simul = oo_.exo_simul(2:end, :); +perfect_foresight_solver; +oo_.endo_simul = [ saved_endo oo_.endo_simul ]; +oo_.exo_simul = [ saved_exo; oo_.exo_simul ]; + +// Information arriving in period 3 (temp shock now + permanent shock in future) +oo_.exo_simul(4,1) = 1.4; +oo_.exo_steady_state = 1.2; +oo_.exo_simul(end, 1) = oo_.exo_steady_state; +oo_.steady_state = evaluate_steady_state(oo_.steady_state, M_, options_, oo_, true); +oo_.endo_simul(:, end) = oo_.steady_state; +periods 5; +saved_endo = oo_.endo_simul(:, 1:2); +saved_exo = oo_.exo_simul(1:2, :); +oo_.endo_simul = oo_.endo_simul(:, 3:end); +oo_.exo_simul = oo_.exo_simul(3:end, :); +perfect_foresight_solver; +oo_.endo_simul = [ saved_endo oo_.endo_simul ]; +oo_.exo_simul = [ saved_exo; oo_.exo_simul ]; + +// Information arriving in period 6 (permanent shock arriving now) +oo_.exo_simul(7,1) = 1.1; +oo_.exo_simul(8,1) = 1.1; +oo_.exo_steady_state = 1.1; +oo_.exo_simul(end, 1) = oo_.exo_steady_state; +oo_.steady_state = evaluate_steady_state(oo_.steady_state, M_, options_, oo_, true); +oo_.endo_simul(:, end) = oo_.steady_state; +periods 2; +saved_endo = oo_.endo_simul(:, 1:5); +saved_exo = oo_.exo_simul(1:5, :); +oo_.endo_simul = oo_.endo_simul(:, 6:end); +oo_.exo_simul = oo_.exo_simul(6:end, :); +perfect_foresight_solver; +oo_.endo_simul = [ saved_endo oo_.endo_simul ]; +oo_.exo_simul = [ saved_exo; oo_.exo_simul ]; + +% We should have strict equality with first pfwee simulation, because algorithm +% and guess values are exactly the same. +if any(any(pfwee1-oo_.endo_simul ~= 0)) + error('Error in perfect_foresight_with_expectation_errors') +end + +% For the 2nd simulation, since the guess values are different, there are some +% numerical differences +if max(max(abs(pfwee2-oo_.endo_simul))) > 10*options_.dynatol.f + error('Error in perfect_foresight_with_expectation_errors + terminal_steady_state_as_guess_value') +end