From 64f55e4a5e5bd1dbc24f806f1b9c4b518f24eb8c Mon Sep 17 00:00:00 2001
From: Houtan Bastani <houtan@dynare.org>
Date: Mon, 25 Feb 2019 15:29:46 +0100
Subject: [PATCH] pac: declare endogenous variables needed by pac model
 consistent expectation before the creation of auxiliary variables

---
 src/DynamicModel.cc | 46 +++++++++++++++++++++++++++++++++++++--------
 src/DynamicModel.hh |  3 +++
 src/ModFile.cc      |  6 ++++++
 3 files changed, 47 insertions(+), 8 deletions(-)

diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index 4d0fd66b..6da7c765 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -4496,6 +4496,41 @@ DynamicModel::getPacTargetSymbId(const string &pac_model_name) const
   return -1;
 }
 
+
+void
+DynamicModel::declarePacModelConsistentExpectationEndogs(const string &name)
+{
+  int i = 0;
+  for (auto & equation : equations)
+    if (equation->containsPacExpectation())
+      {
+        string eqtag = "";
+        for (auto & tag : equation_tags)
+          if (tag.first == (&equation - &equations[0]))
+            if (tag.second.first == "name")
+              {
+                eqtag = tag.second.second;
+                break;
+              }
+        if (eqtag == "")
+          {
+            cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
+            exit(EXIT_FAILURE);
+          }
+        string standard_eqtag = "eq" + to_string(i++);
+        try
+          {
+            pac_mce_z1_symb_ids[{name, standard_eqtag}] =
+              symbol_table.addSymbol("mce_Z1_" + name + "_" + standard_eqtag, SymbolType::endogenous);
+          }
+        catch (SymbolTable::AlreadyDeclaredException &e)
+          {
+            cerr << "Variable name needed by PAC (mce_Z1_" << name << "_" << standard_eqtag << endl;
+            exit(EXIT_FAILURE);
+          }
+      }
+}
+
 void
 DynamicModel::addPacModelConsistentExpectationEquation(const string & name, int discount_symb_id,
                                                        const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
@@ -4510,16 +4545,12 @@ DynamicModel::addPacModelConsistentExpectationEquation(const string & name, int
       string standard_eqtag = it.second.first;
       int pac_max_lag_m = it.second.second + 1;
       string append_to_name = name + "_" + standard_eqtag;
-      int mce_z1_symb_id;
-      try
-        {
-          mce_z1_symb_id = symbol_table.addSymbol("mce_Z1_" + append_to_name, SymbolType::endogenous);
-        }
-      catch (SymbolTable::AlreadyDeclaredException &e)
+      if (pac_mce_z1_symb_ids.find({name, standard_eqtag}) == pac_mce_z1_symb_ids.end())
         {
-          cerr << "Variable name needed by PAC (mce_Z1_" << append_to_name << endl;
+          cerr << "Error finding pac MCE Z1 symb id" << endl;
           exit(EXIT_FAILURE);
         }
+      int mce_z1_symb_id = pac_mce_z1_symb_ids[{name, standard_eqtag}];
 
       expr_t A = One;
       expr_t fp = Zero;
@@ -4597,7 +4628,6 @@ DynamicModel::addPacModelConsistentExpectationEquation(const string & name, int
       addEquation(AddEqual(AddVariable(mce_z1_symb_id),
                            AddMinus(AddTimes(A, AddMinus((expr_t) target_base_diff_node, fs)), fp)), -1);
       neqs++;
-      pac_mce_z1_symb_ids[{name, standard_eqtag}] = mce_z1_symb_id;
       pac_expectation_substitution[{name, eqtag}] = AddVariable(mce_z1_symb_id);
     }
     cout << "Pac Model Consistent Expectation: added " << neqs << " auxiliary variables and equations." << endl;
diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh
index 8ea9e2ad..1293e31d 100644
--- a/src/DynamicModel.hh
+++ b/src/DynamicModel.hh
@@ -455,6 +455,9 @@ public:
   //! Return target of the pac equation
   int getPacTargetSymbId(const string &pac_model_name) const;
 
+  //! Declare Z1 variables before creating aux vars so it comes right after the endo names declared by the user
+  void declarePacModelConsistentExpectationEndogs(const string &name);
+
   //! Add model consistent expectation equation for pac model
   void addPacModelConsistentExpectationEquation(const string & name, int discount,
                                                 const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
diff --git a/src/ModFile.cc b/src/ModFile.cc
index d5002f7f..4b133dab 100644
--- a/src/ModFile.cc
+++ b/src/ModFile.cc
@@ -367,6 +367,12 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const
   // Save the original model (must be done before any model transformations by preprocessor)
   // - except adl and diff which we always want expanded
   dynamic_model.simplifyEquations();
+  for (auto & statement : statements)
+    {
+      auto pms = dynamic_cast<PacModelStatement *>(statement.get());
+      if (pms != nullptr && pms->aux_model_name == "")
+        dynamic_model.declarePacModelConsistentExpectationEndogs(pms->name);
+    }
   dynamic_model.substituteAdl();
   dynamic_model.setLeadsLagsOrig();
   original_model = dynamic_model;
-- 
GitLab