From 46aa6610ab13f449ba4423e02e5df3a2cb6f7e01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Tue, 14 Nov 2023 17:21:31 +0100 Subject: [PATCH] model_replace, model_remove: allow selecting an equation with several (conjunct) tags NB: does not (yet) works with Occbin regime-specific equations. Ref. dynare#1890 --- src/DynamicModel.cc | 30 ++++++++++++++++++++++-------- src/DynamicModel.hh | 21 ++++++++++++--------- src/DynareBison.yy | 18 +++++++++++++----- src/EquationTags.cc | 16 ++++++++++++++++ src/EquationTags.hh | 3 +++ src/ParsingDriver.cc | 4 ++-- src/ParsingDriver.hh | 4 ++-- 7 files changed, 70 insertions(+), 26 deletions(-) diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 0fc43d76..c68c12f4 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -496,7 +496,7 @@ DynamicModel::writeDynamicMCompatFile(const string &basename) const output.close(); } -vector<pair<string, string>> +vector<map<string, string>> DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_option_value, bool exclude_eqs) { auto removeLeadingTrailingWhitespace = [](string &str) @@ -584,7 +584,7 @@ DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_option_value, b exit(EXIT_FAILURE); } - vector<pair<string, string>> eq_tag_set; + vector<map<string, string>> eq_tag_set; regex s(quote_regex + "|" + non_quote_regex); for (auto it = sregex_iterator(tags.begin(), tags.end(), s); it != sregex_iterator(); ++it) @@ -595,13 +595,13 @@ DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_option_value, b str.remove_prefix(1); str.remove_suffix(1); } - eq_tag_set.emplace_back(tagname, str); + eq_tag_set.push_back({ { tagname, string{str} } }); } return eq_tag_set; } vector<int> -DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag, bool exclude_eqs, +DynamicModel::removeEquationsHelper(set<map<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type, vector<BinaryOpNode *> &all_equations, vector<optional<int>> &all_equations_lineno, @@ -616,7 +616,7 @@ DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag the caller knows which tag pairs have not been handled. */ set<int> listed_eqs_by_number; for (auto it = listed_eqs_by_tag.begin(); it != listed_eqs_by_tag.end();) - if (auto tmp = all_equation_tags.getEqnsByTag(it->first, it->second); + if (auto tmp = all_equation_tags.getEqnsByTags(*it); !tmp.empty()) { listed_eqs_by_number.insert(tmp.begin(), tmp.end()); @@ -691,7 +691,7 @@ DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag } void -DynamicModel::removeEquations(const vector<pair<string, string>> &listed_eqs_by_tag, bool exclude_eqs, +DynamicModel::removeEquations(const vector<map<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type) { /* Convert the const vector to a (mutable) set */ @@ -710,8 +710,22 @@ DynamicModel::removeEquations(const vector<pair<string, string>> &listed_eqs_by_ if (!listed_eqs_by_tag2.empty()) { cerr << "ERROR: model_remove/model_replace/exclude_eqs/include_eqs: The equations specified by" << endl; - for (const auto &[tagname, tagvalue] : listed_eqs_by_tag) - cerr << " " << tagname << "=" << tagvalue << endl; + for (const auto &m : listed_eqs_by_tag) + { + cerr << " "; + if (m.size() > 1) + cerr << "[ "; + bool first_printed {false}; + for (const auto &[tagname, tagvalue] : m) + { + if (exchange(first_printed, true)) + cerr << ", "; + cerr << tagname << "=" << tagvalue; + } + if (m.size() > 1) + cerr << " ]"; + cerr << endl; + } cerr << "were not found." << endl; exit(EXIT_FAILURE); } diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 1dc73424..636ee605 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -221,11 +221,12 @@ private: Returns a set of pairs (tag name, tag value) corresponding to the set of equations to be included or excluded. */ - static vector<pair<string, string>> parseIncludeExcludeEquations(const string &inc_exc_option_value, bool exclude_eqs); + static vector<map<string, string>> parseIncludeExcludeEquations(const string &inc_exc_option_value, bool exclude_eqs); /* Helper for the removeEquations() method. - listed_eqs_by_tag is the list of (tag name, tag value) pairs corresponding - to the option value, exclude_eqs is a boolean indicating whether we’re + listed_eqs_by_tag describes a list of equations to remove (identified by + one or more tags; if multiple tags are present for a single equation, they + are understood as a conjunction), exclude_eqs is a boolean indicating whether we’re excluding or including, and excluded_vars_change_type is a boolean indicating whether to compute variables to be excluded. @@ -233,13 +234,13 @@ private: equations. They are either the main structures for storing equations in ModelTree, or their counterpart for static-only equations. The static_equations boolean indicates when we are in the latter case. - The listed_eqs_by_tag structure will be updated by removing those tag - pairs that have been matched with equations in the all_equations* - argument*. + + The listed_eqs_by_tag structure will be updated by removing the tags + matched with equations in the all_equations* argument*. Returns a list of excluded variables (empty if excluded_vars_change_type=false) */ - vector<int> removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag, + vector<int> removeEquationsHelper(set<map<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type, vector<BinaryOpNode *> &all_equations, vector<optional<int>> &all_equations_lineno, @@ -396,10 +397,12 @@ public: //! Implements the include_eqs/exclude_eqs options void includeExcludeEquations(const string &inc_exc_option_value, bool exclude_eqs); - /* Removes equations from the model (identified by their name tags). + /* Removes equations from the model (identified by one or more tags; if + multiple tags are present for a single equation, they are understood as a + conjunction). Used for include_eqs/exclude_eqs options and for model_remove and model_replace blocks */ - void removeEquations(const vector<pair<string, string>> &listed_eqs_by_tag, bool exclude_eqs, + void removeEquations(const vector<map<string, string>> &listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type); /* Replaces model equations with derivatives of Lagrangian w.r.t. endogenous. diff --git a/src/DynareBison.yy b/src/DynareBison.yy index f3ca4265..5ac6f632 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -235,7 +235,8 @@ str_tolower(string s) %type <PriorDistributions> prior_pdf prior_distribution %type <pair<expr_t,expr_t>> calibration_range %type <pair<string,string>> partition_elem subsamples_eq_opt integer_range_w_inf tag_pair -%type <vector<pair<string,string>>> partition partition_1 tag_pair_list_for_selection symbol_list_with_tex +%type <vector<pair<string,string>>> partition partition_1 symbol_list_with_tex +%type <vector<map<string, string>>> tag_pair_list_for_selection %type <map<string, string>> tag_pair_list %type <tuple<string,string,string,string>> prior_eq_opt options_eq_opt %type <vector<pair<int, int>>> period_list @@ -1155,18 +1156,25 @@ model_replace : MODEL_REPLACE '(' tag_pair_list_for_selection ')' ';' model_options : MODEL_OPTIONS '(' model_options_list ')' ';' tag_pair_list_for_selection : QUOTED_STRING - { $$ = { { "name", $1 } }; } + { $$ = { { { "name", $1 } } }; } | tag_pair - { $$ = { $1 }; } + { $$ = { { $1 } }; } + | '[' tag_pair_list ']' + { $$ = { $2 }; } | tag_pair_list_for_selection COMMA QUOTED_STRING { $$ = $1; - $$.emplace_back("name", $3); + $$.push_back({ { "name", $3 } }); } | tag_pair_list_for_selection COMMA tag_pair { $$ = $1; - $$.push_back($3); + $$.push_back({ $3 }); + } + | tag_pair_list_for_selection COMMA '[' tag_pair_list ']' + { + $$ = $1; + $$.push_back($4); } ; diff --git a/src/EquationTags.cc b/src/EquationTags.cc index 063db797..f980d438 100644 --- a/src/EquationTags.cc +++ b/src/EquationTags.cc @@ -52,6 +52,22 @@ EquationTags::getEqnByTag(const string &key, const string &value) const return nullopt; } +set<int> +EquationTags::getEqnsByTags(const map<string, string> &tags_selected) const +{ + set<int> retval; + for (const auto &[eqn, tags] : eqn_tags) + { + for (const auto &[key, value] : tags_selected) + if (auto tmp = tags.find(key); tmp == tags.end() || tmp->second != value) + goto next_eq; + retval.insert(eqn); + next_eq: + ; + } + return retval; +} + void EquationTags::erase(const set<int> &eqns, const map<int, int> &old_eqn_num_2_new) { diff --git a/src/EquationTags.hh b/src/EquationTags.hh index 9ac418bd..75321d96 100644 --- a/src/EquationTags.hh +++ b/src/EquationTags.hh @@ -79,6 +79,9 @@ public: //! Get the first equation that has the given key and value optional<int> getEqnByTag(const string &key, const string &value) const; + // Get equations that have all the given keys and values (seen as a conjunction) + set<int> getEqnsByTags(const map<string, string> &tags_selected) const; + //! Get the tag value given the equation number and key optional<string> getTagValueByEqnAndKey(int eqn, const string &key) const diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index 6a61a54d..a91f5030 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -3756,13 +3756,13 @@ ParsingDriver::isSymbolIdentifier(const string &str) } void -ParsingDriver::model_remove(const vector<pair<string, string>> &listed_eqs_by_tags) +ParsingDriver::model_remove(const vector<map<string, string>> &listed_eqs_by_tags) { mod_file->dynamic_model.removeEquations(listed_eqs_by_tags, true, true); } void -ParsingDriver::begin_model_replace(const vector<pair<string, string>> &listed_eqs_by_tags) +ParsingDriver::begin_model_replace(const vector<map<string, string>> &listed_eqs_by_tags) { mod_file->dynamic_model.removeEquations(listed_eqs_by_tags, true, false); set_current_data_tree(&mod_file->dynamic_model); diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index f75b39b6..b945b0d4 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -904,9 +904,9 @@ public: //! Add an occbin_constraints block void end_occbin_constraints(vector<tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>> constraints); // Process a model_remove statement - void model_remove(const vector<pair<string, string>> &listed_eqs_by_tags); + void model_remove(const vector<map<string, string>> &listed_eqs_by_tags); // Begin a model_replace statement - void begin_model_replace(const vector<pair<string, string>> &listed_eqs_by_tags); + void begin_model_replace(const vector<map<string, string>> &listed_eqs_by_tags); // Add a var_remove statement void var_remove(const vector<string> &symbol_list); void begin_pac_target_info(string name); -- GitLab