From 341b9c666762b7a581483c82cb8c4f30483e157c Mon Sep 17 00:00:00 2001 From: Houtan Bastani <houtan@dynare.org> Date: Thu, 28 Feb 2019 19:22:34 +0100 Subject: [PATCH] pac_model: allow diff as argument to growth option --- src/ComputingTasks.cc | 68 +++++++++++++++++++++++++++++++------------ src/ComputingTasks.hh | 9 +++--- src/DynamicModel.cc | 6 +++- src/DynamicModel.hh | 2 +- src/DynareBison.yy | 6 ++-- src/ModFile.cc | 15 ++++++++-- src/ModFile.hh | 3 +- src/ParsingDriver.cc | 41 ++++++++++++++------------ src/ParsingDriver.hh | 10 +++++-- 9 files changed, 106 insertions(+), 54 deletions(-) diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc index 63aae410..2f3976e0 100644 --- a/src/ComputingTasks.cc +++ b/src/ComputingTasks.cc @@ -260,44 +260,76 @@ PriorPosteriorFunctionStatement::writeJsonOutput(ostream &output) const PacModelStatement::PacModelStatement(string name_arg, string aux_model_name_arg, string discount_arg, - int growth_symb_id_arg, - int growth_lag_arg, + expr_t growth_arg, double steady_state_growth_rate_number_arg, int steady_state_growth_rate_symb_id_arg, const SymbolTable &symbol_table_arg) : name{move(name_arg)}, aux_model_name{move(aux_model_name_arg)}, discount{move(discount_arg)}, - growth_symb_id{growth_symb_id_arg}, - growth_lag{growth_lag_arg}, + growth{growth_arg}, steady_state_growth_rate_number{steady_state_growth_rate_number_arg}, steady_state_growth_rate_symb_id{steady_state_growth_rate_symb_id_arg}, symbol_table{symbol_table_arg} { + growth_symb_id = -1; + growth_lag = 0; } void PacModelStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) { - mod_file_struct.pac_params.insert(symbol_table.getID(discount)); - if (growth_symb_id >= 0) + if (growth == nullptr) + return; + + VariableNode *vn = dynamic_cast<VariableNode *>(growth); + if (vn != nullptr) { - switch (symbol_table.getType(growth_symb_id)) - { - case SymbolType::endogenous: - case SymbolType::exogenous: - case SymbolType::parameter: - break; - default: + mod_file_struct.pac_params.insert(vn->symb_id); + mod_file_struct.pac_params.insert(vn->lag); + } + + UnaryOpNode *uon = dynamic_cast<UnaryOpNode *>(growth); + if (uon != nullptr) + if (uon->op_code == UnaryOpcode::diff) + { + VariableNode *uonvn = dynamic_cast<VariableNode *>(uon->arg); + UnaryOpNode *uon1 = dynamic_cast<UnaryOpNode *>(uon->arg); + while (uonvn == nullptr && uon1 != nullptr) + { + uonvn = dynamic_cast<VariableNode *>(uon1->arg); + uon1 = dynamic_cast<UnaryOpNode *>(uon1->arg); + } + if (uonvn == nullptr) { - cerr << "ERROR: The Expression passed to the growth option of pac_model must be an " - << "endogenous (lagged or not), exogenous (lagged or not), or parameter" << endl; + cerr << "Pac growth parameter must be either a variable or a diff unary op of a variable" << endl; exit(EXIT_FAILURE); } - } - mod_file_struct.pac_params.insert(growth_symb_id); - mod_file_struct.pac_params.insert(growth_lag); + mod_file_struct.pac_params.insert(uonvn->symb_id); + mod_file_struct.pac_params.insert(uonvn->lag); + } + + if (vn == nullptr && uon == nullptr) + { + cerr << "Pac growth parameter must be either a variable or a diff unary op of a variable" << endl; + exit(EXIT_FAILURE); + } +} + +void +PacModelStatement::overwriteGrowth(expr_t new_growth) +{ + if (new_growth == nullptr || growth == nullptr) + return; + + growth = new_growth; + VariableNode *vn = dynamic_cast<VariableNode *>(growth); + if (vn == nullptr) + { + cerr << "PacModelStatement::overwriteGrowth: Internal Dynare error: should not arrive here" << endl; } + growth_symb_id = vn->symb_id; + growth_lag = vn->lag; } void diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh index 47c4446e..36764150 100644 --- a/src/ComputingTasks.hh +++ b/src/ComputingTasks.hh @@ -138,22 +138,23 @@ class PacModelStatement : public Statement { public: const string name, aux_model_name, discount; - const int growth_symb_id, growth_lag; + expr_t growth; private: const double steady_state_growth_rate_number; const int steady_state_growth_rate_symb_id; const SymbolTable &symbol_table; - vector<int> lhs; public: + int growth_symb_id; + int growth_lag; PacModelStatement(string name_arg, string aux_model_name_arg, string discount_arg, - int growth_symb_id_arg, - int growth_lag_arg, + expr_t growth_arg, double steady_state_growth_rate_number_arg, int steady_state_growth_rate_symb_id_arg, const SymbolTable &symbol_table_arg); void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override; + void overwriteGrowth(expr_t new_growth); void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override; void writeJsonOutput(ostream &output) const override; }; diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 28ab0c6c..eeba1b8c 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -6303,7 +6303,7 @@ DynamicModel::substituteUnaryOps(StaticModel &static_model, diff_table_t &nodes, } void -DynamicModel::substituteDiff(StaticModel &static_model, diff_table_t &diff_table, ExprNode::subst_table_t &diff_subst_table) +DynamicModel::substituteDiff(StaticModel &static_model, diff_table_t &diff_table, ExprNode::subst_table_t &diff_subst_table, vector<expr_t> &pac_growth) { set<int> used_local_vars; for (const auto & equation : equations) @@ -6354,6 +6354,10 @@ DynamicModel::substituteDiff(StaticModel &static_model, diff_table_t &diff_table equation = substeq; } + for (auto & it : pac_growth) + if (it != nullptr) + it = it->substituteDiff(static_model, diff_table, diff_subst_table, neweqs); + // Add new equations for (auto & neweq : neweqs) addEquation(neweq, -1); diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 99759db4..30394526 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -444,7 +444,7 @@ public: void substituteUnaryOps(StaticModel &static_model, diff_table_t &nodes, ExprNode::subst_table_t &subst_table, vector<int> &eqnumbers); //! Substitutes diff operator - void substituteDiff(StaticModel &static_model, diff_table_t &diff_table, ExprNode::subst_table_t &diff_subst_table); + void substituteDiff(StaticModel &static_model, diff_table_t &diff_table, ExprNode::subst_table_t &diff_subst_table, vector<expr_t> &pac_growth); //! Substitute VarExpectation operators void substituteVarExpectation(const map<string, expr_t> &subst_table); diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 75f7d105..dc952902 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -388,7 +388,7 @@ trend_component_model_options : o_trend_component_model_name | o_trend_component_model_eq_tags ; -pac_model : PAC_MODEL '(' pac_model_options_list ')' ';' { driver.pac_model(); } ; +pac_model : PAC_MODEL '(' { driver.begin_pac_model(); } pac_model_options_list ')' ';' { driver.pac_model(); }; pac_model_options_list : pac_model_options_list COMMA pac_model_options | pac_model_options @@ -3131,9 +3131,7 @@ o_file : FILE EQUAL filename { driver.option_str("file", $3); }; o_pac_name : MODEL_NAME EQUAL symbol { driver.option_str("pac.model_name", $3); }; o_pac_aux_model_name : AUXILIARY_MODEL_NAME EQUAL symbol { driver.option_str("pac.aux_model_name", $3); }; o_pac_discount : DISCOUNT EQUAL symbol { driver.option_str("pac.discount", $3); }; -o_pac_growth : GROWTH EQUAL symbol { driver.set_pac_growth($3, 0); } - | GROWTH EQUAL symbol '(' MINUS INT_NUMBER ')' { driver.set_pac_growth($3, stoi($6)); } - ; +o_pac_growth : GROWTH { driver.begin_pac_growth(); } EQUAL hand_side { driver.set_pac_growth($4); }; o_pac_steady_state_growth : STEADY_STATE_GROWTH EQUAL signed_number { driver.set_pac_steady_state_growth($3); } | STEADY_STATE_GROWTH EQUAL symbol { driver.set_pac_steady_state_growth($3); } ; diff --git a/src/ModFile.cc b/src/ModFile.cc index 4b133dab..2ddecdc1 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -370,8 +370,13 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const for (auto & statement : statements) { auto pms = dynamic_cast<PacModelStatement *>(statement.get()); - if (pms != nullptr && pms->aux_model_name == "") - dynamic_model.declarePacModelConsistentExpectationEndogs(pms->name); + if (pms != nullptr) + { + if (pms->growth != nullptr) + pac_growth.push_back(pms->growth); + if (pms->aux_model_name == "") + dynamic_model.declarePacModelConsistentExpectationEndogs(pms->name); + } } dynamic_model.substituteAdl(); dynamic_model.setLeadsLagsOrig(); @@ -409,7 +414,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const // Create auxiliary variable and equations for Diff operators diff_table_t diff_table; ExprNode::subst_table_t diff_subst_table; - dynamic_model.substituteDiff(diff_static_model, diff_table, diff_subst_table); + dynamic_model.substituteDiff(diff_static_model, diff_table, diff_subst_table, pac_growth); // Fill Trend Component Model Table dynamic_model.fillTrendComponentModelTable(); @@ -419,11 +424,15 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const original_model.fillVarModelTableFromOrigModel(diff_static_model); // Pac Model + int i = 0; for (auto & statement : statements) { auto pms = dynamic_cast<PacModelStatement *>(statement.get()); if (pms != nullptr) { + if (pms->growth != nullptr) + pms->overwriteGrowth(pac_growth.at(i++)); + int max_lag; vector<int> lhs; vector<bool> nonstationary; diff --git a/src/ModFile.hh b/src/ModFile.hh index a7b73f50..e6c4f2bf 100644 --- a/src/ModFile.hh +++ b/src/ModFile.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2018 Dynare Team + * Copyright (C) 2006-2019 Dynare Team * * This file is part of Dynare. * @@ -130,6 +130,7 @@ private: void writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType json_output_mode, bool transformpass, bool computingpass) const; void writeJsonComputingPassOutput(const string &basename, JsonFileOutputType json_output_mode, bool jsonderivsimple) const; void writeJsonFileHelper(const string &fname, ostringstream &output) const; + vector<expr_t> pac_growth; public: //! Add a statement void addStatement(unique_ptr<Statement> st); diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index 56465009..39f89247 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -2607,6 +2607,22 @@ ParsingDriver::add_pac_expectation(const string &var_model_name) return data_tree->AddPacExpectation(var_model_name); } +void +ParsingDriver::begin_pac_growth() +{ + set_current_data_tree(&mod_file->dynamic_model); +} + +void +ParsingDriver::begin_pac_model() +{ + parsing_pac_model = true; + pac_growth = nullptr; + pac_steady_state_growth_rate_number = -1; + pac_steady_state_growth_rate_symb_id = -1; + options_list.clear(); +} + void ParsingDriver::pac_model() { @@ -2626,13 +2642,6 @@ ParsingDriver::pac_model() } else aux_model_name = it->second; - else - if (pac_growth_symb_id >= 0 && mod_file->symbol_table.getType(pac_growth_symb_id) == SymbolType::parameter - && (pac_steady_state_growth_rate_number >= 0 || pac_steady_state_growth_rate_symb_id >=0)) - warning("If growth option is constant, steady_state_growth is ignored"); - else if (pac_growth_symb_id >= 0 && mod_file->symbol_table.getType(pac_growth_symb_id) != SymbolType::parameter - && (pac_steady_state_growth_rate_number < 0 || pac_steady_state_growth_rate_symb_id < 0)) - error("The steady state growth rate of the target must be provided (steady_state_growth option) if option growth is not constant"); if (pac_steady_state_growth_rate_symb_id >= 0 && mod_file->symbol_table.getType(pac_steady_state_growth_rate_symb_id) != SymbolType::parameter) @@ -2644,24 +2653,18 @@ ParsingDriver::pac_model() auto discount = it->second; mod_file->addStatement(make_unique<PacModelStatement>(name, aux_model_name, discount, - pac_growth_symb_id, pac_growth_lag, + pac_growth, pac_steady_state_growth_rate_number, pac_steady_state_growth_rate_symb_id, mod_file->symbol_table)); - pac_growth_symb_id = -1; - pac_growth_lag = 0; - pac_steady_state_growth_rate_number = -1; - pac_steady_state_growth_rate_symb_id = -1; - options_list.clear(); + parsing_pac_model = false; } void -ParsingDriver::set_pac_growth(const string &name, int lag) +ParsingDriver::set_pac_growth(expr_t pac_growth_arg) { - if (!mod_file->symbol_table.exists(name)) - error("Unknown symbol used in pac_growth option: " + name + "\n"); - pac_growth_symb_id = mod_file->symbol_table.getID(name); - pac_growth_lag = -lag; + pac_growth = pac_growth_arg; + reset_data_tree(); } void @@ -2981,7 +2984,7 @@ ParsingDriver::add_model_var_or_external_function(const string &function_name, b expr_t nid; if (mod_file->symbol_table.exists(function_name)) if (mod_file->symbol_table.getType(function_name) != SymbolType::externalFunction) - if (!in_model_block && !parsing_epilogue) + if (!in_model_block && !parsing_epilogue && !parsing_pac_model) { if (stack_external_function_args.top().size() > 0) error(string("Symbol ") + function_name + string(" cannot take arguments.")); diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index e0fa48ae..78187ac2 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -255,8 +255,7 @@ private: WarningConsolidation &warnings; //! Temporary storage for growth declared in pac_model - int pac_growth_symb_id = -1; - int pac_growth_lag = 0; + expr_t pac_growth; double pac_steady_state_growth_rate_number = -1; int pac_steady_state_growth_rate_symb_id = -1; @@ -271,6 +270,9 @@ private: //! True when parsing the epilogue block bool parsing_epilogue{false}; + //! True when parsing pac_model statement + bool parsing_pac_model{false}; + public: ParsingDriver(WarningConsolidation &warnings_arg, bool nostrict_arg) : warnings{warnings_arg}, nostrict{nostrict_arg} { }; @@ -732,9 +734,11 @@ public: //! Writes token "PAC_EXPECTATION(model_name, discount, growth)" to model tree expr_t add_pac_expectation(const string &var_model_name); //! Creates pac_model statement + void begin_pac_growth(); + void begin_pac_model(); void pac_model(); //! Adds growth for pac - void set_pac_growth(const string &name, int lag = 0); + void set_pac_growth(expr_t pac_growth_arg); //! Adds steady state growth for pac void set_pac_steady_state_growth(const string &name_or_number); //! Writes token "diff(arg1)" to model tree -- GitLab