diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc index 22b33b213ad9fe9e04f18ebdba841ebef9af3b7f..3ec9743bcd764984f363bdd173105e31b861ea0a 100644 --- a/src/ComputingTasks.cc +++ b/src/ComputingTasks.cc @@ -267,7 +267,7 @@ PerfectForesightWithExpectationErrorsSolverStatement::PerfectForesightWithExpect void PerfectForesightWithExpectationErrorsSolverStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) { - mod_file_struct.perfect_foresight_solver_present = true; + mod_file_struct.perfect_foresight_with_expectation_errors_solver_present = true; } void diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 687a85b9b998ea000f4a4b39d5318735e1b7b020..161b74b60bf2ddf58c0401e5db0bdcc489f98b12 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -186,7 +186,7 @@ class ParsingDriver; %token NO_IDENTIFICATION_MINIMAL NO_IDENTIFICATION_SPECTRUM NORMALIZE_JACOBIANS GRID_NBR %token TOL_RANK TOL_DERIV TOL_SV CHECKS_VIA_SUBSETS MAX_DIM_SUBSETS_GROUPS ZERO_MOMENTS_TOLERANCE %token MAX_NROWS SQUEEZE_SHOCK_DECOMPOSITION WITH_EPILOGUE MODEL_REMOVE MODEL_REPLACE MODEL_OPTIONS -%token VAR_REMOVE ESTIMATED_PARAMS_REMOVE STATIC INCIDENCE RESID NON_ZERO +%token VAR_REMOVE ESTIMATED_PARAMS_REMOVE STATIC INCIDENCE RESID NON_ZERO LEARNT_IN %token <vector<string>> SYMBOL_VEC @@ -757,6 +757,8 @@ endval : ENDVAL ';' initval_list END ';' { driver.end_endval(false); } | ENDVAL '(' ALL_VALUES_REQUIRED ')' ';' initval_list END ';' { driver.end_endval(true); } + | ENDVAL '(' LEARNT_IN EQUAL INT_NUMBER ')' ';' initval_list END ';' + { driver.end_endval_learnt_in($5); } ; initval_list : initval_list initval_elem @@ -1126,9 +1128,12 @@ tag_pair_list_for_selection : QUOTED_STRING shocks : SHOCKS ';' shock_list END ';' { driver.end_shocks(false); } | SHOCKS '(' OVERWRITE ')' ';' shock_list END ';' { driver.end_shocks(true); } | SHOCKS '(' OVERWRITE ')' ';' END ';' { driver.end_shocks(true); } - | SHOCKS '(' SURPRISE ')' ';' surprise_shock_list END ';' { driver.end_shocks_surprise(false); } - | SHOCKS '(' SURPRISE COMMA OVERWRITE ')' ';' surprise_shock_list END ';' { driver.end_shocks_surprise(true); } - | SHOCKS '(' OVERWRITE COMMA SURPRISE ')' ';' surprise_shock_list END ';' { driver.end_shocks_surprise(true); } + | SHOCKS '(' SURPRISE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(false); } + | SHOCKS '(' SURPRISE COMMA OVERWRITE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(true); } + | SHOCKS '(' OVERWRITE COMMA SURPRISE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(true); } + | SHOCKS '(' LEARNT_IN EQUAL INT_NUMBER ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, false); } + | SHOCKS '(' LEARNT_IN EQUAL INT_NUMBER COMMA OVERWRITE ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, true); } + | SHOCKS '(' OVERWRITE COMMA LEARNT_IN EQUAL INT_NUMBER ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($7, true); } ; shock_list : shock_list shock_elem @@ -1150,9 +1155,9 @@ det_shock_elem : VAR symbol ';' PERIODS period_list ';' VALUES value_list ';' { driver.add_det_shock($2, $5, $8, false); } ; -surprise_shock_list : surprise_shock_list det_shock_elem - | det_shock_elem - ; +det_shock_list : det_shock_list det_shock_elem + | det_shock_elem + ; heteroskedastic_shocks : HETEROSKEDASTIC_SHOCKS ';' heteroskedastic_shock_list END ';' { driver.end_heteroskedastic_shocks(false); } diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll index 8c9e15a651bc0662c663a32a3317f045c3cf8c02..40dc09bfd77c4730718f1b62d5351760bf77c3fb 100644 --- a/src/DynareFlex.ll +++ b/src/DynareFlex.ll @@ -888,6 +888,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]) <DYNARE_BLOCK>lag {return token::LAG;} <DYNARE_BLOCK>coeff {return token::COEFF;} <DYNARE_BLOCK>overwrite {return token::OVERWRITE;} +<DYNARE_BLOCK>learnt_in {return token::LEARNT_IN;} <DYNARE_STATEMENT,DYNARE_BLOCK>upper_cholesky {return token::UPPER_CHOLESKY;} <DYNARE_STATEMENT,DYNARE_BLOCK>lower_cholesky {return token::LOWER_CHOLESKY;} <DYNARE_STATEMENT>chain {return token::CHAIN;} diff --git a/src/ModFile.cc b/src/ModFile.cc index c16a5ab22b007798bbdec72e70842b8a06b10d87..decf7921076ad6d7d6abc2460c53dd499647bbf5 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -148,6 +148,7 @@ ModFile::checkPass(bool nostrict, bool stochastic) if (dynamic_model.equation_number() == 0 && (mod_file_struct.check_present || mod_file_struct.perfect_foresight_solver_present + || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present || stochastic_statement_present)) { cerr << "ERROR: At least one model equation must be declared!" << endl; @@ -184,9 +185,10 @@ ModFile::checkPass(bool nostrict, bool stochastic) exit(EXIT_FAILURE); } - if (mod_file_struct.perfect_foresight_solver_present && stochastic_statement_present) + if ((mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present) + && stochastic_statement_present) { - cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver,simul} and one of {stoch_simul, estimation, osr, ramsey_policy, discretionary_policy}. This is not possible: one cannot mix perfect foresight context with stochastic context in the same file." << endl; + cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver, simul, perfect_foresight_with_expectation_errors_solver} and one of {stoch_simul, estimation, osr, ramsey_policy, discretionary_policy}. This is not possible: one cannot mix perfect foresight context with stochastic context in the same file." << endl; exit(EXIT_FAILURE); } @@ -308,6 +310,7 @@ ModFile::checkPass(bool nostrict, bool stochastic) if (linear && !mod_file_struct.perfect_foresight_solver_present + && !mod_file_struct.perfect_foresight_with_expectation_errors_solver_present && (dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::sign) || dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::abs) || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::max) @@ -576,9 +579,10 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool exit(EXIT_FAILURE); } - if (symbol_table.exo_det_nbr() > 0 && mod_file_struct.perfect_foresight_solver_present) + if (symbol_table.exo_det_nbr() > 0 + && (mod_file_struct.perfect_foresight_solver_present || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present)) { - cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver, simul} and varexo_det declaration (all exogenous variables are deterministic in this case)" << endl; + cerr << "ERROR: A .mod file cannot contain both one of {perfect_foresight_solver, simul, perfect_foresight_with_expectation_errors_solver} and varexo_det declaration (all exogenous variables are deterministic in this case)" << endl; exit(EXIT_FAILURE); } @@ -610,6 +614,18 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool exit(EXIT_FAILURE); } + if (mod_file_struct.shocks_learnt_in_present && !mod_file_struct.perfect_foresight_with_expectation_errors_solver_present) + { + cerr << "ERROR: the 'shocks(learnt_in=…)' block can only be used in conjunction with the 'perfect_foresight_with_expectation_errors_solver' command." << endl; + exit(EXIT_FAILURE); + } + + if (mod_file_struct.endval_learnt_in_present && !mod_file_struct.perfect_foresight_with_expectation_errors_solver_present) + { + cerr << "ERROR: the 'endval(learnt_in=…)' block can only be used in conjunction with the 'perfect_foresight_with_expectation_errors_solver' command." << endl; + exit(EXIT_FAILURE); + } + if (!mod_file_struct.ramsey_model_present) cout << "Found " << dynamic_model.equation_number() << " equation(s)." << endl; else @@ -669,13 +685,16 @@ ModFile::computingPass(bool no_tmp_terms, OutputType output, int params_derivs_o static_model.computingPass(derivsOrder, paramsDerivsOrder, global_eval_context, no_tmp_terms, block, bytecode); } // Set things to compute for dynamic model - if (mod_file_struct.perfect_foresight_solver_present || mod_file_struct.check_present + if (mod_file_struct.perfect_foresight_solver_present + || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present + || mod_file_struct.check_present || mod_file_struct.stoch_simul_present || mod_file_struct.estimation_present || mod_file_struct.osr_present || mod_file_struct.ramsey_model_present || mod_file_struct.identification_present || mod_file_struct.calib_smoother_present || mod_file_struct.mom_estimation_present) { - if (mod_file_struct.perfect_foresight_solver_present) + if (mod_file_struct.perfect_foresight_solver_present + || mod_file_struct.perfect_foresight_with_expectation_errors_solver_present) { int derivsOrder = 1; if (output == OutputType::second) @@ -897,9 +916,11 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global, // May be later modified by a shocks block mOutputFile << "M_.sigma_e_is_diagonal = true;" << endl; - // Initialize M_.det_shocks, M_.surprise_shocks and M_.heteroskedastic_shocks + // Initialize M_.det_shocks, M_.surprise_shocks, M_.learnt_shocks, M_.learnt_endval and M_.heteroskedastic_shocks mOutputFile << "M_.det_shocks = [];" << endl << "M_.surprise_shocks = [];" << endl + << "M_.learnt_shocks = [];" << endl + << "M_.learnt_endval = [];" << endl << "M_.heteroskedastic_shocks.Qvalue_orig = [];" << endl << "M_.heteroskedastic_shocks.Qscale_orig = [];" << endl; diff --git a/src/NumericalInitialization.cc b/src/NumericalInitialization.cc index 27849afb5361c3be77dcb42c0b682991f3671e66..afe6667ab35db81c0e1fe483e2e8682dad4aea8c 100644 --- a/src/NumericalInitialization.cc +++ b/src/NumericalInitialization.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2021 Dynare Team + * Copyright © 2003-2022 Dynare Team * * This file is part of Dynare. * @@ -299,6 +299,54 @@ EndValStatement::writeJsonOutput(ostream &output) const output << "]}"; } +EndValLearntInStatement::EndValLearntInStatement(int learnt_in_period_arg, + const InitOrEndValStatement::init_values_t &init_values_arg, + const SymbolTable &symbol_table_arg) : + learnt_in_period{learnt_in_period_arg}, + init_values{move(init_values_arg)}, + symbol_table{symbol_table_arg} +{ +} + +void +EndValLearntInStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) +{ + mod_file_struct.endval_learnt_in_present = true; +} + +void +EndValLearntInStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const +{ + output << "M_.learnt_endval = [ M_.learnt_endval;" << endl; + for (auto [symb_id, value] : init_values) + { + output << "struct('learnt_in'," << learnt_in_period + << ",'exo_id'," << symbol_table.getTypeSpecificID(symb_id)+1 + << ",'value',"; + value->writeOutput(output); + output << ");" << endl; + } + output << "];" << endl; +} + +void +EndValLearntInStatement::writeJsonOutput(ostream &output) const +{ + output << R"({"statementName": "endval", "learnt_in": )" + << learnt_in_period << R"(, "vals": [)"; + for (auto it = init_values.begin(); + it != init_values.end(); ++it) + { + auto [symb_id, value] = *it; + if (it != init_values.begin()) + output << ", "; + output << R"({"name": ")" << symbol_table.getName(symb_id) << R"(", )" << R"("value": ")"; + value->writeJsonOutput(output, {}, {}); + output << R"("})"; + } + output << "]}"; +} + HistValStatement::HistValStatement(hist_values_t hist_values_arg, const SymbolTable &symbol_table_arg, bool all_values_required_arg) : diff --git a/src/NumericalInitialization.hh b/src/NumericalInitialization.hh index 2c58656cccc5617dd0d6145b867f1f75cc03295a..5c5fd611fc7a5a5981e35cd7b85202a79d9e70e9 100644 --- a/src/NumericalInitialization.hh +++ b/src/NumericalInitialization.hh @@ -96,6 +96,20 @@ public: void writeJsonOutput(ostream &output) const override; }; +class EndValLearntInStatement : public Statement +{ +public: + const int learnt_in_period; + const InitOrEndValStatement::init_values_t init_values; + const SymbolTable &symbol_table; + EndValLearntInStatement(int learnt_in_period_arg, + const InitOrEndValStatement::init_values_t &init_values_arg, + const SymbolTable &symbol_table_arg); + void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override; + void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override; + void writeJsonOutput(ostream &output) const override; +}; + class HistValStatement : public Statement { public: diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index 48ba4537a5ae25a11cb9621f780ffe0014e1715e..60f70d7fcbc0c7596162fae36fb13f49c8ea395c 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -747,6 +747,16 @@ ParsingDriver::end_endval(bool all_values_required) init_values.clear(); } +void +ParsingDriver::end_endval_learnt_in(const string &learnt_in_period) +{ + for (auto [symb_id, value] : init_values) + if (mod_file->symbol_table.getType(symb_id) != SymbolType::exogenous) + error("endval(learnt_in=...): " + mod_file->symbol_table.getName(symb_id) + " is not an exogenous variable"); + mod_file->addStatement(make_unique<EndValLearntInStatement>(stoi(learnt_in_period), init_values, mod_file->symbol_table)); + init_values.clear(); +} + void ParsingDriver::end_histval(bool all_values_required) { @@ -848,6 +858,18 @@ ParsingDriver::end_shocks_surprise(bool overwrite) det_shocks.clear(); } +void +ParsingDriver::end_shocks_learnt_in(const string &learnt_in_period, bool overwrite) +{ + int learnt_in_period_int = stoi(learnt_in_period); + for (auto &[symb_id, vals] : det_shocks) + for (auto [period1, period2, expr] : vals) + if (period1 < learnt_in_period_int) + error("shocks: for variable " + mod_file->symbol_table.getName(symb_id) + ", shock period (" + to_string(period1) + ") is earlier than the period in which the shock is learnt (" + learnt_in_period + ")"); + mod_file->addStatement(make_unique<ShocksLearntInStatement>(learnt_in_period_int, overwrite, det_shocks, mod_file->symbol_table)); + det_shocks.clear(); +} + void ParsingDriver::end_heteroskedastic_shocks(bool overwrite) { diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index a421bc5ea21bf88b92d9c587b5a20cfb11acea69..2329a2e999a40708c271f35f55c47fa3a7010b03 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -101,7 +101,7 @@ private: //! Checks that a given symbol exists and is a endogenous, and stops with an error message if it isn't void check_symbol_is_endogenous(const string &name); - //! Checks that a given symbol exists and is a exogenous, and stops with an error message if it isn't + //! Checks that a given symbol exists and is a exogenous (possibly deterministic), and stops with an error message if it isn't void check_symbol_is_exogenous(const string &name); //! Checks for symbol existence in model block. If it doesn't exist, an error message is stored to be printed at @@ -423,6 +423,8 @@ public: void end_initval(bool all_values_required); //! Writes end of an endval block void end_endval(bool all_values_required); + //! Writes end of an endval(learnt_in=…) block + void end_endval_learnt_in(const string &learnt_in_period); //! Writes end of an histval block void end_histval(bool all_values_required); //! Writes end of an homotopy_setup block @@ -447,6 +449,8 @@ public: void end_mshocks(bool overwrite); //! Writes a shocks(surprise) statement void end_shocks_surprise(bool overwrite); + //! Writes a shocks(learnt_in=…) block + void end_shocks_learnt_in(const string &learnt_in_period, bool overwrite); //! Writes a heteroskedastic_shocks statement void end_heteroskedastic_shocks(bool overwrite); /* Adds a deterministic shock, a path element inside a diff --git a/src/Shocks.cc b/src/Shocks.cc index 0e77c0c9d8dd9fb628110a6c17e485f87fdb24e0..9031774278a8192c6030e789a6a321536477f5c5 100644 --- a/src/Shocks.cc +++ b/src/Shocks.cc @@ -491,6 +491,73 @@ ShocksSurpriseStatement::writeJsonOutput(ostream &output) const output << "]}"; } +ShocksLearntInStatement::ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg, + AbstractShocksStatement::det_shocks_t learnt_shocks_arg, + const SymbolTable &symbol_table_arg) : + learnt_in_period{learnt_in_period_arg}, overwrite{overwrite_arg}, + learnt_shocks{move(learnt_shocks_arg)}, symbol_table{symbol_table_arg} +{ +} + +void +ShocksLearntInStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) +{ + mod_file_struct.shocks_learnt_in_present = true; +} + +void +ShocksLearntInStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const +{ + if (overwrite) + output << "if ~isempty(M_.learnt_shocks)" << endl + << " M_.learnt_shocks = M_.learnt_shocks([M_.learnt_shocks.learnt_in] ~= " << learnt_in_period << ");" << endl + << "end" << endl; + + output << "M_.learnt_shocks = [ M_.learnt_shocks;" << endl; + for (const auto &[id, shock_vec] : learnt_shocks) + { + for (const auto &[period1, period2, value] : shock_vec) + { + output << "struct('learnt_in'," << learnt_in_period + << ",'exo_id'," << symbol_table.getTypeSpecificID(id)+1 + << ",'periods'," << period1 << ":" << period2 + << ",'value',"; + value->writeOutput(output); + output << ");" << endl; + } + } + output << "];" << endl; +} + +void +ShocksLearntInStatement::writeJsonOutput(ostream &output) const +{ + output << R"({"statementName": "shocks")" + << R"(, "learnt_in": )" << learnt_in_period + << R"(, "overwrite": )" << (overwrite ? "true" : "false") + << R"(, "learnt_shocks": [)"; + for (auto it = learnt_shocks.begin(); it != learnt_shocks.end(); ++it) + { + if (it != learnt_shocks.begin()) + output << ", "; + output << R"({"var": ")" << symbol_table.getName(it->first) << R"(", )" + << R"("values": [)"; + for (auto it1 = it->second.begin(); it1 != it->second.end(); ++it1) + { + auto [period1, period2, value] = *it1; + if (it1 != it->second.begin()) + output << ", "; + output << R"({"period1": )" << period1 << ", " + << R"("period2": )" << period2 << ", " + << R"("value": ")"; + value->writeJsonOutput(output, {}, {}); + output << R"("})"; + } + output << "]}"; + } + output << "]}"; +} + ConditionalForecastPathsStatement::ConditionalForecastPathsStatement(AbstractShocksStatement::det_shocks_t paths_arg, const SymbolTable &symbol_table_arg) : paths{move(paths_arg)}, diff --git a/src/Shocks.hh b/src/Shocks.hh index 83ec46e93ec190fce16d35e6467b3e367bc44bc1..dac2ab0c224c8160f2a61470309980ad81321dd0 100644 --- a/src/Shocks.hh +++ b/src/Shocks.hh @@ -106,6 +106,27 @@ public: void writeJsonOutput(ostream &output) const override; }; +/* Represents a shocks(learnt_in=…) block. + Given the differences with the plain “shocks” block, it was easier to make + it a separate class. */ +class ShocksLearntInStatement : public Statement +{ +public: + const int learnt_in_period; + //! Does this "shocks(learnt_in=…)" statement replace the previous ones? + const bool overwrite; + const AbstractShocksStatement::det_shocks_t learnt_shocks; +private: + const SymbolTable &symbol_table; +public: + ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg, + AbstractShocksStatement::det_shocks_t learnt_shocks_arg, + const SymbolTable &symbol_table_arg); + void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override; + void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override; + void writeJsonOutput(ostream &output) const override; +}; + class ConditionalForecastPathsStatement : public Statement { private: diff --git a/src/Statement.hh b/src/Statement.hh index 57d36061f6153798820a5e0095a71195d26230cb..58e3e9d5a3af7b00f01731803e6f411a784e0357 100644 --- a/src/Statement.hh +++ b/src/Statement.hh @@ -36,8 +36,10 @@ public: bool check_present{false}; //! Whether steady is present bool steady_present{false}; - //! Whether a perfect_foresight_solver/simul/perfect_foresight_with_expectation_errors_solver statement is present + //! Whether a perfect_foresight_solver/simul statement is present bool perfect_foresight_solver_present{false}; + //! Whether a perfect_foresight_with_expectation_errors_solver statement is present + bool perfect_foresight_with_expectation_errors_solver_present{false}; //! Whether a stoch_simul statement is present bool stoch_simul_present{false}; //! Whether an estimation statement is present @@ -147,6 +149,10 @@ public: set<int> parameters_in_planner_discount; // Whether a shocks(surprise) block appears bool shocks_surprise_present{false}; + // Whether a shocks(learnt_in=…) block appears + bool shocks_learnt_in_present{false}; + // Whether an endval(learnt_in=…) block appears + bool endval_learnt_in_present{false}; // Whether an occbin_constraints block appears bool occbin_constraints_present{false}; // Whether a ramsey_constraints block appears