From 1088cc42420dcaec5c27f3605afcb0dd7b682332 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org>
Date: Wed, 14 Sep 2022 17:48:33 +0200
Subject: [PATCH] Improve informative messages about derivatives and block
 decomposition

When computing the derivatives or block decomposition of the planner objective,
the epilogue or the original Ramsey model, the preprocessor would talk about
dynamic/static model, which was confusing. It now uses the right terminology.
---
 src/DynamicModel.cc       | 14 +++++++-------
 src/DynamicModel.hh       |  7 +++++++
 src/ModFile.hh            |  2 +-
 src/ModelEquationBlock.cc | 17 +++++++++++++++++
 src/ModelEquationBlock.hh | 33 +++++++++++++++++++++++++++++++++
 src/ModelTree.cc          | 16 ++++++++--------
 src/ModelTree.hh          |  7 +++++--
 src/StaticModel.cc        | 14 +++++++-------
 src/StaticModel.hh        |  7 +++++++
 9 files changed, 92 insertions(+), 25 deletions(-)

diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc
index 85037d4d..1807762f 100644
--- a/src/DynamicModel.cc
+++ b/src/DynamicModel.cc
@@ -953,7 +953,7 @@ DynamicModel::writeDynamicCFile(const string &basename) const
       exit(EXIT_FAILURE);
     }
   output << "/*" << endl
-         << " * " << filename << " : Computes dynamic model for Dynare" << endl
+         << " * " << filename << " : Computes " << modelClassName() << " for Dynare" << endl
          << " *" << endl
          << " * Warning : this file is generated automatically by Dynare" << endl
          << " *           from model file (.mod)" << endl
@@ -3261,7 +3261,7 @@ DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsO
      getJacobianColsNbr() is not yet set.*/
   if (log2(getJacobianColsNbr())*derivsOrder >= numeric_limits<int>::digits)
     {
-      cerr << "ERROR: The dynamic derivatives matrix is too large. Please decrease the approximation order." << endl;
+      cerr << "ERROR: The derivatives matrix of the " << modelClassName() << " is too large. Please decrease the approximation order." << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -3275,7 +3275,7 @@ DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsO
     }
 
   // Launch computations
-  cout << "Computing dynamic model derivatives (order " << derivsOrder << ")." << endl;
+  cout << "Computing " << modelClassName() << " derivatives (order " << derivsOrder << ")." << endl;
 
   computeDerivatives(derivsOrder, vars);
 
@@ -3285,7 +3285,7 @@ DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsO
 
   if (paramsDerivsOrder > 0)
     {
-      cout << "Computing dynamic model derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
+      cout << "Computing " << modelClassName() << " derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
       computeParamsDerivatives(paramsDerivsOrder);
     }
 
@@ -3307,12 +3307,12 @@ bool
 DynamicModel::computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms)
 {
   auto contemporaneous_jacobian = evaluateAndReduceJacobian(eval_context);
-  if (!computeNonSingularNormalization(contemporaneous_jacobian, true))
+  if (!computeNonSingularNormalization(contemporaneous_jacobian))
     return false;
   auto [prologue, epilogue] = computePrologueAndEpilogue();
   auto first_order_endo_derivatives = collectFirstOrderDerivativesEndogenous();
   equationTypeDetermination(first_order_endo_derivatives, mfs);
-  cout << "Finding the optimal block decomposition of the dynamic model..." << endl;
+  cout << "Finding the optimal block decomposition of the " << modelClassName() << "..." << endl;
   computeBlockDecomposition(prologue, epilogue);
   reduceBlockDecomposition();
   printBlockDecomposition();
@@ -3663,7 +3663,7 @@ DynamicModel::writeSetAuxiliaryVariables(const string &basename, bool julia) con
     output << "ds = ";
   output << func_name + "(ds, params)" << endl
          << comment << endl
-         << comment << " Status : Computes Auxiliary variables of the dynamic model and returns a dseries" << endl
+         << comment << " Status : Computes Auxiliary variables of the " << modelClassName() << " and returns a dseries" << endl
          << comment << endl
          << comment << " Warning : this file is generated automatically by Dynare" << endl
          << comment << "           from model file (.mod)" << endl << endl;
diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh
index 37051525..458de8d1 100644
--- a/src/DynamicModel.hh
+++ b/src/DynamicModel.hh
@@ -303,6 +303,13 @@ private:
      (failure can happen in normalization). */
   virtual bool computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms);
 
