diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 98cee52eaf94b118dd10b088764cdc524f105015..ddcb24d833fc09be5eff8af92c2c6f5b03afeacd 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -172,6 +172,7 @@ class ParsingDriver; %token NUMBER_OF_POSTERIOR_DRAWS_AFTER_PERTURBATION MAX_NUMBER_OF_STAGES %token RANDOM_FUNCTION_CONVERGENCE_CRITERION RANDOM_PARAMETER_CONVERGENCE_CRITERION NO_INIT_ESTIMATION_CHECK_FIRST_OBS %token HETEROSKEDASTIC_FILTER TIME_SHIFT STRUCTURAL TERMINAL_STEADY_STATE_AS_GUESS_VALUE +%token SURPRISE /* Method of Moments */ %token METHOD_OF_MOMENTS MOM_METHOD %token BARTLETT_KERNEL_LAG WEIGHTING_MATRIX WEIGHTING_MATRIX_SCALING_FACTOR ANALYTIC_STANDARD_ERRORS ANALYTIC_JACOBIAN PENALIZED_ESTIMATOR VERBOSE @@ -1028,6 +1029,9 @@ pound_expression: '#' symbol EQUAL hand_side ';' 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); } ; shock_list : shock_list shock_elem @@ -1049,6 +1053,10 @@ 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 + ; + heteroskedastic_shocks : HETEROSKEDASTIC_SHOCKS ';' heteroskedastic_shock_list END ';' { driver.end_heteroskedastic_shocks(false); } | HETEROSKEDASTIC_SHOCKS '(' OVERWRITE ')' ';' heteroskedastic_shock_list END ';' diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll index 6816154d8bc760d25023ba790b804bc4b43b8ad2..fec10ec5b1edebfc3bbc6c7c8fdaaf7281f9ff2d 100644 --- a/src/DynareFlex.ll +++ b/src/DynareFlex.ll @@ -761,6 +761,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]) <DYNARE_BLOCK>uniform_pdf {return token::UNIFORM_PDF;} <DYNARE_BLOCK>weibull_pdf {return token::WEIBULL_PDF;} <DYNARE_BLOCK>dsge_prior_weight {return token::DSGE_PRIOR_WEIGHT;} +<DYNARE_BLOCK>surprise {return token::SURPRISE;} <DYNARE_BLOCK>; {return Dynare::parser::token_type (yytext[0]);} <DYNARE_BLOCK># {return Dynare::parser::token_type (yytext[0]);} diff --git a/src/ModFile.cc b/src/ModFile.cc index 8fc0b422b02ad9c414b78ced0981d826d37d47b1..6c8b6b6e0561d74c6c80f74d0c071e54ecbf14a5 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -700,6 +700,12 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool exit(EXIT_FAILURE); } + if (mod_file_struct.shocks_surprise_present && !occbin) + { + cerr << "ERROR: the 'shocks(surprise)' block can only be used in conjunction with occbin commands." << endl; + exit(EXIT_FAILURE); + } + if (!mod_file_struct.ramsey_model_present) cout << "Found " << dynamic_model.equation_number() << " equation(s)." << endl; else @@ -985,8 +991,9 @@ 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 and M_.heteroskedastic_shocks + // Initialize M_.det_shocks, M_.surprise_shocks and M_.heteroskedastic_shocks mOutputFile << "M_.det_shocks = [];" << endl + << "M_.surprise_shocks = [];" << endl << "M_.heteroskedastic_shocks.Qvalue_orig = [];" << endl << "M_.heteroskedastic_shocks.Qscale_orig = [];" << endl; diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index 1bf5618dbcba8c8a90c67390eca8f093edb26c24..2674f8f2ffd520ec69c028524ca6e212c87ed0dd 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -798,6 +798,13 @@ ParsingDriver::end_mshocks(bool overwrite) det_shocks.clear(); } +void +ParsingDriver::end_shocks_surprise(bool overwrite) +{ + mod_file->addStatement(make_unique<ShocksSurpriseStatement>(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 972bd40b1421eb3ff4e11cf8cb25fa7479cfad83..324883b4a9d848d086985d7a0448e1fba884c128 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -149,7 +149,8 @@ private: OptimWeightsStatement::var_weights_t var_weights; //! Temporary storage of covariances from optim_weights OptimWeightsStatement::covar_weights_t covar_weights; - //! Temporary storage for deterministic shocks + /* Temporary storage for deterministic shocks. Also used for + conditional_forecast paths and for surprise shocks. */ ShocksStatement::det_shocks_t det_shocks; //! Temporary storage for variances of shocks ShocksStatement::var_and_std_shocks_t var_shocks; @@ -436,9 +437,12 @@ public: void end_shocks(bool overwrite); //! Writes a mshocks statement void end_mshocks(bool overwrite); + //! Writes a shocks(surprise) statement + void end_shocks_surprise(bool overwrite); //! Writes a heteroskedastic_shocks statement void end_heteroskedastic_shocks(bool overwrite); - //! Adds a deterministic shock or a path element inside a conditional_forecast_paths block + /* Adds a deterministic shock, a path element inside a + conditional_forecast_paths block, or a surprise shock */ void add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool conditional_forecast); //! Adds a heteroskedastic shock (either values or scales) void add_heteroskedastic_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool scales); diff --git a/src/Shocks.cc b/src/Shocks.cc index 4fbf8607726770a8b88d94aff1632052eb670f75..0e77c0c9d8dd9fb628110a6c17e485f87fdb24e0 100644 --- a/src/Shocks.cc +++ b/src/Shocks.cc @@ -428,6 +428,69 @@ MShocksStatement::writeJsonOutput(ostream &output) const output << "}"; } +ShocksSurpriseStatement::ShocksSurpriseStatement(bool overwrite_arg, + AbstractShocksStatement::det_shocks_t surprise_shocks_arg, + const SymbolTable &symbol_table_arg) : + overwrite{overwrite_arg}, surprise_shocks{move(surprise_shocks_arg)}, + symbol_table{symbol_table_arg} +{ +} + +void +ShocksSurpriseStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) +{ + mod_file_struct.shocks_surprise_present = true; +} + +void +ShocksSurpriseStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const +{ + if (overwrite) + output << "M_.surprise_shocks = [" << endl; + else + output << "M_.surprise_shocks = [ M_.surprise_shocks;" << endl; + for (const auto &[id, shock_vec] : surprise_shocks) + { + for (const auto &[period1, period2, value] : shock_vec) + { + output << "struct('exo_id'," << symbol_table.getTypeSpecificID(id)+1 + << ",'periods'," << period1 << ":" << period2 + << ",'value',"; + value->writeOutput(output); + output << ");" << endl; + } + } + output << "];" << endl; +} + +void +ShocksSurpriseStatement::writeJsonOutput(ostream &output) const +{ + output << R"({"statementName": "shocks")" + << R"(, "surprise": true)" + << R"(, "surprise_shocks": [)"; + for (auto it = surprise_shocks.begin(); it != surprise_shocks.end(); ++it) + { + if (it != surprise_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 243768832acbf5f0f9cffdc8f1ee28eb0cd818a2..b2b22155ba672863d3f4e053a288ed89ec5decd4 100644 --- a/src/Shocks.hh +++ b/src/Shocks.hh @@ -86,6 +86,26 @@ public: void writeJsonOutput(ostream &output) const override; }; +/* Represents a shocks(surprise) block. + Given the differences with the plain “shocks” block, it was easier to make + it a separate class. */ +class ShocksSurpriseStatement : public Statement +{ +public: + //! Does this "shocks(surprise)" statement replace the previous ones? + const bool overwrite; + const AbstractShocksStatement::det_shocks_t surprise_shocks; +private: + const SymbolTable &symbol_table; +public: + ShocksSurpriseStatement(bool overwrite_arg, + AbstractShocksStatement::det_shocks_t surprise_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 32e020a8b196af042192fe82ad45c3b57b4c4f17..0b23aad61522fefb350aded009fe2b7fed698301 100644 --- a/src/Statement.hh +++ b/src/Statement.hh @@ -145,6 +145,8 @@ public: /* Lists symbol IDs of parameters that appear in a “planner_discount” option. See dynare#1173 for more details. */ set<int> parameters_in_planner_discount; + // Whether a shocks(surprise) block appears + bool shocks_surprise_present{false}; }; class Statement