From f78c428d99884c4b336dba0a7df20c7ad41fb682 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Wed, 18 Oct 2023 13:48:45 -0400 Subject: [PATCH] =?UTF-8?q?New=20option=20=E2=80=9Crelative=5Fto=5Finitval?= =?UTF-8?q?=E2=80=9D=20to=20=E2=80=9Cmshocks=E2=80=9D=20block?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/DynareBison.yy | 47 ++++++++++++++++++++++++++++++++++++++------ src/DynareFlex.ll | 1 + src/ParsingDriver.cc | 14 ++++++++----- src/ParsingDriver.hh | 4 ++-- src/Shocks.cc | 38 ++++++++++++++++++++++++++--------- src/Shocks.hh | 20 +++++++++++++------ 6 files changed, 96 insertions(+), 28 deletions(-) diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 7e21d57d..521100fa 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -33,6 +33,13 @@ class ParsingDriver; } %code requires { +#include <string> +#include <vector> +#include <map> +#include <utility> +#include <tuple> +#include <variant> + #include "CommonEnums.hh" #include "ExprNode.hh" } @@ -196,7 +203,7 @@ class ParsingDriver; %token ENDVAL_STEADY STEADY_SOLVE_ALGO STEADY_MAXIT STEADY_TOLF STEADY_TOLX STEADY_MARKOWITZ %token HOMOTOPY_MAX_COMPLETION_SHARE HOMOTOPY_MIN_STEP_SIZE HOMOTOPY_INITIAL_STEP_SIZE HOMOTOPY_STEP_SIZE_INCREASE_SUCCESS_COUNT %token HOMOTOPY_LINEARIZATION_FALLBACK HOMOTOPY_MARGINAL_LINEARIZATION_FALLBACK FROM_INITVAL_TO_ENDVAL -%token STATIC_MFS +%token STATIC_MFS RELATIVE_TO_INITVAL %token <vector<string>> SYMBOL_VEC @@ -228,6 +235,8 @@ class ParsingDriver; %type <pair<string, expr_t>> occbin_constraints_regime_option %type <PacTargetKind> pac_target_kind %type <vector<tuple<string, string, vector<pair<string, string>>>>> symbol_list_with_tex_and_partition +%type <map<string, variant<bool, string>>> mshocks_options_list +%type <pair<string, variant<bool, string>>> mshocks_option %% %start statement_list; @@ -1280,13 +1289,39 @@ svar_options : o_coefficients | o_chain ; -mshocks : MSHOCKS ';' mshock_list END ';' { driver.end_mshocks(false); } - | MSHOCKS '(' OVERWRITE ')' ';' mshock_list END ';' { driver.end_mshocks(true); } - | MSHOCKS '(' LEARNT_IN EQUAL INT_NUMBER ')' ';' mshock_list END ';' { driver.end_mshocks_learnt_in($5, false); } - | MSHOCKS '(' LEARNT_IN EQUAL INT_NUMBER COMMA OVERWRITE ')' ';' mshock_list END ';' { driver.end_mshocks_learnt_in($5, true); } - | MSHOCKS '(' OVERWRITE COMMA LEARNT_IN EQUAL INT_NUMBER ')' ';' mshock_list END ';' { driver.end_mshocks_learnt_in($7, true); } +mshocks : MSHOCKS ';' mshock_list END ';' + { driver.end_mshocks(false, false); } + | MSHOCKS '(' mshocks_options_list ')' ';' mshock_list END ';' + { + /* NB: the following relies of the fact that bool is the first + alternative in the variant, so that default initialization of the + variant by the [] operator will give false */ + if ($3.contains("learnt_in")) + driver.end_mshocks_learnt_in(get<string>($3.at("learnt_in")), get<bool>($3["overwrite"]), get<bool>($3["relative_to_initval"])); + else + driver.end_mshocks(get<bool>($3["overwrite"]), get<bool>($3["relative_to_initval"])); + } ; +mshocks_options_list : mshocks_option + { $$ = { $1 }; } + | mshocks_options_list mshocks_option + { + $$ = $1; + auto [it, success] = $$.insert($2); + if (!success) + driver.error("The '" + $2.first + "' option is declared multiple times"); + } + ; + +mshocks_option : OVERWRITE + { $$ = { "overwrite", true }; } + | LEARNT_IN EQUAL INT_NUMBER + { $$ = { "learnt_in", $3 }; } + | RELATIVE_TO_INITVAL + { $$ = { "relative_to_initval", true }; } + ; + mshock_list : mshock_list det_shock_elem | det_shock_elem ; diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll index 60544e89..092712bf 100644 --- a/src/DynareFlex.ll +++ b/src/DynareFlex.ll @@ -829,6 +829,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]) yylval->build<string>(yytext); return token::ERROR_RELAX; } +<DYNARE_BLOCK>relative_to_initval {return token::RELATIVE_TO_INITVAL;} <DYNARE_BLOCK>; {return Dynare::parser::token_type (yytext[0]);} <DYNARE_BLOCK># {return Dynare::parser::token_type (yytext[0]);} diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index f8ce2cac..18abd332 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -887,9 +887,10 @@ ParsingDriver::end_shocks(bool overwrite) } void -ParsingDriver::end_mshocks(bool overwrite) +ParsingDriver::end_mshocks(bool overwrite, bool relative_to_initval) { - mod_file->addStatement(make_unique<MShocksStatement>(overwrite, move(det_shocks), + mod_file->addStatement(make_unique<MShocksStatement>(overwrite, relative_to_initval, + move(det_shocks), mod_file->symbol_table)); det_shocks.clear(); if (!learnt_shocks_add.empty()) @@ -960,14 +961,14 @@ ParsingDriver::end_shocks_learnt_in(const string &learnt_in_period, bool overwri } void -ParsingDriver::end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite) +ParsingDriver::end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite, bool relative_to_initval) { int learnt_in_period_int = stoi(learnt_in_period); if (learnt_in_period_int < 1) error("mshocks: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option"); if (learnt_in_period_int == 1) { - end_mshocks(overwrite); + end_mshocks(overwrite, relative_to_initval); return; } @@ -977,11 +978,14 @@ ParsingDriver::end_mshocks_learnt_in(const string &learnt_in_period, bool overwr error("mshocks: 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 + ")"); ShocksLearntInStatement::learnt_shocks_t learnt_shocks; + const auto type { relative_to_initval ? + ShocksLearntInStatement::LearntShockType::multiplyInitialSteadyState : + ShocksLearntInStatement::LearntShockType::multiplySteadyState }; for (const auto &[id, v] : det_shocks) { vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2; for (auto [period1, period2, value] : v) - v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiplySteadyState, period1, period2, value); + v2.emplace_back(type, period1, period2, value); learnt_shocks[id] = v2; } diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index 7c6f7144..f9a47ac1 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -447,13 +447,13 @@ public: //! Writes a shocks statement void end_shocks(bool overwrite); //! Writes a mshocks statement - void end_mshocks(bool overwrite); + void end_mshocks(bool overwrite, bool relative_to_initval); //! 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 mshocks(learnt_in=…) block - void end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite); + void end_mshocks_learnt_in(const string &learnt_in_period, bool overwrite, bool relative_to_initval); //! 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 1218c6c9..c0c2b95e 100644 --- a/src/Shocks.cc +++ b/src/Shocks.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2022 Dynare Team + * Copyright © 2003-2023 Dynare Team * * This file is part of Dynare. * @@ -24,12 +24,11 @@ #include "Shocks.hh" -AbstractShocksStatement::AbstractShocksStatement(bool mshocks_arg, - bool overwrite_arg, +AbstractShocksStatement::AbstractShocksStatement(bool overwrite_arg, ShockType type_arg, det_shocks_t det_shocks_arg, const SymbolTable &symbol_table_arg) : - mshocks{mshocks_arg}, overwrite{overwrite_arg}, + type{type_arg}, det_shocks{move(det_shocks_arg)}, symbol_table{symbol_table_arg} { @@ -48,7 +47,7 @@ AbstractShocksStatement::writeDetShocks(ostream &output) const << boolalpha << "struct('exo_det'," << exo_det << ",'exo_id'," << symbol_table.getTypeSpecificID(id)+1 - << ",'multiplicative'," << mshocks + << ",'type','" << typeToString(type) << "'" << ",'periods'," << period1 << ":" << period2 << ",'value',"; value->writeOutput(output); @@ -87,6 +86,21 @@ AbstractShocksStatement::writeJsonDetShocks(ostream &output) const output << "]"; } +string +AbstractShocksStatement::typeToString(ShockType type) +{ + switch (type) + { + case ShockType::level: + return "level"; + case ShockType::multiplySteadyState: + return "multiply_steady_state"; + case ShockType::multiplyInitialSteadyState: + return "multiply_initial_steady_state"; + } + __builtin_unreachable(); // Silence GCC warning +} + ShocksStatement::ShocksStatement(bool overwrite_arg, det_shocks_t det_shocks_arg, var_and_std_shocks_t var_shocks_arg, @@ -94,7 +108,7 @@ ShocksStatement::ShocksStatement(bool overwrite_arg, covar_and_corr_shocks_t covar_shocks_arg, covar_and_corr_shocks_t corr_shocks_arg, const SymbolTable &symbol_table_arg) : - AbstractShocksStatement{false, overwrite_arg, move(det_shocks_arg), symbol_table_arg}, + AbstractShocksStatement{overwrite_arg, ShockType::level, move(det_shocks_arg), symbol_table_arg}, var_shocks{move(var_shocks_arg)}, std_shocks{move(std_shocks_arg)}, covar_shocks{move(covar_shocks_arg)}, @@ -400,10 +414,13 @@ ShocksStatement::has_calibrated_measurement_errors() const return false; } -MShocksStatement::MShocksStatement(bool overwrite_arg, +MShocksStatement::MShocksStatement(bool overwrite_arg, bool relative_to_initval_arg, det_shocks_t det_shocks_arg, const SymbolTable &symbol_table_arg) : - AbstractShocksStatement{true, overwrite_arg, move(det_shocks_arg), symbol_table_arg} + AbstractShocksStatement{overwrite_arg, + relative_to_initval_arg ? ShockType::multiplyInitialSteadyState : ShockType::multiplySteadyState, + move(det_shocks_arg), symbol_table_arg}, + relative_to_initval{relative_to_initval_arg} { } @@ -425,7 +442,8 @@ void MShocksStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "mshocks")" - << R"(, "overwrite": )" << boolalpha << overwrite; + << R"(, "overwrite": )" << boolalpha << overwrite + << R"(, "relative_to_initval": )" << boolalpha << relative_to_initval; if (!det_shocks.empty()) { output << ", "; @@ -526,6 +544,8 @@ ShocksLearntInStatement::typeToString(LearntShockType type) return "multiply"; case LearntShockType::multiplySteadyState: return "multiply_steady_state"; + case LearntShockType::multiplyInitialSteadyState: + return "multiply_initial_steady_state"; } __builtin_unreachable(); // Silence GCC warning } diff --git a/src/Shocks.hh b/src/Shocks.hh index e5743d02..43573760 100644 --- a/src/Shocks.hh +++ b/src/Shocks.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2022 Dynare Team + * Copyright © 2003-2023 Dynare Team * * This file is part of Dynare. * @@ -35,17 +35,23 @@ class AbstractShocksStatement : public Statement public: // The tuple is (period1, period2, value) using det_shocks_t = map<int, vector<tuple<int, int, expr_t>>>; + enum class ShockType + { + level, // The value is the level of the exogenous (“values†statement in “shocksâ€) + multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state (“values†statement in “mshocksâ€) + multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady state (“values†statement in “mshocks(relative_to_initval)â€) + }; protected: - //! Is this statement a "mshocks" statement ? (instead of a "shocks" statement) - const bool mshocks; //! Does this "shocks" statement replace the previous ones? const bool overwrite; + const ShockType type; // Type of shocks represented by this block const det_shocks_t det_shocks; const SymbolTable &symbol_table; void writeDetShocks(ostream &output) const; void writeJsonDetShocks(ostream &output) const; + static string typeToString(ShockType type); - AbstractShocksStatement(bool mshocks_arg, bool overwrite_arg, + AbstractShocksStatement(bool overwrite_arg, ShockType type_arg, det_shocks_t det_shocks_arg, const SymbolTable &symbol_table_arg); }; @@ -79,7 +85,8 @@ public: class MShocksStatement : public AbstractShocksStatement { public: - MShocksStatement(bool overwrite_arg, + const bool relative_to_initval; + MShocksStatement(bool overwrite_arg, bool relative_to_initval_arg, det_shocks_t det_shocks_arg, const SymbolTable &symbol_table_arg); void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override; @@ -120,7 +127,8 @@ public: level, // The value is the level of the exogenous (“values†statement in “shocks(learnt_in=…)â€) add, // The value is the additive change of the exogenous compared to previous information period (“add†statement in “shocks(learnt_in=…)â€) multiply, // The value is the multiplicative change of the exogenous compared to previous information period (“multiply†statement in “shocks(learnt_in=…)â€) - multiplySteadyState // The value is the ratio of the exogenous over its (terminal) steady state as anticipated in the same informational period (“values†statement in “mshocks(learnt_in=…)â€) + multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state as anticipated in the same informational period (“values†statement in “mshocks(learnt_in=…)â€) + multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady state as anticipated in the same informational period (“values†statement in “mshocks(learnt_in=…, relative_to_initval)â€) }; // The tuple is (type, period1, period2, value) using learnt_shocks_t = map<int, vector<tuple<LearntShockType, int, int, expr_t>>>; -- GitLab