+protected:
+  string
+  modelClassName() const override
+  {
+    return "dynamic model";
+  }
+
 public:
   DynamicModel(SymbolTable &symbol_table_arg,
                NumericalConstants &num_constants_arg,
diff --git a/src/ModFile.hh b/src/ModFile.hh
index 90d73f89..02bc8027 100644
--- a/src/ModFile.hh
+++ b/src/ModFile.hh
@@ -68,7 +68,7 @@ public:
   //! A copy of Dynamic model, for testing trends declared by user
   DynamicModel trend_dynamic_model;
   //! A copy of the original model, used to test model linearity under ramsey problem
-  DynamicModel orig_ramsey_dynamic_model;
+  OrigRamseyDynamicModel orig_ramsey_dynamic_model;
   //! Epilogue model, as declared in the "epilogue" block
   Epilogue epilogue;
   //! Static model, as derived from the "model" block when leads and lags have been removed
diff --git a/src/ModelEquationBlock.cc b/src/ModelEquationBlock.cc
index fe0d6491..58db1c8a 100644
--- a/src/ModelEquationBlock.cc
+++ b/src/ModelEquationBlock.cc
@@ -38,6 +38,23 @@ PlannerObjective::computingPassBlock([[maybe_unused]] const eval_context_t &eval
   return false;
 }
 
+OrigRamseyDynamicModel::OrigRamseyDynamicModel(SymbolTable &symbol_table_arg,
+                                               NumericalConstants &num_constants_arg,
+                                               ExternalFunctionsTable &external_functions_table_arg,
+                                               TrendComponentModelTable &trend_component_model_table_arg,
+                                               VarModelTable &var_model_table_arg) :
+  DynamicModel {symbol_table_arg, num_constants_arg, external_functions_table_arg,
+                trend_component_model_table_arg, var_model_table_arg}
+{
+}
+
+OrigRamseyDynamicModel &
+OrigRamseyDynamicModel::operator=(const DynamicModel &m)
+{
+  DynamicModel::operator=(m);
+  return *this;
+}
+
 SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg,
                                    NumericalConstants &num_constants_arg,
                                    ExternalFunctionsTable &external_functions_table_arg,
diff --git a/src/ModelEquationBlock.hh b/src/ModelEquationBlock.hh
index eb255e03..a34fb6dc 100644
--- a/src/ModelEquationBlock.hh
+++ b/src/ModelEquationBlock.hh
@@ -32,10 +32,35 @@ public:
   PlannerObjective(SymbolTable &symbol_table_arg,
                    NumericalConstants &num_constants_arg,
                    ExternalFunctionsTable &external_functions_table_arg);
+protected:
+  string
+  modelClassName() const override
+  {
+    return "planner objective";
+  }
+
 private:
   bool computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms) override;
 };
 
+class OrigRamseyDynamicModel : public DynamicModel
+{
+public:
+  OrigRamseyDynamicModel(SymbolTable &symbol_table_arg,
+                         NumericalConstants &num_constants_arg,
+                         ExternalFunctionsTable &external_functions_table_arg,
+                         TrendComponentModelTable &trend_component_model_table_arg,
+                         VarModelTable &var_model_table_arg);
+  OrigRamseyDynamicModel &operator=(const DynamicModel &m);
+
+protected:
+  string
+  modelClassName() const override
+  {
+    return "original Ramsey model";
+  }
+};
+
 class SteadyStateModel : public DataTree
 {
 private:
@@ -104,6 +129,14 @@ public:
 
   //! Write Output
   void writeOutput(ostream &output) const;
+
+protected:
+  string
+  modelClassName() const override
+  {
+    return "epilogue";
+  }
+
 private:
   //! Helper for public writeEpilogueFile
   void writeStaticEpilogueFile(const string &basename) const;
diff --git a/src/ModelTree.cc b/src/ModelTree.cc
index 8da7b1ad..1ad98dd6 100644
--- a/src/ModelTree.cc
+++ b/src/ModelTree.cc
@@ -202,7 +202,7 @@ ModelTree::operator=(const ModelTree &m)
 }
 
 bool
-ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic, bool verbose)
+ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose)
 {
   const int n = equations.size();
 
@@ -242,7 +242,7 @@ ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, boo
       it != mate_map.begin() + n)
     {
       if (verbose)
-        cerr << "Could not normalize the " << (dynamic ? "dynamic" : "static") << " model. Variable "
+        cerr << "Could not normalize the " << modelClassName() << " . Variable "
              << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, it - mate_map.begin()))
              << " is not in the maximum cardinality matching." << endl;
       check = false;
@@ -251,7 +251,7 @@ ModelTree::computeNormalization(const jacob_map_t &contemporaneous_jacobian, boo
 }
 
 bool
-ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic)
+ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian)
 {
   int n = equations.size();
 
@@ -259,11 +259,11 @@ ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_ja
      not have as many equations as variables. */
   if (n != symbol_table.endo_nbr())
     {
-      cout << "The " << (dynamic ? "dynamic" : "static") << " model cannot be normalized, since it does not have as many equations as variables." << endl;
+      cout << "The " << modelClassName() << " cannot be normalized, since it does not have as many equations as variables." << endl;
       return false;
     }
 
-  cout << "Normalizing the " << (dynamic ? "dynamic" : "static") << " model..." << endl;
+  cout << "Normalizing the " << modelClassName() << "..." << endl;
 
   // Compute the maximum value of each row of the contemporaneous Jacobian matrix
   vector max_val(n, 0.0);
@@ -293,14 +293,14 @@ ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_ja
           suppressed++;
 
       if (suppressed != last_suppressed)
-        found_normalization = computeNormalization(normalized_contemporaneous_jacobian_above_cutoff, dynamic, false);
+        found_normalization = computeNormalization(normalized_contemporaneous_jacobian_above_cutoff, false);
       last_suppressed = suppressed;
       if (!found_normalization)
         {
           current_cutoff /= 2;
           // In this last case try to normalize with the complete jacobian
           if (current_cutoff <= cutoff_lower_limit)
-            found_normalization = computeNormalization(normalized_contemporaneous_jacobian, dynamic, false);
+            found_normalization = computeNormalization(normalized_contemporaneous_jacobian, false);
         }
     }
 
@@ -311,7 +311,7 @@ ModelTree::computeNonSingularNormalization(const jacob_map_t &contemporaneous_ja
          normalization even with a potential singularity.
          TODO: Explain why symbolic_jacobian is not contemporaneous. */
       auto symbolic_jacobian = computeSymbolicJacobian();
-      found_normalization = computeNormalization(symbolic_jacobian, dynamic, true);
+      found_normalization = computeNormalization(symbolic_jacobian, true);
     }
 
   /* NB: If normalization failed, an explanatory message has been printed by the last call
diff --git a/src/ModelTree.hh b/src/ModelTree.hh
index ecb49614..fdeb5eca 100644
--- a/src/ModelTree.hh
+++ b/src/ModelTree.hh
@@ -344,7 +344,7 @@ protected:
     \param contemporaneous_jacobian Jacobian used as an incidence matrix: all elements declared in the map (even if they are zero), are used as vertices of the incidence matrix
     \return True if a complete normalization has been achieved
   */
-  bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic, bool verbose);
+  bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose);
 
   //! Try to compute the matching between endogenous and variable using a decreasing cutoff
   /*!
@@ -354,7 +354,7 @@ protected:
     The resulting normalization is stored in endo2eq.
     Returns a boolean indicating success.
   */
-  bool computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian, bool dynamic);
+  bool computeNonSingularNormalization(const jacob_map_t &contemporaneous_jacobian);
   //! Evaluate the jacobian (w.r.t. endogenous) and suppress all the elements below the cutoff
   /*! Returns the contemporaneous_jacobian.
       Elements below the cutoff are discarded. External functions are evaluated to 1. */
