From bdb5d37dec98908fd9b941c13d56f12b95b242a6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Wed, 4 Jan 2023 16:03:12 +0100
Subject: [PATCH] EquationTags::getTagValueByEqnAndKey() now return an
 optional<string>

By the way, optimize the implementation.
---
 src/DynamicModel.cc | 38 +++++++++++++++++++-------------------
 src/EquationTags.hh |  8 ++++++--
 2 files changed, 25 insertions(+), 21 deletions(-)

diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index e93efd3d..96d78b0f 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright © 2003-2022 Dynare Team
+ * Copyright © 2003-2023 Dynare Team
  *
  * This file is part of Dynare.
  *
@@ -1229,8 +1229,8 @@ DynamicModel::removeEquationsHelper(set<pair<string, string>> &listed_eqs_by_tag
     if (eqs_to_delete_by_number.contains(i))
       {
         if (excluded_vars_change_type)
-          if (auto tmp = all_equation_tags.getTagValueByEqnAndKey(i, "endogenous"); !tmp.empty())
-            excluded_vars.push_back(symbol_table.getID(tmp));
+          if (auto tmp = all_equation_tags.getTagValueByEqnAndKey(i, "endogenous"); tmp)
+            excluded_vars.push_back(symbol_table.getID(*tmp));
           else
             {
               set<int> result;
@@ -1998,19 +1998,19 @@ DynamicModel::fillVarModelTableFromOrigModel() const
       for (auto eqn : eqns)
         {
           // Perform some sanity checks on the RHS
-          string eqtag = equation_tags.getTagValueByEqnAndKey(eqn, "name");
+          optional<string> eqtag { equation_tags.getTagValueByEqnAndKey(eqn, "name") };
           set<pair<int, int>> rhs_endo_set, rhs_exo_set;
           equations[eqn]->arg2->collectDynamicVariables(SymbolType::endogenous, rhs_endo_set);
           for (const auto &[symb_id, lag] : rhs_endo_set)
             if (lag > 0)
               {
-                cerr << "ERROR: in Equation " << eqtag
+                cerr << "ERROR: in Equation " << eqtag.value_or(to_string(eqn+1))
                      << ". A VAR model may not have leaded endogenous variables on the RHS. " << endl;
                 exit(EXIT_FAILURE);
               }
             else if (!var_model_table.getStructural().at(model_name) && lag == 0)
               {
-                cerr << "ERROR: in Equation " << eqtag
+                cerr << "ERROR: in Equation " << eqtag.value_or(to_string(eqn+1))
                      << ". A non-structural VAR model may not have contemporaneous endogenous variables on the RHS. " << endl;
                 exit(EXIT_FAILURE);
               }
@@ -2019,7 +2019,7 @@ DynamicModel::fillVarModelTableFromOrigModel() const
           for (const auto &[symb_id, lag] : rhs_exo_set)
             if (lag != 0)
               {
-                cerr << "ERROR: in Equation " << eqtag
+                cerr << "ERROR: in Equation " << eqtag.value_or(to_string(eqn+1))
                      << ". A VAR model may not have lagged or leaded exogenous variables on the RHS. " << endl;
                 exit(EXIT_FAILURE);
               }
@@ -2149,7 +2149,7 @@ DynamicModel::fillVarModelTableMatrices()
                     {
                       if (!d->isConstant())
                         {
-                          cerr << "ERROR: Equation '" << equation_tags.getTagValueByEqnAndKey(eqns[i], "name") << "' is not linear" << endl;
+                          cerr << "ERROR: Equation " << equation_tags.getTagValueByEqnAndKey(eqns[i], "name").value_or(to_string(eqns[i]+1)) << " is not linear" << endl;
                           exit(EXIT_FAILURE);
                         }
 
@@ -2167,7 +2167,7 @@ DynamicModel::fillVarModelTableMatrices()
                 {
                   if (!d->isConstant())
                     {
-                      cerr << "ERROR: Equation '" << equation_tags.getTagValueByEqnAndKey(eqns[i], "name") << "' is not linear" << endl;
+                      cerr << "ERROR: Equation " << equation_tags.getTagValueByEqnAndKey(eqns[i], "name").value_or(to_string(eqns[i]+1)) << " is not linear" << endl;
                       exit(EXIT_FAILURE);
                     }
 
@@ -2347,13 +2347,13 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel() const
       for (auto eqn : eqns)
         {
           // Perform some sanity checks on the RHS
-          string eqtag = equation_tags.getTagValueByEqnAndKey(eqn, "name");
+          optional<string> eqtag { equation_tags.getTagValueByEqnAndKey(eqn, "name") };
           set<pair<int, int>> rhs_endo_set, rhs_exo_set;
           equations[eqn]->arg2->collectDynamicVariables(SymbolType::endogenous, rhs_endo_set);
           for (const auto &[symb_id, lag] : rhs_endo_set)
             if (lag >= 0)
               {
-                cerr << "ERROR: in Equation " << eqtag
+                cerr << "ERROR: in Equation " << eqtag.value_or(to_string(eqn+1))
                      << ". A trend component model may not have leaded or contemporaneous endogenous variables on the RHS. " << endl;
                 exit(EXIT_FAILURE);
               }
@@ -2361,7 +2361,7 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel() const
           for (const auto &[symb_id, lag] : rhs_exo_set)
             if (lag != 0)
               {
-                cerr << "ERROR: in Equation " << eqtag
+                cerr << "ERROR: in Equation " << eqtag.value_or(to_string(eqn+1))
                      << ". A trend component model may not have lagged or leaded exogenous variables on the RHS. " << endl;
                 exit(EXIT_FAILURE);
               }
@@ -2498,13 +2498,13 @@ DynamicModel::analyzePacEquationStructure(const string &name, map<string, string
             cerr << "It is not possible to use 'pac_expectation(" << name << ")' in several equations." << endl;
             exit(EXIT_FAILURE);
           }
-        string eqn = equation_tags.getTagValueByEqnAndKey(&equation - &equations[0], "name");
-        if (eqn.empty())
+        optional<string> eqn { equation_tags.getTagValueByEqnAndKey(&equation - &equations[0], "name") };
+        if (!eqn)
           {
             cerr << "Every equation with a 'pac_expectation' operator must have been assigned an equation tag name" << endl;
             exit(EXIT_FAILURE);
           }
-        pac_eq_name[name] = eqn;
+        pac_eq_name[name] = *eqn;
 
         set<pair<int, int>> lhss;
         equation->arg1->collectDynamicVariables(SymbolType::endogenous, lhss);
@@ -4545,11 +4545,11 @@ DynamicModel::writeJsonVariableMapping(ostream &output) const
       for (bool printed_something2{false};
            int it2 : eqs)
         if (auto tmp = equation_tags.getTagValueByEqnAndKey(it2, "name");
-            !tmp.empty())
+            tmp)
           {
             if (exchange(printed_something2, true))
               output << ", ";
-            output << '"' << tmp << '"';
+            output << '"' << *tmp << '"';
           }
       output << "]}" << endl;
     }
@@ -4752,7 +4752,7 @@ DynamicModel::checkNoRemainingPacExpectation() const
   for (size_t eq = 0; eq < equations.size(); eq++)
     if (equations[eq]->containsPacExpectation())
       {
-        cerr << "ERROR: in equation " << equation_tags.getTagValueByEqnAndKey(eq, "name")
+        cerr << "ERROR: in equation " << equation_tags.getTagValueByEqnAndKey(eq, "name").value_or(to_string(eq+1))
              << ", the pac_expectation operator references an unknown pac_model" << endl;
         exit(EXIT_FAILURE);
       }
@@ -4785,7 +4785,7 @@ DynamicModel::checkNoRemainingPacTargetNonstationary() const
   for (size_t eq = 0; eq < equations.size(); eq++)
     if (equations[eq]->containsPacTargetNonstationary())
       {
-        cerr << "ERROR: in equation " << equation_tags.getTagValueByEqnAndKey(eq, "name")
+        cerr << "ERROR: in equation " << equation_tags.getTagValueByEqnAndKey(eq, "name").value_or(to_string(eq+1))
              << ", the pac_target_nonstationary operator does not match a corresponding 'pac_target_info' block" << endl;
         exit(EXIT_FAILURE);
       }
diff --git a/src/EquationTags.hh b/src/EquationTags.hh
index 729ac861..6f9e5cd9 100644
--- a/src/EquationTags.hh
+++ b/src/EquationTags.hh
@@ -23,6 +23,7 @@
 #include <map>
 #include <set>
 #include <string>
+#include <optional>
 
 using namespace std;
 
@@ -84,10 +85,13 @@ public:
   int getEqnByTag(const string &key, const string &value) const;
 
   //! Get the tag value given the equation number and key
-  string
+  optional<string>
   getTagValueByEqnAndKey(int eqn, const string &key) const
   {
-    return exists(eqn, key) ? eqn_tags.at(eqn).at(key) : "";
+    if (auto it = eqn_tags.find(eqn); it != eqn_tags.end())
+      if (auto it2 = it->second.find(key); it2 != it->second.end())
+        return it2->second;
+    return nullopt;
   }
 
   //! Get the equations marked dynamic
-- 
GitLab