From 92d3b8166ab7df1bdfabca416efad6246c4e6399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Thu, 5 May 2022 18:39:27 +0200 Subject: [PATCH] C++17 modernization: use std::optional for equation line numbers --- src/DynamicModel.cc | 49 ++++++++++++++++++++++++--------------------- src/DynamicModel.hh | 8 ++++---- src/ModelTree.cc | 18 ++++++++++------- src/ModelTree.hh | 10 +++++---- src/SubModel.cc | 2 +- 5 files changed, 48 insertions(+), 39 deletions(-) diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 15daa76c..1fa87a1f 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -2475,7 +2475,7 @@ vector<int> DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type, vector<BinaryOpNode *> &all_equations, - vector<int> &all_equations_lineno, + vector<optional<int>> &all_equations_lineno, EquationTags &all_equation_tags, bool static_equations) const { if (all_equations.empty()) @@ -2507,7 +2507,7 @@ DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag // remove from equations, equations_lineno, equation_tags vector<BinaryOpNode *> new_equations; - vector<int> new_equations_lineno; + vector<optional<int>> new_equations_lineno; map<int, int> old_eqn_num_2_new; vector<int> excluded_vars; for (size_t i = 0; i < all_equations.size(); i++) @@ -3980,7 +3980,7 @@ DynamicModel::computePacModelConsistentExpectationSubstitution(const string &nam auto neweq = AddEqual(const_cast<VariableNode *>(target_base_diff_node), AddMinus(create_target_lag(0), create_target_lag(-1))); - addEquation(neweq, -1); + addEquation(neweq, nullopt); addAuxEquation(neweq); neqs++; } @@ -3994,7 +3994,7 @@ DynamicModel::computePacModelConsistentExpectationSubstitution(const string &nam last_aux_var->symb_id, 1); VariableNode *current_aux_var = AddVariable(symb_id); auto neweq = AddEqual(current_aux_var, AddVariable(last_aux_var->symb_id, 1)); - addEquation(neweq, -1); + addEquation(neweq, nullopt); addAuxEquation(neweq); last_aux_var = current_aux_var; target_aux_var_to_add[i] = current_aux_var; @@ -4023,7 +4023,7 @@ DynamicModel::computePacModelConsistentExpectationSubstitution(const string &nam } auto neweq = AddEqual(AddVariable(mce_z1_symb_id), AddMinus(AddTimes(A, AddMinus(const_cast<VariableNode *>(target_base_diff_node), fs)), fp)); - addEquation(neweq, -1); + addEquation(neweq, nullopt); /* This equation is not added to the list of auxiliary equations, because it is recursive, and this would in particular break dynamic_set_auxiliary_series.m */ neqs++; @@ -4087,7 +4087,7 @@ DynamicModel::computePacBackwardExpectationSubstitution(const string &name, auxname = "pac_expectation_" + name; int expect_var_id = symbol_table.addPacExpectationAuxiliaryVar(auxname, subExpr); expr_t neweq = AddEqual(AddVariable(expect_var_id), subExpr); - addEquation(neweq, -1); + addEquation(neweq, nullopt); addAuxEquation(neweq); pac_aux_var_symb_ids[name] = expect_var_id; pac_expectation_substitution[name] = AddVariable(expect_var_id); @@ -4155,7 +4155,7 @@ DynamicModel::computePacBackwardExpectationSubstitutionWithComponents(const stri // Add the equation defining the auxiliary variable for this component expr_t neweq = AddEqual(auxvar, auxdef); - addEquation(neweq, -1); + addEquation(neweq, nullopt); addAuxEquation(neweq); // Update the expression to be substituted for the pac_expectation operator @@ -4673,7 +4673,7 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) // Add Planner Objective to equations so that it appears in Lagrangian assert(static_model.equations.size() == 1); - addEquation(static_model.equations[0]->clone(*this), -1); + addEquation(static_model.equations[0]->clone(*this), nullopt); // Get max endo lead and max endo lag set<pair<int, int>> dynvars; @@ -4721,14 +4721,14 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) // Prepare derivation of the Lagrangian clearEquations(); - addEquation(AddEqual(lagrangian, Zero), -1); + addEquation(AddEqual(lagrangian, Zero), nullopt); computeDerivIDs(); /* Compute Lagrangian derivatives. Also restore line numbers and tags for FOCs w.r.t. a Lagrange multiplier (i.e. a FOC identical to an equation of the original model) */ vector<expr_t> neweqs; - vector<int> neweqs_lineno; + vector<optional<int>> neweqs_lineno; map<int, map<string, string>> neweqs_tags; for (auto &[symb_id_and_lag, deriv_id] : deriv_id_table) { @@ -4748,7 +4748,7 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) neweqs_tags[neweqs.size()-1] = tags; } else - neweqs_lineno.push_back(-1); + neweqs_lineno.push_back(nullopt); } } @@ -5060,8 +5060,10 @@ DynamicModel::testTrendDerivativesEqualToZero(const eval_context_t &eval_context double nearZero = testeq->getDerivative(endogit.second)->eval(eval_context); // eval d F / d Trend d Endog if (fabs(nearZero) > balanced_growth_test_tol) { - cerr << "ERROR: trends not compatible with balanced growth path; the second-order cross partial of equation " << eq + 1 << " (line " - << equations_lineno[eq] << ") w.r.t. trend variable " + cerr << "ERROR: trends not compatible with balanced growth path; the second-order cross partial of equation " << eq + 1; + if (equations_lineno[eq]) + cerr << " (line " << *equations_lineno[eq] << ")"; + cerr << "w.r.t. trend variable " << symbol_table.getName(it.first.first) << " and endogenous variable " << symbol_table.getName(endogit.first.first) << " is not null (abs. value = " << fabs(nearZero) << "). If you are confident that your trends are correctly specified, you can raise the value of option 'balanced_growth_test_tol' in the 'model' block." << endl; @@ -5505,7 +5507,7 @@ DynamicModel::substituteLeadLagInternal(AuxVarType type, bool deterministic_mode // Add new equations for (auto &neweq : neweqs) { - addEquation(neweq, -1); + addEquation(neweq, nullopt); aux_equations.push_back(neweq); } @@ -5652,7 +5654,7 @@ DynamicModel::substituteUnaryOps(const set<int> &eqnumbers, VarExpectationModelT // Add new equations for (auto &neweq : neweqs) { - addEquation(neweq, -1); + addEquation(neweq, nullopt); aux_equations.push_back(neweq); } @@ -5707,7 +5709,7 @@ DynamicModel::substituteDiff(VarExpectationModelTable &var_expectation_model_tab // Add new equations for (auto &neweq : neweqs) { - addEquation(neweq, -1); + addEquation(neweq, nullopt); aux_equations.push_back(neweq); } @@ -5740,7 +5742,7 @@ DynamicModel::substituteExpectation(bool partial_information_model) // Add new equations for (auto &neweq : neweqs) { - addEquation(neweq, -1); + addEquation(neweq, nullopt); aux_equations.push_back(neweq); } @@ -5800,7 +5802,7 @@ DynamicModel::substituteLogTransform() */ addAuxEquation(AddEqual(AddVariable(aux_symb_id), aux_def)); addEquation(AddEqual(AddVariable(symb_id), AddExp(AddVariable(aux_symb_id))), - -1, {}); + nullopt, {}); } } @@ -5920,14 +5922,14 @@ DynamicModel::fillEvalContext(eval_context_t &eval_context) const } void -DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const map<string, string> &eq_tags) +DynamicModel::addStaticOnlyEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags) { auto beq = dynamic_cast<BinaryOpNode *>(eq); assert(beq && beq->op_code == BinaryOpcode::equal); static_only_equations_equation_tags.add(static_only_equations.size(), eq_tags); static_only_equations.push_back(beq); - static_only_equations_lineno.push_back(lineno); + static_only_equations_lineno.push_back(move(lineno)); } size_t @@ -5943,7 +5945,7 @@ DynamicModel::dynamicOnlyEquationsNbr() const } void -DynamicModel::addOccbinEquation(expr_t eq, int lineno, const map<string, string> &eq_tags, const vector<string> ®imes_bind, const vector<string> ®imes_relax) +DynamicModel::addOccbinEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags, const vector<string> ®imes_bind, const vector<string> ®imes_relax) { auto beq = dynamic_cast<BinaryOpNode *>(eq); assert(beq && beq->op_code == BinaryOpcode::equal); @@ -6080,8 +6082,9 @@ DynamicModel::writeJsonAST(ostream &output) const if (eq != 0) output << ", "; - output << R"({ "number":)" << eq - << R"(, "line":)" << equations_lineno[eq]; + output << R"({ "number":)" << eq; + if (equations_lineno[eq]) + output << R"(, "line":)" << *equations_lineno[eq]; equation_tags.writeJsonAST(output, eq); diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index d858b739..c53cf524 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -51,7 +51,7 @@ private: vector<BinaryOpNode *> static_only_equations; //! Stores line numbers of equations declared as [static] - vector<int> static_only_equations_lineno; + vector<optional<int>> static_only_equations_lineno; //! Stores the equation tags of equations declared as [static] EquationTags static_only_equations_equation_tags; @@ -283,7 +283,7 @@ private: vector<int> removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type, vector<BinaryOpNode *> &all_equations, - vector<int> &all_equations_lineno, + vector<optional<int>> &all_equations_lineno, EquationTags &all_equation_tags, bool static_equations) const; @@ -444,7 +444,7 @@ public: void replaceMyEquations(DynamicModel &dynamic_model) const; //! Adds an equation marked as [static] - void addStaticOnlyEquation(expr_t eq, int lineno, const map<string, string> &eq_tags); + void addStaticOnlyEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags); //! Returns number of static only equations size_t staticOnlyEquationsNbr() const; @@ -457,7 +457,7 @@ public: auxiliary parameters have already been added to the symbol table. It also assumes that the “bind” and “relax” tags have been cleared from eq_tags. */ - void addOccbinEquation(expr_t eq, int lineno, const map<string, string> &eq_tags, const vector<string> ®imes_bind, const vector<string> ®imes_relax); + void addOccbinEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags, const vector<string> ®imes_bind, const vector<string> ®imes_relax); //! Writes LaTeX file with the equations of the dynamic model void writeLatexFile(const string &basename, bool write_equation_tags) const; diff --git a/src/ModelTree.cc b/src/ModelTree.cc index 1998fbfa..d82a32b7 100644 --- a/src/ModelTree.cc +++ b/src/ModelTree.cc @@ -343,7 +343,10 @@ ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context) const } catch (ExprNode::EvalException &e) { - cerr << "ERROR: evaluation of Jacobian failed for equation " << eq+1 << " (line " << equations_lineno[eq] << ") and variable " << symbol_table.getName(symb) << "(" << lag << ") [" << symb << "] !" << endl; + cerr << "ERROR: evaluation of Jacobian failed for equation " << eq+1; + if (equations_lineno[eq]) + cerr << " (line " << *equations_lineno[eq] << ")"; + cerr << " and variable " << symbol_table.getName(symb) << "(" << lag << ") [" << symb << "] !" << endl; d1->writeOutput(cerr, ExprNodeOutputType::matlabDynamicModel, {}, {}); cerr << endl; exit(EXIT_FAILURE); @@ -1539,13 +1542,13 @@ ModelTree::writeLatexModelFile(const string &mod_basename, const string &latex_b } void -ModelTree::addEquation(expr_t eq, int lineno) +ModelTree::addEquation(expr_t eq, optional<int> lineno) { auto beq = dynamic_cast<BinaryOpNode *>(eq); assert(beq && beq->op_code == BinaryOpcode::equal); equations.push_back(beq); - equations_lineno.push_back(lineno); + equations_lineno.push_back(move(lineno)); } void @@ -1558,10 +1561,10 @@ ModelTree::findConstantEquationsWithoutMcpTag(map<VariableNode *, NumConstNode * } void -ModelTree::addEquation(expr_t eq, int lineno, const map<string, string> &eq_tags) +ModelTree::addEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags) { equation_tags.add(equations.size(), eq_tags); - addEquation(eq, lineno); + addEquation(eq, move(lineno)); } void @@ -1746,8 +1749,9 @@ ModelTree::writeJsonModelEquations(ostream &output, bool residuals) const lhs->writeJsonOutput(output, {}, {}); output << R"(", "rhs": ")"; rhs->writeJsonOutput(output, {}, {}); - output << R"(")" - << R"(, "line": )" << equations_lineno[eq]; + output << R"(")"; + if (equations_lineno[eq]) + output << R"(, "line": )" << *equations_lineno[eq]; if (auto eqtags = getEquationTags(eq); !eqtags.empty()) diff --git a/src/ModelTree.hh b/src/ModelTree.hh index c7f17aea..5aeee110 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -27,6 +27,7 @@ #include <ostream> #include <array> #include <filesystem> +#include <optional> #include "DataTree.hh" #include "EquationTags.hh" @@ -76,8 +77,9 @@ protected: */ //! Stores declared and generated auxiliary equations vector<BinaryOpNode *> equations; - //! Stores line numbers of declared equations; -1 means undefined - vector<int> equations_lineno; + /* Stores line numbers of declared equations; undefined in some cases (e.g. + auxiliary equations) */ + vector<optional<int>> equations_lineno; //! Stores equation tags EquationTags equation_tags; /* @@ -422,9 +424,9 @@ public: default value = 0 */ int mfs{0}; //! Declare a node as an equation of the model; also give its line number - void addEquation(expr_t eq, int lineno); + void addEquation(expr_t eq, optional<int> lineno); //! Declare a node as an equation of the model, also giving its tags - void addEquation(expr_t eq, int lineno, const map<string, string> &eq_tags); + void addEquation(expr_t eq, optional<int> lineno, const map<string, string> &eq_tags); //! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations void addAuxEquation(expr_t eq); //! Returns the number of equations in the model diff --git a/src/SubModel.cc b/src/SubModel.cc index f80b3b47..cc3074e6 100644 --- a/src/SubModel.cc +++ b/src/SubModel.cc @@ -1273,7 +1273,7 @@ PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes, yns = dynamic_model.AddPlus(yns, dynamic_model.AddTimes(coeff, component)); int target_nonstationary_id = symbol_table.addPacTargetNonstationaryAuxiliaryVar(get<1>(target_info[name]), yns); expr_t neweq = dynamic_model.AddEqual(dynamic_model.AddVariable(target_nonstationary_id), yns); - dynamic_model.addEquation(neweq, -1); + dynamic_model.addEquation(neweq, nullopt); dynamic_model.addAuxEquation(neweq); /* Perform the substitution of the pac_target_nonstationary operator. -- GitLab