@@ -453,6 +453,9 @@ protected:
      “var” is the block-specific endogenous variable index. */
   virtual int getBlockJacobianEndoCol(int blk, int var, int lag) const = 0;
 
+  // Returns a human-readable string describing the model class (e.g. “dynamic model”…)
+  virtual string modelClassName() const = 0;
+
 private:
   //! Internal helper for the copy constructor and assignment operator
   /*! Copies all the structures that contain ExprNode*, by the converting the
diff --git a/src/StaticModel.cc b/src/StaticModel.cc
index 8636bd76..13a023f5 100644
--- a/src/StaticModel.cc
+++ b/src/StaticModel.cc
@@ -344,7 +344,7 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
      with DynamicModel::computingPass(). */
   if (log2(symbol_table.endo_nbr())*derivsOrder >= numeric_limits<int>::digits)
     {
-      cerr << "ERROR: The static derivatives matrix is too large. Please decrease the approximation order." << endl;
+      cerr << "ERROR: The derivatives matrix of the " << modelClassName() << " is too large. Please decrease the approximation order." << endl;
       exit(EXIT_FAILURE);
     }
 
@@ -357,13 +357,13 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
     }
 
   // Launch computations
-  cout << "Computing static model derivatives (order " << derivsOrder << ")." << endl;
+  cout << "Computing " << modelClassName() << " derivatives (order " << derivsOrder << ")." << endl;
 
   computeDerivatives(derivsOrder, vars);
 
   if (paramsDerivsOrder > 0)
     {
-      cout << "Computing static model derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
+      cout << "Computing " << modelClassName() << " derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
       computeParamsDerivatives(paramsDerivsOrder);
     }
 
@@ -385,12 +385,12 @@ bool
 StaticModel::computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms)
 {
   auto contemporaneous_jacobian = evaluateAndReduceJacobian(eval_context);
-  if (!computeNonSingularNormalization(contemporaneous_jacobian, false))
+  if (!computeNonSingularNormalization(contemporaneous_jacobian))
     return false;
   auto [prologue, epilogue] = computePrologueAndEpilogue();
   auto first_order_endo_derivatives = collectFirstOrderDerivativesEndogenous();
   equationTypeDetermination(first_order_endo_derivatives, mfs);
-  cout << "Finding the optimal block decomposition of the static model..." << endl;
+  cout << "Finding the optimal block decomposition of the " << modelClassName() << "..." << endl;
   computeBlockDecomposition(prologue, epilogue);
   reduceBlockDecomposition();
   printBlockDecomposition();
@@ -637,7 +637,7 @@ StaticModel::writeStaticCFile(const string &basename) const
     }
 
   output << "/*" << endl
-         << " * " << filename << " : Computes static model for Dynare" << endl
+         << " * " << filename << " : Computes " << modelClassName() << " for Dynare" << endl
          << " *" << endl
          << " * Warning : this file is generated automatically by Dynare" << endl
          << " *           from model file (.mod)" << endl << endl
@@ -1325,7 +1325,7 @@ StaticModel::writeSetAuxiliaryVariables(const string &basename, bool julia) cons
     output << "y = ";
   output << func_name << "(y, x, params)" << endl
          << comment << endl
-         << comment << " Status : Computes static model for Dynare" << endl
+         << comment << " Status : Computes Auxiliary variables of the " << modelClassName() << endl
          << comment << endl
          << comment << " Warning : this file is generated automatically by Dynare" << endl
          << comment << "           from model file (.mod)" << endl << endl;
diff --git a/src/StaticModel.hh b/src/StaticModel.hh
index da652839..127252b1 100644
--- a/src/StaticModel.hh
+++ b/src/StaticModel.hh
@@ -116,6 +116,13 @@ private:
      (failure can happen in normalization). */
   virtual bool computingPassBlock(const eval_context_t &eval_context, bool no_tmp_terms);
 
+protected:
+  string
+  modelClassName() const override
+  {
+    return "static model";
+  }
+
 public:
   StaticModel(SymbolTable &symbol_table_arg,
               NumericalConstants &num_constants,
-- 
GitLab