diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index e85ab80056596a28dc7cca121431b313780f98a0..cc5d7987fbc9368c00b453e3c0ad6aebf1f2a89b 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2023 Dynare Team + * Copyright © 2003-2024 Dynare Team * * This file is part of Dynare. * @@ -3600,25 +3600,25 @@ DynamicModel::dynamicOnlyEquationsNbr() const void DynamicModel::addOccbinEquation(expr_t eq, const optional<int>& lineno, map<string, string> eq_tags, - const vector<string>& regimes_bind, - const vector<string>& regimes_relax) + const vector<string>& constraints_bind, + const vector<string>& constraints_relax) { auto beq = dynamic_cast<BinaryOpNode*>(eq); assert(beq && beq->op_code == BinaryOpcode::equal); - occbin_regime_trackers[eq_tags.at("name")].addAlternative(regimes_bind, regimes_relax); + occbin_regime_trackers[eq_tags.at("name")].addRegime(constraints_bind, constraints_relax); // Construct the term to be added to the corresponding equation expr_t basic_term = AddMinus(beq->arg1, beq->arg2); expr_t term = basic_term; - for (auto& regime : regimes_bind) + for (auto& constraint : constraints_bind) { - int param_id = symbol_table.getID(ParsingDriver::buildOccbinBindParamName(regime)); + int param_id = symbol_table.getID(ParsingDriver::buildOccbinBindParamName(constraint)); term = AddTimes(term, AddVariable(param_id)); } - for (auto& regime : regimes_relax) + for (auto& constraint : constraints_relax) { - int param_id = symbol_table.getID(ParsingDriver::buildOccbinBindParamName(regime)); + int param_id = symbol_table.getID(ParsingDriver::buildOccbinBindParamName(constraint)); term = AddTimes(term, AddMinus(One, AddVariable(param_id))); } @@ -3641,7 +3641,7 @@ DynamicModel::addOccbinEquation(expr_t eq, const optional<int>& lineno, map<stri } // Create or update the static equation (corresponding to the pure relax regime) - if (regimes_bind.empty()) + if (constraints_bind.empty()) { /* Similar remark as above. We could have entirely skipped this equation updating, since normally there is only one such clause, @@ -4031,27 +4031,27 @@ DynamicModel::checkOccbinRegimes() const { try { - tracker.checkAllAlternativesPresent(); + tracker.checkAllRegimesPresent(); } - catch (OccbinRegimeTracker::MissingAlternativeException& e) + catch (OccbinRegimeTracker::MissingRegimeException& e) { - cerr << "ERROR: for equation '" << eq_name << "', the alternative corresponding to '"; - if (!e.regimes_bind.empty()) + cerr << "ERROR: for equation '" << eq_name << "', the regime corresponding to "; + if (!e.constraints_bind.empty()) { - cerr << "bind="; - for (bool first_printed {false}; const auto& r : e.regimes_bind) + cerr << "bind='"; + for (bool first_printed {false}; const auto& r : e.constraints_bind) { if (exchange(first_printed, true)) cerr << ","; cerr << r; } } - if (!e.regimes_bind.empty() && !e.regimes_relax.empty()) - cerr << "'and '"; - if (!e.regimes_relax.empty()) + if (!e.constraints_bind.empty() && !e.constraints_relax.empty()) + cerr << "' and "; + if (!e.constraints_relax.empty()) { - cerr << "relax="; - for (bool first_printed {false}; const auto& r : e.regimes_relax) + cerr << "relax='"; + for (bool first_printed {false}; const auto& r : e.constraints_relax) { if (exchange(first_printed, true)) cerr << ","; @@ -4065,102 +4065,105 @@ DynamicModel::checkOccbinRegimes() const } void -DynamicModel::OccbinRegimeTracker::addAlternative(const vector<string>& regimes_bind, - const vector<string>& regimes_relax) +DynamicModel::OccbinRegimeTracker::addRegime(const vector<string>& constraints_bind, + const vector<string>& constraints_relax) { - // Check that no regime appears in both bind and relax - set regimes_bind_sorted(regimes_bind.begin(), regimes_bind.end()), - regimes_relax_sorted(regimes_relax.begin(), regimes_relax.end()); - vector<string> regimes_intersect; - ranges::set_intersection(regimes_bind_sorted, regimes_relax_sorted, - back_inserter(regimes_intersect)); - if (!regimes_intersect.empty()) - throw RegimeInBothBindAndRelaxException {regimes_intersect.front()}; - - // If a regime has never been mentioned before, add it to the list and adapt the alternatives - vector<string> regimes_union; - ranges::set_union(regimes_bind_sorted, regimes_relax_sorted, back_inserter(regimes_union)); - for (const auto& r : regimes_union) - if (ranges::find(regimes, r) == regimes.end()) + // Check that no constraint appears in both bind and relax + set constraints_bind_sorted(constraints_bind.begin(), constraints_bind.end()), + constraints_relax_sorted(constraints_relax.begin(), constraints_relax.end()); + vector<string> constraints_intersect; + ranges::set_intersection(constraints_bind_sorted, constraints_relax_sorted, + back_inserter(constraints_intersect)); + if (!constraints_intersect.empty()) + throw ConstraintInBothBindAndRelaxException {constraints_intersect.front()}; + + // If a constraint has never been mentioned before, add it to the list and adapt the regimes + vector<string> constraints_union; + ranges::set_union(constraints_bind_sorted, constraints_relax_sorted, + back_inserter(constraints_union)); + for (const auto& c : constraints_union) + if (ranges::find(constraints, c) == constraints.end()) { - regimes.push_back(r); - auto alt_copy = alternatives_present; - alternatives_present.clear(); - for (const auto& a : alt_copy) + constraints.push_back(c); + auto regimes_copy = regimes_present; + regimes_present.clear(); + for (const auto& r : regimes_copy) { - auto a0 = a, a1 = a; - a0.push_back(false); - a1.push_back(true); - alternatives_present.insert(a0); - alternatives_present.insert(a1); + auto r0 = r, r1 = r; + r0.push_back(false); + r1.push_back(true); + regimes_present.insert(r0); + regimes_present.insert(r1); } } // Create the bit vector(s) corresponding to the function arguments - vector<bool> new_alt_template(regimes.size(), false); - for (const auto& r : regimes_bind) + vector<bool> new_regime_template(constraints.size(), false); + for (const auto& c : constraints_bind) { - int i = distance(regimes.begin(), ranges::find(regimes, r)); - new_alt_template[i] = true; + int i = distance(constraints.begin(), ranges::find(constraints, c)); + new_regime_template[i] = true; } - set<vector<bool>> new_alts {new_alt_template}; - set all_regimes_sorted(regimes.begin(), regimes.end()); - vector<string> regimes_not_mentioned; - ranges::set_difference(all_regimes_sorted, regimes_union, back_inserter(regimes_not_mentioned)); - for (const auto& r : regimes_not_mentioned) + set<vector<bool>> new_regimes {new_regime_template}; + set all_constraints_sorted(constraints.begin(), constraints.end()); + vector<string> constraints_not_mentioned; + ranges::set_difference(all_constraints_sorted, constraints_union, + back_inserter(constraints_not_mentioned)); + for (const auto& c : constraints_not_mentioned) { - int i = distance(regimes.begin(), ranges::find(regimes, r)); - auto new_alts_copy = new_alts; - for (const auto& a : new_alts_copy) + int i = distance(constraints.begin(), ranges::find(constraints, c)); + auto new_regimes_copy = new_regimes; + for (const auto& r : new_regimes_copy) { - auto a2 = a; - a2[i] = true; - new_alts.insert(move(a2)); + auto r2 = r; + r2[i] = true; + new_regimes.insert(move(r2)); } } // Add the new bit vector(s) - for (const auto& a : new_alts) + for (const auto& r : new_regimes) { - auto [it, success] = alternatives_present.insert(a); + auto [it, success] = regimes_present.insert(r); if (!success) { - auto [regimes_bind_duplicate, regimes_relax_duplicate] = convertBitVectorToRegimes(a); - throw AlternativeAlreadyPresentException {regimes_bind_duplicate, - regimes_relax_duplicate}; + auto [constraints_bind_duplicate, constraints_relax_duplicate] + = convertBitVectorToRegimes(r); + throw RegimeAlreadyPresentException {constraints_bind_duplicate, + constraints_relax_duplicate}; } } } void -DynamicModel::OccbinRegimeTracker::checkAllAlternativesPresent() const +DynamicModel::OccbinRegimeTracker::checkAllRegimesPresent() const { - vector<bool> a(regimes.size(), false); + vector<bool> r(constraints.size(), false); do { - if (!alternatives_present.contains(a)) + if (!regimes_present.contains(r)) { - auto [regimes_bind, regimes_relax] = convertBitVectorToRegimes(a); - throw MissingAlternativeException {regimes_bind, regimes_relax}; + auto [constraints_bind, constraints_relax] = convertBitVectorToRegimes(r); + throw MissingRegimeException {constraints_bind, constraints_relax}; } - auto it = ranges::find(a, false); - if (it == a.end()) + auto it = ranges::find(r, false); + if (it == r.end()) break; *it = true; - if (it != a.begin()) - fill(a.begin(), prev(it), false); + if (it != r.begin()) + fill(r.begin(), prev(it), false); } while (true); } pair<vector<string>, vector<string>> -DynamicModel::OccbinRegimeTracker::convertBitVectorToRegimes(const vector<bool>& a) const +DynamicModel::OccbinRegimeTracker::convertBitVectorToRegimes(const vector<bool>& r) const { - vector<string> regimes_bind, regimes_relax; - for (size_t i = 0; i < regimes.size(); i++) - if (a[i]) - regimes_bind.push_back(regimes[i]); + vector<string> constraints_bind, constraints_relax; + for (size_t i = 0; i < constraints.size(); i++) + if (r[i]) + constraints_bind.push_back(constraints[i]); else - regimes_relax.push_back(regimes[i]); - return {regimes_bind, regimes_relax}; + constraints_relax.push_back(constraints[i]); + return {constraints_bind, constraints_relax}; } diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index fc34f190074d6eb032876d92a476766fd671e33e..05d5b4440916c1ff8cec519840e0cea48e4933eb 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2023 Dynare Team + * Copyright © 2003-2024 Dynare Team * * This file is part of Dynare. * @@ -48,32 +48,32 @@ public: class OccbinRegimeTracker { private: - // The list of regimes used for this equation - vector<string> regimes; - /* The list of alternatives present for this equation; each alternative is a vector of boolean, - of same length as “regimes”; each boolean represents a regime (in the order of “regimes”): - false for relax, true for bind */ - set<vector<bool>> alternatives_present; + // The list of constraints used for this equation + vector<string> constraints; + /* The list of regimes present for this equation; each regime is a vector of boolean, of same + length as “constraints”; each boolean represents a constraint (in the order of + “constraints”): false for relax, true for bind */ + set<vector<bool>> regimes_present; public: - struct RegimeInBothBindAndRelaxException + struct ConstraintInBothBindAndRelaxException { - const string regime; + const string constraint; }; - struct AlternativeAlreadyPresentException + struct RegimeAlreadyPresentException { - const vector<string> regimes_bind, regimes_relax; + const vector<string> constraints_bind, constraints_relax; }; - void addAlternative(const vector<string>& regimes_bind, - const vector<string>& regimes_relax) noexcept(false); - struct MissingAlternativeException + void addRegime(const vector<string>& constraints_bind, + const vector<string>& constraints_relax) noexcept(false); + struct MissingRegimeException { - const vector<string> regimes_bind, regimes_relax; + const vector<string> constraints_bind, constraints_relax; }; - void checkAllAlternativesPresent() const noexcept(false); + void checkAllRegimesPresent() const noexcept(false); private: - pair<vector<string>, vector<string>> convertBitVectorToRegimes(const vector<bool>& a) const; + pair<vector<string>, vector<string>> convertBitVectorToRegimes(const vector<bool>& r) const; }; private: @@ -478,7 +478,8 @@ public: It also assumes that the “bind” and “relax” tags have been cleared from eq_tags. */ void addOccbinEquation(expr_t eq, const optional<int>& lineno, map<string, string> eq_tags, - const vector<string>& regimes_bind, const vector<string>& regimes_relax); + const vector<string>& constraints_bind, + const vector<string>& constraints_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/ParsingDriver.cc b/src/ParsingDriver.cc index 79b68d66df9ba030d151fc79d8c7c07e05f7f30c..c8733c18dd3dcd4233ef1e7f221ec429fa3c9a8c 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -2648,23 +2648,23 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_ // If the equation has a “bind” or “relax” tag (occbin case) if (!eq_tags.contains("name")) error("An equation with a 'bind' or 'relax' tag must have a 'name' tag"); - auto regimes_bind = DataTree::strsplit(eq_tags["bind"], ','); - auto regimes_relax = DataTree::strsplit(eq_tags["relax"], ','); - auto regimes_all = regimes_bind; - regimes_all.insert(regimes_all.end(), regimes_relax.begin(), - regimes_relax.end()); // Concatenate the two vectors - for (const auto& regime : regimes_all) + auto constraints_bind = DataTree::strsplit(eq_tags["bind"], ','); + auto constraints_relax = DataTree::strsplit(eq_tags["relax"], ','); + auto constraints_all = constraints_bind; + constraints_all.insert(constraints_all.end(), constraints_relax.begin(), + constraints_relax.end()); // Concatenate the two vectors + for (const auto& constraint : constraints_all) { - if (!isSymbolIdentifier(regime)) - error("The string '" + regime - + "' is not a valid Occbin regime name (contains unauthorized characters)"); - string param_name = buildOccbinBindParamName(regime); + if (!isSymbolIdentifier(constraint)) + error("The string '" + constraint + + "' is not a valid Occbin constraint name (contains unauthorized characters)"); + string param_name = buildOccbinBindParamName(constraint); try { if (mod_file->symbol_table.getType(param_name) != SymbolType::parameter) error("The name '" + param_name - + "' is already used. Please use another name for Occbin regime '" + regime - + "'"); + + "' is already used. Please use another name for Occbin constraint '" + + constraint + "'"); } catch (SymbolTable::UnknownSymbolNameException& e) { @@ -2679,40 +2679,41 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_ try { - dynamic_model->addOccbinEquation(id, location.begin.line, move(eq_tags), regimes_bind, - regimes_relax); + dynamic_model->addOccbinEquation(id, location.begin.line, move(eq_tags), constraints_bind, + constraints_relax); } - catch (DynamicModel::OccbinRegimeTracker::RegimeInBothBindAndRelaxException& e) + catch (DynamicModel::OccbinRegimeTracker::ConstraintInBothBindAndRelaxException& e) { - error("The regime '" + e.regime + "' is both in the 'bind' and 'relax' tags"); + error("The constraint '" + e.constraint + "' is both in the 'bind' and 'relax' tags"); } - catch (DynamicModel::OccbinRegimeTracker::AlternativeAlreadyPresentException& e) + catch (DynamicModel::OccbinRegimeTracker::RegimeAlreadyPresentException& e) { stringstream s; - if (!e.regimes_bind.empty()) + if (!e.constraints_bind.empty()) { - cerr << "bind="; - for (bool first_printed {false}; const auto& r : e.regimes_bind) + s << "bind='"; + for (bool first_printed {false}; const auto& c : e.constraints_bind) { if (exchange(first_printed, true)) - cerr << ","; - cerr << r; + s << ","; + s << c; } } - if (!e.regimes_bind.empty() && !e.regimes_relax.empty()) - cerr << "'and '"; - if (!e.regimes_relax.empty()) + if (!e.constraints_bind.empty() && !e.constraints_relax.empty()) + s << "' and "; + if (!e.constraints_relax.empty()) { - cerr << "relax="; - for (bool first_printed {false}; const auto& r : e.regimes_relax) + s << "relax='"; + for (bool first_printed {false}; const auto& c : e.constraints_relax) { if (exchange(first_printed, true)) - cerr << ","; - cerr << r; + s << ","; + s << c; } } - error("The alternative corresponding to '" + s.str() - + "' has already been declared for this equation"); + s << "'"; + error("The regime corresponding to " + s.str() + + " has already been declared for this equation"); } } else // General case @@ -3802,7 +3803,7 @@ ParsingDriver::end_occbin_constraints( { string param_name = buildOccbinBindParamName(name); if (!mod_file->symbol_table.exists(param_name)) - error("No equation has been declared for regime '" + name + "'"); + error("No equation has been declared for constraint '" + name + "'"); if (!bind) error("The 'bind' expression is missing in constraint '" + name + "'"); }