From 539fddc9f68c751c3f83559403cc7ef5e7e04e76 Mon Sep 17 00:00:00 2001 From: Houtan Bastani Date: Tue, 21 Aug 2018 11:46:59 +0200 Subject: [PATCH] introduce var model table --- src/ComputingTasks.cc | 155 +------------------------- src/ComputingTasks.hh | 33 +----- src/DataTree.cc | 4 +- src/DataTree.hh | 5 +- src/DynamicModel.cc | 205 +++++++++++++++++++++++++++++++--- src/DynamicModel.hh | 16 ++- src/ModFile.cc | 131 +++++++++------------- src/ModFile.hh | 4 +- src/ModelTree.cc | 7 +- src/ModelTree.hh | 3 +- src/ParsingDriver.cc | 42 ++++--- src/StaticModel.cc | 7 +- src/StaticModel.hh | 3 +- src/SteadyStateModel.cc | 7 +- src/SteadyStateModel.hh | 3 +- src/SubModel.cc | 238 ++++++++++++++++++++++++++++++++++++++++ src/SubModel.hh | 65 +++++++++++ 17 files changed, 615 insertions(+), 313 deletions(-) diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc index 992f38a7..ead7e744 100644 --- a/src/ComputingTasks.cc +++ b/src/ComputingTasks.cc @@ -380,154 +380,6 @@ PacModelStatement::getPacModelInfoForPacExpectation() const return { name, aux_model_name, growth_symb_id }; } -VarModelStatement::VarModelStatement(SymbolList symbol_list_arg, - OptionsList options_list_arg, - string name_arg, - const SymbolTable &symbol_table_arg) : - symbol_list(move(symbol_list_arg)), - options_list(move(options_list_arg)), - name{move(name_arg)}, - symbol_table(symbol_table_arg) -{ -} - -void -VarModelStatement::getVarModelInfo(string &var_model_name, - map> &var_model_info, - map> &var_model_eqtags) const -{ - var_model_name = name; - if (symbol_list.empty()) - { - auto it = options_list.vector_str_options.find("var.eqtags"); - var_model_eqtags[name] = it->second; - } - else - { - auto it = options_list.num_options.find("var.order"); - var_model_info[name] = { symbol_list, stoi(it->second) }; - } -} - -void -VarModelStatement::fillVarModelInfoFromEquations(vector &eqnumber_arg, vector &lhs_arg, - vector>> &rhs_arg, - vector &nonstationary_arg, - vector &diff_arg, - vector &orig_diff_var_arg, - int max_lag_arg) -{ - eqnumber = eqnumber_arg; - lhs = lhs_arg; - rhs_by_eq = rhs_arg; - nonstationary = nonstationary_arg; - diff = diff_arg; - orig_diff_var = orig_diff_var_arg; - max_lag = max_lag_arg; -} - -void -VarModelStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) -{ -} - -void -VarModelStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const -{ - options_list.writeOutput(output); - if (!symbol_list.empty()) - symbol_list.writeOutput("options_.var.var_list_", output); - - output << "M_.var." << name << " = options_.var;" << endl - << "options_ = rmfield(options_, 'var');" << endl; - - output << "M_.var." << name << ".eqn = ["; - for (auto it = eqnumber.begin(); - it != eqnumber.end(); it++) - { - if (it != eqnumber.begin()) - output << " "; - output << *it + 1; - } - output << "];" << endl - << "M_.var." << name << ".lhs = ["; - for (auto it = lhs.begin(); - it != lhs.end(); it++) - { - if (it != lhs.begin()) - output << " "; - output << symbol_table.getTypeSpecificID(*it) + 1; - } - output << "];" << endl - << "M_.var." << name << ".max_lag = " << max_lag << ";" << endl - << "M_.var." << name << ".nonstationary = ["; - for (auto it = nonstationary.begin(); - it != nonstationary.end(); it++) - { - if (it != nonstationary.begin()) - output << " "; - if (*it) - output << "true"; - else - output << "false"; - } - output << "];" << endl - << "M_.var." << name << ".diff = ["; - for (auto it = diff.begin(); - it != diff.end(); it++) - { - if (it != diff.begin()) - output << " "; - if (*it) - output << "true"; - else - output << "false"; - } - output << "];" << endl - << "M_.var." << name << ".orig_diff_var = ["; - for (auto it = orig_diff_var.begin(); - it != orig_diff_var.end(); it++) - { - if (it != orig_diff_var.begin()) - output << " "; - if (*it == -1) - output << -1; - else - output << symbol_table.getTypeSpecificID(*it) + 1; - } - output << "];" << endl; - int i = 1; - for (auto it = rhs_by_eq.begin(); - it != rhs_by_eq.end(); it++, i++) - { - output << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.var = ["; - for (auto it1 = it->begin(); - it1 != it->end(); it1++) - { - if (it1 != it->begin()) - output << " "; - output << symbol_table.getTypeSpecificID(it1->first) + 1; - } - output << "];" << endl - << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.lag = ["; - for (auto it1 = it->begin(); - it1 != it->end(); it1++) - { - if (it1 != it->begin()) - output << " "; - output << it1->second; - } - output << "];" << endl; - } -} - -void -VarModelStatement::writeJsonOutput(ostream &output) const -{ - output << "{\"statementName\": \"var_model\"," - << "\"model_name\": \"" << name << "\"}"; -} - VarEstimationStatement::VarEstimationStatement(OptionsList options_list_arg) : options_list(move(options_list_arg)) { @@ -2210,9 +2062,10 @@ ModelComparisonStatement::writeJsonOutput(ostream &output) const PlannerObjectiveStatement::PlannerObjectiveStatement(SymbolTable &symbol_table, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table, - TrendComponentModelTable &trend_component_model_table_arg) : - model_tree{symbol_table, num_constants, - external_functions_table, trend_component_model_table_arg} + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : + model_tree{symbol_table, num_constants, external_functions_table, + trend_component_model_table_arg, var_model_table_arg} { } diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh index cdfe4499..ccadaea9 100644 --- a/src/ComputingTasks.hh +++ b/src/ComputingTasks.hh @@ -141,36 +141,6 @@ public: tuple getPacModelInfoForPacExpectation() const; }; -class VarModelStatement : public Statement -{ -public: - const SymbolList symbol_list; - const OptionsList options_list; - const string name; -private: - const SymbolTable &symbol_table; - vector eqnumber, lhs, orig_diff_var; - vector>> rhs_by_eq; // rhs by equation - vector nonstationary, diff; - int max_lag; -public: - VarModelStatement(SymbolList symbol_list_arg, - OptionsList options_list_arg, - string name_arg, - const SymbolTable &symbol_table_arg); - void getVarModelInfo(string &var_model_name, - map> &var_model_info, - map> &var_model_eqtags) const; - void fillVarModelInfoFromEquations(vector &eqnumber_arg, vector &lhs_arg, - vector>> &rhs_arg, - vector &nonstationary_arg, - vector &diff_arg, vector &orig_diff_var_arg, - int max_lag_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 VarRestrictionsStatement : public Statement { private: @@ -541,7 +511,8 @@ public: PlannerObjectiveStatement(SymbolTable &symbol_table, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table, - TrendComponentModelTable &trend_component_model_table_arg); + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); /*! \todo check there are only endogenous variables at the current period in the objective (no exogenous, no lead/lag) */ void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override; diff --git a/src/DataTree.cc b/src/DataTree.cc index b824ccab..a349c383 100644 --- a/src/DataTree.cc +++ b/src/DataTree.cc @@ -29,11 +29,13 @@ DataTree::DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg) : + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : symbol_table(symbol_table_arg), num_constants(num_constants_arg), external_functions_table(external_functions_table_arg), trend_component_model_table(trend_component_model_table_arg), + var_model_table(var_model_table_arg), node_counter(0) { Zero = AddNonNegativeConstant("0"); diff --git a/src/DataTree.hh b/src/DataTree.hh index 7e0635de..55a7c810 100644 --- a/src/DataTree.hh +++ b/src/DataTree.hh @@ -59,6 +59,8 @@ protected: ExternalFunctionsTable &external_functions_table; //! A reference to the trend component model table TrendComponentModelTable &trend_component_model_table; + //! A reference to the VAR model table + VarModelTable &var_model_table; //! num_constant_id -> NumConstNode using num_const_node_map_t = map; @@ -136,7 +138,8 @@ public: DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg); + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); virtual ~DataTree(); diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 157def47..dce1b7cd 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -34,9 +34,10 @@ DynamicModel::DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg) : - ModelTree(symbol_table_arg, num_constants_arg, - external_functions_table_arg, trend_component_model_table_arg), + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : + ModelTree(symbol_table_arg, num_constants_arg, external_functions_table_arg, + trend_component_model_table_arg, var_model_table_arg), max_lag(0), max_lead(0), max_endo_lag(0), max_endo_lead(0), max_exo_lag(0), max_exo_lead(0), @@ -3454,6 +3455,168 @@ DynamicModel::runTrendTest(const eval_context_t &eval_context) testTrendDerivativesEqualToZero(eval_context); } +void +DynamicModel::fillVarModelTable() const +{ + map> eqnums, lhsr; + map> lhs_expr_tr; + map> nonstationaryr; + map>>> rhsr; + map> eqtags = var_model_table.getEqTags(); + + for (const auto &it : eqtags) + { + vector eqnumber, lhs; + vector lhs_expr_t; + vector>> rhs; + vector nonstationary; + + for (const auto &eqtag : it.second) + { + int eqn = -1; + set> lhs_set, lhs_tmp_set, rhs_set; + for (const auto &equation_tag : equation_tags) + if (equation_tag.second.first == "name" + && equation_tag.second.second == eqtag) + { + eqn = equation_tag.first; + break; + } + + if (eqn == -1) + { + cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl; + exit(EXIT_FAILURE); + } + + bool nonstationary_bool = false; + for (const auto &equation_tag : equation_tags) + if (equation_tag.first == eqn) + if (equation_tag.second.first == "data_type" + && equation_tag.second.second == "nonstationary") + { + nonstationary_bool = true; + break; + } + nonstationary.push_back(nonstationary_bool); + + equations[eqn]->get_arg1()->collectDynamicVariables(SymbolType::endogenous, lhs_set); + equations[eqn]->get_arg1()->collectDynamicVariables(SymbolType::exogenous, lhs_tmp_set); + equations[eqn]->get_arg1()->collectDynamicVariables(SymbolType::parameter, lhs_tmp_set); + + if (lhs_set.size() != 1 || !lhs_tmp_set.empty()) + { + cerr << "ERROR: in Equation " << eqtag + << ". A VAR may only have one endogenous variable on the LHS. " << endl; + exit(EXIT_FAILURE); + } + + auto it = lhs_set.begin(); + if (it->second != 0) + { + cerr << "ERROR: in Equation " << eqtag + << ". The variable on the LHS of a VAR may not appear with a lead or a lag. " + << endl; + exit(EXIT_FAILURE); + } + + eqnumber.push_back(eqn); + lhs.push_back(it->first); + lhs_set.clear(); + set lhs_expr_t_set; + equations[eqn]->get_arg1()->collectVARLHSVariable(lhs_expr_t_set); + lhs_expr_t.push_back(*(lhs_expr_t_set.begin())); + + equations[eqn]->get_arg2()->collectDynamicVariables(SymbolType::endogenous, rhs_set); + for (const auto &it : rhs_set) + if (it.second > 0) + { + cerr << "ERROR: in Equation " << eqtag + << ". A VAR may not have leaded or contemporaneous variables on the RHS. " << endl; + exit(EXIT_FAILURE); + } + rhs.push_back(rhs_set); + } + eqnums[it.first] = eqnumber; + lhsr[it.first] = lhs; + lhs_expr_tr[it.first] = lhs_expr_t; + rhsr[it.first] = rhs; + nonstationaryr[it.first] = nonstationary; + } + var_model_table.setEqNums(eqnums); + var_model_table.setLhs(lhsr); + var_model_table.setRhs(rhsr); + var_model_table.setLhsExprT(lhs_expr_tr); + var_model_table.setNonstationary(nonstationaryr); +} + +void +DynamicModel::fillVarModelTableFromOrigModel(StaticModel &static_model) const +{ + map> lags, orig_diff_var; + map> diff; + for (const auto &it : var_model_table.getEqNums()) + { + set lhs; + vector orig_diff_var_vec; + vector diff_vec; + for (auto eqn : it.second) + { + // ensure no leads in equations + if (equations[eqn]->get_arg2()->VarMinLag() <= 0) + { + cerr << "ERROR in VAR model Equation (#" << eqn << "). " + << "Leaded exogenous variables " + << "and leaded or contemporaneous endogenous variables not allowed in VAR" + << endl; + exit(EXIT_FAILURE); + } + + // save lhs variables + equations[eqn]->get_arg1()->collectVARLHSVariable(lhs); + + equations[eqn]->get_arg1()->countDiffs() > 0 ? + diff_vec.push_back(true) : diff_vec.push_back(false); + if (diff_vec.back()) + { + set> diff_set; + equations[eqn]->get_arg1()->collectDynamicVariables(SymbolType::endogenous, diff_set); + + if (diff_set.size() != 1) + { + cerr << "ERROR: problem getting variable for LHS diff operator in equation " + << eqn << endl; + exit(EXIT_FAILURE); + } + orig_diff_var_vec.push_back(diff_set.begin()->first); + } + else + orig_diff_var_vec.push_back(-1); + + } + + if (it.second.size() != lhs.size()) + { + cerr << "ERROR: The LHS variables of the VAR model are not unique" << endl; + exit(EXIT_FAILURE); + } + + set lhs_static; + for(const auto &lh : lhs) + lhs_static.insert(lh->toStatic(static_model)); + + vector max_lag; + for (auto eqn : it.second) + max_lag.push_back(equations[eqn]->get_arg2()->VarMaxLag(static_model, lhs_static)); + lags[it.first] = max_lag; + diff[it.first] = diff_vec; + orig_diff_var[it.first] = orig_diff_var_vec; + } + var_model_table.setDiff(diff); + var_model_table.setMaxLags(lags); + var_model_table.setOrigDiffVar(orig_diff_var); +} + void DynamicModel::fillTrendComponentModelTable() const { @@ -3530,7 +3693,7 @@ DynamicModel::fillTrendComponentModelTable() const if (lhs_set.size() != 1 || !lhs_tmp_set.empty()) { cerr << "ERROR: in Equation " << eqtag - << ". A VAR may only have one endogenous variable on the LHS. " << endl; + << ". A trend component model may only have one endogenous variable on the LHS. " << endl; exit(EXIT_FAILURE); } @@ -3538,7 +3701,7 @@ DynamicModel::fillTrendComponentModelTable() const if (it->second != 0) { cerr << "ERROR: in Equation " << eqtag - << ". The variable on the LHS of a VAR may not appear with a lead or a lag. " + << ". The variable on the LHS of a trend component model may not appear with a lead or a lag. " << endl; exit(EXIT_FAILURE); } @@ -3555,7 +3718,7 @@ DynamicModel::fillTrendComponentModelTable() const if (it->second > 0) { cerr << "ERROR: in Equation " << eqtag - << ". A VAR may not have leaded or contemporaneous variables on the RHS. " << endl; + << ". A trend component model may not have leaded or contemporaneous variables on the RHS. " << endl; exit(EXIT_FAILURE); } rhs.push_back(rhs_set); @@ -3589,7 +3752,7 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel(StaticModel &static_mode // ensure no leads in equations if (equations[eqn]->get_arg2()->VarMinLag() <= 0) { - cerr << "ERROR in VAR Equation (#" << eqn << "). " + cerr << "ERROR in trend component model Equation (#" << eqn << "). " << "Leaded exogenous variables " << "and leaded or contemporaneous endogenous variables not allowed in VAR" << endl; @@ -3621,7 +3784,7 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel(StaticModel &static_mode if (it.second.size() != lhs.size()) { - cerr << "ERROR: The LHS variables of the VAR are not unique" << endl; + cerr << "ERROR: The LHS variables of the trend component model are not unique" << endl; exit(EXIT_FAILURE); } @@ -3640,19 +3803,23 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel(StaticModel &static_mode trend_component_model_table.setMaxLags(lags); trend_component_model_table.setOrigDiffVar(orig_diff_var); } -/* + void -DynamicModel::addEquationsForVar(map> &var_model_info) +DynamicModel::addEquationsForVar() { + if (var_model_table.empty()) + return; + map> var_symbol_list_and_order = + var_model_table.getSymbolListAndOrder(); + // List of endogenous variables and the minimum lag value that must exist in the model equations map var_endos_and_lags, model_endos_and_lags; - for (map>::const_iterator it = var_model_info.begin(); - it != var_model_info.end(); it++) + for (const auto & it : var_symbol_list_and_order) for (auto & equation : equations) - if (equation->isVarModelReferenced(it->first)) + if (equation->isVarModelReferenced(it.first)) { - vector symbol_list = it->second.first.get_symbols(); - int order = it->second.second; + vector symbol_list = it.second.first.get_symbols(); + int order = it.second.second; for (vector::const_iterator it1 = symbol_list.begin(); it1 != symbol_list.end(); it1++) if (order > 2) @@ -3666,7 +3833,8 @@ DynamicModel::addEquationsForVar(map> &var_model_i if (var_endos_and_lags.empty()) return; - // Ensure that the minimum lag value exists in the model equations. If not, add an equation for it + // Ensure that the minimum lag value exists in the model equations. + // If not, add an equation for it for (auto & equation : equations) equation->getEndosAndMaxLags(model_endos_and_lags); @@ -3690,9 +3858,10 @@ DynamicModel::addEquationsForVar(map> &var_model_i } if (count > 0) - cout << "Accounting for var_model lags not in model block: added " << count << " auxiliary variables and equations." << endl; + cout << "Accounting for var_model lags not in model block: added " + << count << " auxiliary variables and equations." << endl; } -*/ + vector DynamicModel::getUndiffLHSForPac(const string &aux_model_name, ExprNode::subst_table_t &diff_subst_table) diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 90814436..da8d6397 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -250,7 +250,11 @@ private: void findPacExpectationEquationNumbers(vector &eqnumber) const; public: - DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, TrendComponentModelTable &trend_component_model_table_arg); + DynamicModel(SymbolTable &symbol_table_arg, + NumericalConstants &num_constants_arg, + ExternalFunctionsTable &external_functions_table_arg, + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); //! Adds a variable node /*! This implementation allows for non-zero lag */ VariableNode *AddVariable(int symb_id, int lag = 0) override; @@ -304,8 +308,14 @@ public: void fillTrendComponentModelTable() const; void fillTrendComponentModelTableFromOrigModel(StaticModel &static_model) const; - //! Add aux equations (and aux variables) for variables declared in var_model at max order if they don't already exist - // void addEquationsForVar(map> &var_model_info); + //! Fill the Var Model Table + void fillVarModelTable() const; + void fillVarModelTableFromOrigModel(StaticModel &static_model) const; + + //! Add aux equations (and aux variables) for variables declared in var_model + //! at max order if they don't already exist + void addEquationsForVar(); + //! Get Pac equation parameter info void walkPacParameters(); //! Add var_model info to pac_expectation nodes diff --git a/src/ModFile.cc b/src/ModFile.cc index 644c7ae3..788801cd 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -30,25 +30,26 @@ #include "ComputingTasks.hh" ModFile::ModFile(WarningConsolidation &warnings_arg) - : trend_component_model_table(symbol_table), - expressions_tree(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - original_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - dynamic_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - trend_dynamic_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - ramsey_FOC_equations_dynamic_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - orig_ramsey_dynamic_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - static_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), - steady_state_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table, static_model), - diff_static_model(symbol_table, num_constants, - external_functions_table, trend_component_model_table), + : var_model_table(symbol_table), + trend_component_model_table(symbol_table), + expressions_tree(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + original_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + dynamic_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + trend_dynamic_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + ramsey_FOC_equations_dynamic_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + orig_ramsey_dynamic_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + static_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), + steady_state_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table, static_model), + diff_static_model(symbol_table, num_constants, external_functions_table, + trend_component_model_table, var_model_table), linear(false), block(false), byte_code(false), use_dll(false), no_static(false), differentiate_forward_vars(false), nonstationary_variables(false), param_used_with_lead_lag(false), warnings(warnings_arg) @@ -374,19 +375,21 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const } // Get all equation tags associated with VARs and Pac Models - string var_model_name; set eqtags; - map> var_model_eq_tags; map> var_model_info_var_expectation; for (auto const &it : trend_component_model_table.getEqTags()) for (auto &it1 : it.second) eqtags.insert(it1); + for (auto const &it : var_model_table.getEqTags()) + for (auto &it1 : it.second) + eqtags.insert(it1); + if (transform_unary_ops) dynamic_model.substituteUnaryOps(diff_static_model); else - // substitute only those unary ops that appear in VAR equations + // substitute only those unary ops that appear in auxiliary model equations dynamic_model.substituteUnaryOps(diff_static_model, eqtags); // Create auxiliary variable and equations for Diff operators that appear in VAR equations @@ -396,8 +399,10 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const // Fill Trend Component Model Table dynamic_model.fillTrendComponentModelTable(); original_model.fillTrendComponentModelTableFromOrigModel(diff_static_model); + dynamic_model.fillVarModelTable(); + original_model.fillVarModelTableFromOrigModel(diff_static_model); - // Var Model + // Pac Model for (auto & statement : statements) { auto *pms = dynamic_cast(statement); @@ -415,10 +420,16 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const lhs = dynamic_model.getUndiffLHSForPac(aux_model_name, diff_subst_table); nonstationary = trend_component_model_table.getNonstationary(aux_model_name); } + else if (var_model_table.isExistingVarModelName(aux_model_name)) + { + max_lag = var_model_table.getMaxLag(aux_model_name) + 1; + lhs = var_model_table.getLhs(aux_model_name); + nonstationary = var_model_table.getNonstationary(aux_model_name); + } else { - // get var_model lhs and max_lag; for now stop with error - cerr << "ERROR: var_models not yet supported for use with pac_model" << endl; + cerr << "Error: aux_model_name not recognized as VAR model or Trend Component model" + << endl; exit(EXIT_FAILURE); } pms->fillUndiffedLHS(lhs); @@ -429,10 +440,9 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const dynamic_model.substitutePacExpectation(); } } - /* - if (!var_model_info_var_expectation.empty()) - dynamic_model.addEquationsForVar(var_model_info_var_expectation); - */ + + dynamic_model.addEquationsForVar(); + if (symbol_table.predeterminedNbr() > 0) dynamic_model.transformPredeterminedVariables(); @@ -507,35 +517,17 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const continue; auto &model_name = vems->model_name; - - /* Find the corresponding VM statement and extract information for it; - ideally we should have a VarModelTable for that purpose */ - VarModelStatement *vms = nullptr; - for (auto & statement2 : statements) - if ((vms = dynamic_cast(statement2)) - && vms->name == vems->var_model_name) - break; - if (!vms) + if (!var_model_table.isExistingVarModelName(vems->var_model_name)) { - cerr << "ERROR: var_expectation_model " << model_name << " refers to nonexistent " << vems->var_model_name << " var_model" << endl; + cerr << "ERROR: var_expectation_model " << model_name + << " refers to nonexistent " << vems->var_model_name << " var_model" << endl; exit(EXIT_FAILURE); } - /* The code below is duplicated further below in this function; but we - can't avoid that until the collecting of information about VARs is - moved *before* lead/lag substitutions (or even better, in checkPass()) */ - vector lhs_expr_t; - vector lhs, eqnumber; - vector>> rhs; - vector nonstationary; - vector eqtags{var_model_eq_tags[var_model_name]}; - /* - dynamic_model.getVarModelVariablesFromEqTags(eqtags, - eqnumber, lhs, lhs_expr_t, rhs, nonstationary); - */ - int max_lag = trend_component_model_table.getMaxLag(var_model_name); /* Create auxiliary parameters and the expression to be substituted to the var_expectations statement */ + int max_lag = var_model_table.getMaxLag(vems->var_model_name); + vector lhs = var_model_table.getLhs(vems->var_model_name); auto subst_expr = dynamic_model.Zero; for (int lag = 0; lag < max_lag; lag++) for (auto variable : lhs) @@ -580,35 +572,8 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const dynamic_model.substituteEndoLagGreaterThanTwo(true); } - /* TODO: most of this should rather be done in checkPass(). Also we should - probably add a VarModelTable class (similar to SymbolTable) for storing all - this information about VAR models, instead of putting it inside the - Statement(s) classes */ dynamic_model.fillTrendComponentModelTable(); - /* - for (auto & statement : statements) - { - auto *vms = dynamic_cast(statement); - if (vms != nullptr) - { - string var_model_name; - //vms->getVarModelInfo(var_model_name, var_model_info_var_expectation, var_model_eq_tags); - vector lhs_expr_t; - vector lhs, eqnumber, orig_diff_var; - vector>> rhs; - vector nonstationary, diff; - vector eqtags = var_model_eq_tags[var_model_name]; - dynamic_model.getVarModelVariablesFromEqTags(eqtags, - eqnumber, lhs, lhs_expr_t, rhs, nonstationary); - int max_lag = trend_component_model_table.getMaxLag(var_model_name); - // int max_lag = original_model.getVarMaxLag(diff_static_model, eqnumber); - //original_model.getVarLhsDiffAndInfo(eqnumber, diff, orig_diff_var); - vms->fillVarModelInfoFromEquations(eqnumber, lhs, rhs, nonstationary, - diff, orig_diff_var, max_lag); - } - } -*/ if (differentiate_forward_vars) dynamic_model.differentiateForwardVars(differentiate_forward_vars_subset); @@ -1315,10 +1280,18 @@ ModFile::writeJsonOutputParsingCheck(const string &basename, JsonFileOutputType output << ", "; dynamic_model.writeJsonOutput(output); + if (!statements.empty() + || !var_model_table.empty() || !trend_component_model_table.empty()) { output << ", \"statements\": ["; + if (!var_model_table.empty()) + { + var_model_table.writeJsonOutput(output); + output << ", "; + } + if (!trend_component_model_table.empty()) { trend_component_model_table.writeJsonOutput(output); diff --git a/src/ModFile.hh b/src/ModFile.hh index 2e33b74e..f15ccbd8 100644 --- a/src/ModFile.hh +++ b/src/ModFile.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2017 Dynare Team + * Copyright (C) 2006-2018 Dynare Team * * This file is part of Dynare. * @@ -52,6 +52,8 @@ public: ExternalFunctionsTable external_functions_table; //! Numerical constants table NumericalConstants num_constants; + //! Var Model Table used for storing info about trend component models + VarModelTable var_model_table; //! Trend Component Model Table used for storing info about trend component models TrendComponentModelTable trend_component_model_table; //! Expressions outside model block diff --git a/src/ModelTree.cc b/src/ModelTree.cc index 401ad86b..8fa85271 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -1004,9 +1004,10 @@ ModelTree::BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vec ModelTree::ModelTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg) : - DataTree(symbol_table_arg, num_constants_arg, - external_functions_table_arg, trend_component_model_table_arg), + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : + DataTree(symbol_table_arg, num_constants_arg, external_functions_table_arg, + trend_component_model_table_arg, var_model_table_arg), cutoff(1e-15), mfs(0) diff --git a/src/ModelTree.hh b/src/ModelTree.hh index 84772d5b..97594d66 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -324,7 +324,8 @@ public: ModelTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg); + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); //! Absolute value under which a number is considered to be zero double cutoff; //! Compute the minimum feedback set diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index a86b37ff..80bc0642 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -349,7 +349,8 @@ ParsingDriver::declare_or_change_type(SymbolType new_type, const string &name) auto dm = make_unique(mod_file->symbol_table, mod_file->num_constants, mod_file->external_functions_table, - mod_file->trend_component_model_table); + mod_file->trend_component_model_table, + mod_file->var_model_table); mod_file->dynamic_model.updateAfterVariableChange(*dm); // remove error messages @@ -1444,25 +1445,34 @@ ParsingDriver::trend_component_model() void ParsingDriver::var_model() { - OptionsList::string_options_t::const_iterator it = options_list.string_options.find("var.model_name"); - if (it == options_list.string_options.end()) + const auto its = options_list.string_options.find("var.model_name"); + if (its == options_list.string_options.end()) error("You must pass the model_name option to the var_model statement."); - auto name = it->second; - - if (options_list.vector_str_options.find("var.eqtags") != options_list.vector_str_options.end()) - if (!symbol_list.empty()) - error("You cannot pass a symbol list when passing equation tags to the var_model statement"); - else if (options_list.num_options.find("var.order") != options_list.num_options.end()) - error("You cannot pass the order option when passing equation tags to the var_model statement"); + auto name = its->second; + int order = 0; + const auto itn = options_list.num_options.find("var.order"); + if (itn != options_list.num_options.end()) + order = stoi(itn->second); + else if (!symbol_list.empty()) - if (options_list.num_options.find("var.order") == options_list.num_options.end()) - error("You must pass the order option when passing a symbol list to the var_model statement"); + error("You must pass the order option when passing a symbol list to the var_model statement"); - mod_file->addStatement(new VarModelStatement(symbol_list, options_list, name, mod_file->symbol_table)); - var_map[it->second] = symbol_list.getSymbols(); + vector eqtags; + const auto itvs = options_list.vector_str_options.find("var.eqtags"); + if (itvs != options_list.vector_str_options.end()) + { + eqtags = itvs->second; + if (!symbol_list.empty()) + error("You cannot pass a symbol list when passing equation tags to the var_model statement"); + else if (itn != options_list.num_options.end()) + error("You cannot pass the order option when passing equation tags to the var_model statement"); + } + + mod_file->var_model_table.addVarModel(name, eqtags, make_pair(symbol_list, order)); symbol_list.clear(); options_list.clear(); + var_map[its->second] = symbol_list.getSymbols(); } void @@ -2071,8 +2081,8 @@ ParsingDriver::begin_planner_objective() planner_objective_statement = new PlannerObjectiveStatement(mod_file->symbol_table, mod_file->num_constants, mod_file->external_functions_table, - mod_file->trend_component_model_table); - + mod_file->trend_component_model_table, + mod_file->var_model_table); set_current_data_tree(&planner_objective_statement->getPlannerObjective()); } diff --git a/src/StaticModel.cc b/src/StaticModel.cc index f9834c2f..32ac5ccb 100644 --- a/src/StaticModel.cc +++ b/src/StaticModel.cc @@ -32,9 +32,10 @@ StaticModel::StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg) : - ModelTree(symbol_table_arg, num_constants_arg, - external_functions_table_arg, trend_component_model_table_arg), + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg) : + ModelTree(symbol_table_arg, num_constants_arg, external_functions_table_arg, + trend_component_model_table_arg, var_model_table_arg), global_temporary_terms(true) { } diff --git a/src/StaticModel.hh b/src/StaticModel.hh index 5374739d..341b36e5 100644 --- a/src/StaticModel.hh +++ b/src/StaticModel.hh @@ -163,7 +163,8 @@ public: StaticModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table_arg, - TrendComponentModelTable &trend_component_model_table_arg); + TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg); //! Writes information on block decomposition when relevant void writeOutput(ostream &output, bool block) const; diff --git a/src/SteadyStateModel.cc b/src/SteadyStateModel.cc index 282d8e1b..0291135f 100644 --- a/src/SteadyStateModel.cc +++ b/src/SteadyStateModel.cc @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2017 Dynare Team + * Copyright (C) 2010-2018 Dynare Team * * This file is part of Dynare. * @@ -26,9 +26,10 @@ SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg, const StaticModel &static_model_arg) : - DataTree(symbol_table_arg, num_constants_arg, - external_functions_table_arg, trend_component_model_table_arg), + DataTree(symbol_table_arg, num_constants_arg, external_functions_table_arg, + trend_component_model_table_arg, var_model_table_arg), static_model(static_model_arg) { } diff --git a/src/SteadyStateModel.hh b/src/SteadyStateModel.hh index d3b4e2db..bf436766 100644 --- a/src/SteadyStateModel.hh +++ b/src/SteadyStateModel.hh @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010-2017 Dynare Team + * Copyright (C) 2010-2018 Dynare Team * * This file is part of Dynare. * @@ -39,6 +39,7 @@ public: NumericalConstants &num_constants_arg, ExternalFunctionsTable &external_functions_table_arg, TrendComponentModelTable &trend_component_model_table_arg, + VarModelTable &var_model_table_arg, const StaticModel &static_model_arg); //! Add an expression of the form "var = expr;" void addDefinition(int symb_id, expr_t expr); diff --git a/src/SubModel.cc b/src/SubModel.cc index 0e399796..731993e2 100644 --- a/src/SubModel.cc +++ b/src/SubModel.cc @@ -301,3 +301,241 @@ TrendComponentModelTable::writeJsonOutput(ostream &output) const output << "]}"; } } + +VarModelTable::VarModelTable(SymbolTable &symbol_table_arg) : + symbol_table(symbol_table_arg) +{ +} + +void +VarModelTable::addVarModel(string name_arg, vector eqtags_arg, + pair symbol_list_and_order_arg) +{ + if (isExistingVarModelName(name_arg)) + { + cerr << "Error: a VAR model already exists with the name " << name_arg << endl; + exit(EXIT_FAILURE); + } + + eqtags[name_arg] = move(eqtags_arg); + symbol_list_and_order[name_arg] = move(symbol_list_and_order_arg); + names.insert(move(name_arg)); +} + +map> +VarModelTable::getSymbolListAndOrder() const +{ + return symbol_list_and_order; +} + +void +VarModelTable::writeOutput(ostream &output) const +{ + for (const auto &name : names) + { + output << "M_.var." << name << ".model_name = '" << name << "';" << endl; + if (!symbol_list_and_order.empty()) + { + symbol_list_and_order.at(name).first.writeOutput("M_.var." + name + ".var_list_", output); + output << "M_.var." << name << ".order = " + << symbol_list_and_order.at(name).second << ";" << endl; + } + output << "M_.var." << name << ".eqtags = {"; + for (const auto &it : eqtags.at(name)) + output << "'" << it << "'; "; + output << "};" << endl + << "M_.var." << name << ".eqn = ["; + for (auto it : eqnums.at(name)) + output << it + 1 << " "; + output << "];" << endl + << "M_.var." << name << ".lhs = ["; + for (auto it : lhs.at(name)) + output << symbol_table.getTypeSpecificID(it) + 1 << " "; + output << "];" << endl + << "M_.var." << name << ".max_lag = ["; + for (auto it : max_lags.at(name)) + output << it << " "; + output << "];" << endl + << "M_.var." << name << ".diff = ["; + for (const auto &it : diff.at(name)) + output << (it ? "true" : "false") << " "; + output << "];" << endl + << "M_.var." << name << ".orig_diff_var = ["; + for (auto it : orig_diff_var.at(name)) + output << (it >= 0 ? symbol_table.getTypeSpecificID(it) + 1 : -1) << " "; + output << "];" << endl; + + int i = 1; + for (const auto &it : rhs.at(name)) + { + output << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.var = ["; + for (const auto &it1 : it) + output << symbol_table.getTypeSpecificID(it1.first) + 1 << " "; + output << "];" << endl + << "M_.var." << name << ".rhs.vars_at_eq{" << i << "}.lag = ["; + for (const auto &it1 : it) + output << it1.second << " "; + output << "];" << endl; + + i++; + } + } +} + +void +VarModelTable::writeJsonOutput(ostream &output) const +{ + for (const auto &name : names) + { + if (name != *(names.begin())) + output << ", "; + output << "{\"statementName\": \"var_model\"," + << "\"model_name\": \"" << name << "\","; + if (symbol_list_and_order.empty()) + { + output << "\"eqtags\": ["; + for (const auto &it : eqtags.at(name)) + { + output << "\"" << it << "\""; + if (&it != &eqtags.at(name).back()) + output << ", "; + } + output << "]"; + } + else + { + output << "\"order\": \"" << symbol_list_and_order.at(name).second << "\","; + } + output << "}"; + } +} + +map> +VarModelTable::getEqTags() const +{ + return eqtags; +} + +vector +VarModelTable::getEqTags(const string &name_arg) const +{ + checkModelName(name_arg); + return eqtags.find(name_arg)->second; +} + +void +VarModelTable::checkModelName(const string &name_arg) const +{ + if (!isExistingVarModelName(name_arg)) + { + cerr << name_arg + << " is not a recognized equation tag of a VAR model equation" << endl; + exit(EXIT_FAILURE); + } +} + +void +VarModelTable::setEqNums(map> eqnums_arg) +{ + eqnums = move(eqnums_arg); +} + +void +VarModelTable::setLhs(map> lhs_arg) +{ + lhs = move(lhs_arg); +} + +void +VarModelTable::setRhs(map>>> rhs_arg) +{ + rhs = move(rhs_arg); +} + +void +VarModelTable::setLhsExprT(map> lhs_expr_t_arg) +{ + lhs_expr_t = move(lhs_expr_t_arg); +} + +void +VarModelTable::setNonstationary(map> nonstationary_arg) +{ + nonstationary = move(nonstationary_arg); +} + +map> +VarModelTable::getEqNums() const +{ + return eqnums; +} + +vector +VarModelTable::getEqNums(const string &name_arg) const +{ + checkModelName(name_arg); + return eqnums.find(name_arg)->second; +} + +void +VarModelTable::setMaxLags(map> max_lags_arg) +{ + max_lags = move(max_lags_arg); +} + +void +VarModelTable::setDiff(map> diff_arg) +{ + diff = move(diff_arg); +} + +void +VarModelTable::setOrigDiffVar(map> orig_diff_var_arg) +{ + orig_diff_var = move(orig_diff_var_arg); +} + +vector +VarModelTable::getMaxLags(const string &name_arg) const +{ + checkModelName(name_arg); + return max_lags.find(name_arg)->second; +} + +int +VarModelTable::getMaxLag(const string &name_arg) const +{ + int max_lag_int = 0; + for (auto it : getMaxLags(name_arg)) + max_lag_int = max(max_lag_int, it); + return max_lag_int; +} + +vector +VarModelTable::getLhs(const string &name_arg) const +{ + checkModelName(name_arg); + return lhs.find(name_arg)->second; +} + +vector +VarModelTable::getNonstationary(const string &name_arg) const +{ + checkModelName(name_arg); + return nonstationary.find(name_arg)->second; +} + +vector>> +VarModelTable::getRhs(const string &name_arg) const +{ + checkModelName(name_arg); + return rhs.find(name_arg)->second; +} + + +vector +VarModelTable::getLhsExprT(const string &name_arg) const +{ + checkModelName(name_arg); + return lhs_expr_t.find(name_arg)->second; +} diff --git a/src/SubModel.hh b/src/SubModel.hh index d03ad0fd..d8b691f0 100644 --- a/src/SubModel.hh +++ b/src/SubModel.hh @@ -101,4 +101,69 @@ TrendComponentModelTable::empty() const return names.empty(); } + +class VarModelTable +{ +private: + SymbolTable &symbol_table; + set names; + map> symbol_list_and_order; + map> eqtags; + map> eqnums, max_lags, lhs, orig_diff_var; + map>>> rhs; + map> diff, nonstationary; + map> lhs_expr_t; +public: + VarModelTable(SymbolTable &symbol_table_arg); + + //! Add a trend component model + void addVarModel(string name, vector eqtags, + pair symbol_list_and_order_arg); + + inline bool isExistingVarModelName(const string &name_arg) const; + inline bool empty() const; + + map> getEqTags() const; + vector getEqTags(const string &name_arg) const; + map> getEqNums() const; + vector getEqNums(const string &name_arg) const; + vector getMaxLags(const string &name_arg) const; + int getMaxLag(const string &name_arg) const; + vector getLhs(const string &name_arg) const; + vector getNonstationary(const string &name_arg) const; + map> getSymbolListAndOrder() const; + vector>> getRhs(const string &name_arg) const; + vector getLhsExprT(const string &name_arg) const; + + void setEqNums(map> eqnums_arg); + void setLhs(map> lhs_arg); + void setRhs(map>>> rhs_arg); + void setLhsExprT(map> lhs_expr_t_arg); + void setNonstationary(map> nonstationary_arg); + void setDiff(map> diff_arg); + void setMaxLags(map> max_lags_arg); + void setOrigDiffVar(map> orig_diff_var_arg); + + //! Write output of this class + void writeOutput(ostream &output) const; + + //! Write JSON Output + void writeJsonOutput(ostream &output) const; + +private: + void checkModelName(const string &name_arg) const; +}; + +inline bool +VarModelTable::isExistingVarModelName(const string &name_arg) const +{ + return names.find(name_arg) == names.end() ? false : true; +} + +inline bool +VarModelTable::empty() const +{ + return names.empty(); +} + #endif