From 4e2538a2a2c141352e6de6dd6538d51854018f70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Mon, 6 Jan 2020 18:26:35 +0100 Subject: [PATCH] Ensure original tags and line numbers are preserved with ramsey_model In particular, introduce a method for clearing all equations, so that tags and line numbers are also cleared. Ref. dynare#1685 --- src/DynamicModel.cc | 71 ++++++++++++++++++++++++++++++++++----------- src/DynamicModel.hh | 4 +++ src/ModelTree.hh | 2 ++ src/SymbolTable.cc | 9 ++++++ src/SymbolTable.hh | 2 ++ 5 files changed, 71 insertions(+), 17 deletions(-) diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 14135914..6116b85a 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -5516,13 +5516,25 @@ DynamicModel::writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputTyp } } +void +DynamicModel::clearEquations() +{ + equations.clear(); + equations_lineno.clear(); + equation_tags.clear(); + equation_tags_xref.clear(); +} + void DynamicModel::replaceMyEquations(DynamicModel &dynamic_model) const { - dynamic_model.equations.clear(); + dynamic_model.clearEquations(); + for (size_t i = 0; i < equations.size(); i++) - dynamic_model.addEquation(equations[i]->clone(dynamic_model), - equations_lineno[i]); + dynamic_model.addEquation(equations[i]->clone(dynamic_model), equations_lineno[i]); + + dynamic_model.equation_tags = equation_tags; + dynamic_model.equation_tags_xref = equation_tags_xref; } void @@ -5539,9 +5551,9 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) } cout << "Ramsey Problem: added " << i << " Multipliers." << endl; - // Add Planner Objective to equations to include in computeDerivIDs + // Add Planner Objective to equations so that it appears in Lagrangian assert(static_model.equations.size() == 1); - addEquation(static_model.equations[0]->clone(*this), static_model.equations_lineno[0]); + addEquation(static_model.equations[0]->clone(*this), -1); // Get max endo lead and max endo lag set<pair<int, int>> dynvars; @@ -5550,9 +5562,8 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) for (auto &equation : equations) equation->collectDynamicVariables(SymbolType::endogenous, dynvars); - for (const auto &dynvar : dynvars) + for (const auto &[symb_id, lag] : dynvars) { - int lag = dynvar.second; if (max_eq_lead < lag) max_eq_lead = lag; else if (-max_eq_lag > lag) @@ -5584,21 +5595,47 @@ DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model) equations[i]->getNonZeroPartofEquation()->decreaseLeadsLags(lag)), lagrangian); } - equations.clear(); + // Save line numbers and tags, see below + auto old_equations_lineno = equations_lineno; + auto old_equation_tags = equation_tags; + + // Prepare derivation of the Lagrangian + clearEquations(); addEquation(AddEqual(lagrangian, Zero), -1); computeDerivIDs(); - //Compute derivatives and overwrite equations + /* 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; - for (auto &it : deriv_id_table) - // For all endogenous variables with zero lag - if (symbol_table.getType(it.first.first) == SymbolType::endogenous && it.first.second == 0) - neweqs.push_back(AddEqual(equations[0]->getNonZeroPartofEquation()->getDerivative(it.second), Zero)); + vector<int> neweqs_lineno; + map<int, vector<pair<string, string>>> neweqs_tags; + for (auto &[symb_id_and_lag, deriv_id] : deriv_id_table) + { + auto &[symb_id, lag] = symb_id_and_lag; + if (symbol_table.getType(symb_id) == SymbolType::endogenous && lag == 0) + { + neweqs.push_back(AddEqual(equations[0]->getNonZeroPartofEquation()->getDerivative(deriv_id), Zero)); + if (int i = symbol_table.getEquationNumberForMultiplier(symb_id); + i != -1) + { + // This is a derivative w.r.t. a Lagrange multiplier + neweqs_lineno.push_back(old_equations_lineno[i]); + vector<pair<string, string>> tags; + for (auto &[j, tagpair] : old_equation_tags) + if (j == i) + tags.emplace_back(tagpair); + neweqs_tags[neweqs.size()-1] = tags; + } + else + neweqs_lineno.push_back(-1); + } + } - // Add new equations - equations.clear(); - for (auto &neweq : neweqs) - addEquation(neweq, -1); + // Overwrite equations with the Lagrangian derivatives + clearEquations(); + for (size_t i = 0; i < neweqs.size(); i++) + addEquation(neweqs[i], neweqs_lineno[i], neweqs_tags[i]); } void diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 9a2db5c7..487017a6 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -446,6 +446,10 @@ public: //! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous void computeRamseyPolicyFOCs(const StaticModel &static_model); + + //! Clears all equations + void clearEquations(); + //! Replaces the model equations in dynamic_model with those in this model void replaceMyEquations(DynamicModel &dynamic_model) const; diff --git a/src/ModelTree.hh b/src/ModelTree.hh index d04f5d4d..040b2696 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -77,6 +77,8 @@ protected: * The following structures keep track of the model equations and must all be updated * when adding or removing an equation. Hence, if a new parallel structure is added * in the future, it must be maintained whereever these structures are updated + * See in particular methods clearEquations(), replaceMyEquations() and + * computeRamseyPolicyFOCs() of DynamicModel class. * NB: This message added with the introduction of the `exclude_eqs` option, hence * that's a place to update future structures. */ diff --git a/src/SymbolTable.cc b/src/SymbolTable.cc index 5363026f..895a2849 100644 --- a/src/SymbolTable.cc +++ b/src/SymbolTable.cc @@ -1096,3 +1096,12 @@ SymbolTable::getUltimateOrigSymbID(int symb_id) const } return symb_id; } + +int +SymbolTable::getEquationNumberForMultiplier(int symb_id) const +{ + for (const auto &aux_var : aux_vars) + if (aux_var.get_symb_id() == symb_id && aux_var.get_type() == AuxVarType::multiplier) + return aux_var.get_equation_number_for_multiplier(); + return -1; +} diff --git a/src/SymbolTable.hh b/src/SymbolTable.hh index d601f6f1..1d31964a 100644 --- a/src/SymbolTable.hh +++ b/src/SymbolTable.hh @@ -412,6 +412,8 @@ public: repeatedly call getOrigSymbIDForAuxVar() until an original (non-auxiliary) variable is found. */ int getUltimateOrigSymbID(int symb_id) const; + //! If this is a Lagrange multiplier, return its associated equation number; otherwise return -1 + int getEquationNumberForMultiplier(int symb_id) const; }; inline void -- GitLab