From 22000da5eac20dec7c61511422a24dc8e6199ac8 Mon Sep 17 00:00:00 2001
From: sebastien <sebastien@ac1d8469-bf42-47a9-8791-bf33cf982152>
Date: Mon, 21 Dec 2009 10:29:21 +0000
Subject: [PATCH] Changes by Ferhat: * fix options stack_solve_algo={2,3,4}
 (closes #68) * fix crashes for singular normalizations (closes #44) and
 implement decreasing cutoff * fail for stack_solve_algo=2 under Octave
 (because there is no gmres function in Octave)

git-svn-id: https://www.dynare.org/svn/dynare/trunk@3279 ac1d8469-bf42-47a9-8791-bf33cf982152
---
 DynamicModel.cc |   2 +-
 ModelTree.cc    | 109 +++++++++++++++++++++++++++++++-----------------
 ModelTree.hh    |  29 ++++++-------
 StaticModel.cc  |   6 +--
 StaticModel.hh  |   2 +-
 5 files changed, 89 insertions(+), 59 deletions(-)

diff --git a/DynamicModel.cc b/DynamicModel.cc
index 26b7c2c9..1bfb09d6 100644
--- a/DynamicModel.cc
+++ b/DynamicModel.cc
@@ -1995,7 +1995,7 @@ DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivative
 
       evaluateAndReduceJacobian(eval_context, contemporaneous_jacobian, static_jacobian, dynamic_jacobian, cutoff, false);
 
-      computePossiblySingularNormalization(contemporaneous_jacobian, cutoff == 0);
+      computeNonSingularNormalization(contemporaneous_jacobian, cutoff, static_jacobian, dynamic_jacobian);
 
       computePrologueAndEpilogue(static_jacobian, equation_reordered, variable_reordered, prologue, epilogue);
 
diff --git a/ModelTree.cc b/ModelTree.cc
index 0b285315..d7d6f1e2 100644
--- a/ModelTree.cc
+++ b/ModelTree.cc
@@ -32,8 +32,8 @@
 using namespace boost;
 using namespace MFS;
 
-void
-ModelTree::computeNormalization(const set<pair<int, int> > &endo_eqs_incidence) throw (NormalizationException)
+bool
+ModelTree::computeNormalization(const jacob_map &contemporaneous_jacobian, bool verbose)
 {
   const int n = equation_number();
 
@@ -50,8 +50,8 @@ ModelTree::computeNormalization(const set<pair<int, int> > &endo_eqs_incidence)
   // Fill in the graph
   set<pair<int, int> > endo;
 
-  for (set<pair<int, int> >::const_iterator it = endo_eqs_incidence.begin(); it != endo_eqs_incidence.end(); it++)
-    add_edge(it->first + n, it->second, g);
+  for (jacob_map::const_iterator it = contemporaneous_jacobian.begin(); it != contemporaneous_jacobian.end(); it++)
+    add_edge(it->first.first + n, it->first.second, g);
 
   // Compute maximum cardinality matching
   vector<int> mate_map(2*n);
@@ -125,63 +125,96 @@ ModelTree::computeNormalization(const set<pair<int, int> > &endo_eqs_incidence)
   // Check if all variables are normalized
   vector<int>::const_iterator it = find(mate_map.begin(), mate_map.begin() + n, graph_traits<BipartiteGraph>::null_vertex());
   if (it != mate_map.begin() + n)
-    throw NormalizationException(symbol_table.getID(eEndogenous, it - mate_map.begin()));
+    {
+      if (verbose)
+        cerr << "ERROR: Could not normalize the model. Variable "
+             << symbol_table.getName(symbol_table.getID(eEndogenous, it - mate_map.begin()))
+             << " is not in the maximum cardinality matching." << endl;
+      check = false;
+    }
+  return check;
 }
 
 void
-ModelTree::computePossiblySingularNormalization(const jacob_map &contemporaneous_jacobian, bool try_symbolic)
+ModelTree::computeNonSingularNormalization(jacob_map &contemporaneous_jacobian, double cutoff, jacob_map &static_jacobian, dynamic_jacob_map &dynamic_jacobian)
 {
+  bool check = false;
+
   cout << "Normalizing the model..." << endl;
 
-  set<pair<int, int> > endo_eqs_incidence;
+  int n = equation_number();
 
-  for (jacob_map::const_iterator it = contemporaneous_jacobian.begin();
-       it != contemporaneous_jacobian.end(); it++)
-    endo_eqs_incidence.insert(make_pair(it->first.first, it->first.second));
+  // compute the maximum value of each row of the contemporaneous Jacobian matrix
+  //jacob_map normalized_contemporaneous_jacobian;
+  jacob_map normalized_contemporaneous_jacobian(contemporaneous_jacobian);
+  vector<double> max_val(n, 0.0);
+  for (jacob_map::const_iterator iter = contemporaneous_jacobian.begin(); iter != contemporaneous_jacobian.end(); iter++)
+    if (fabs(iter->second) > max_val[iter->first.first])
+      max_val[iter->first.first] = fabs(iter->second);
 
-  try
-    {
-      computeNormalization(endo_eqs_incidence);
-      return;
-    }
-  catch (NormalizationException &e)
+  for (jacob_map::iterator iter = normalized_contemporaneous_jacobian.begin(); iter != normalized_contemporaneous_jacobian.end(); iter++)
+    iter->second /= max_val[iter->first.first];
+
+  //We start with the highest value of the cutoff and try to normalize the model
+  double current_cutoff = 0.99999999;
+
+  int suppressed = 0;
+  while (!check && current_cutoff > 1e-19)
     {
-      if (try_symbolic)
-        cout << "Normalization failed with cutoff, trying symbolic normalization..." << endl;
-      else
+      jacob_map tmp_normalized_contemporaneous_jacobian;
+      int suppress = 0;
+      for (jacob_map::iterator iter = normalized_contemporaneous_jacobian.begin(); iter != normalized_contemporaneous_jacobian.end(); iter++)
+        if (fabs(iter->second) > max(current_cutoff, cutoff))
+          tmp_normalized_contemporaneous_jacobian[make_pair(iter->first.first, iter->first.second)] = iter->second;
+        else
+          suppress++;
+
+      if (suppress != suppressed)
+        check = computeNormalization(tmp_normalized_contemporaneous_jacobian, false);
+      suppressed = suppress;
+      if (!check)
         {
-          cerr << "ERROR: Could not normalize the model. Variable "
-               << symbol_table.getName(e.symb_id)
-               << " is not in the maximum cardinality matching. Try to decrease the cutoff." << endl;
-          exit(EXIT_FAILURE);
+          current_cutoff /= 2;
+          // In this last case try to normalize with the complete jacobian
+          if (current_cutoff <= 1e-19)
+            check = computeNormalization(normalized_contemporaneous_jacobian, false);
         }
     }
 
-  // If no non-singular normalization can be found, try to find a normalization even with a potential singularity
-  if (try_symbolic)
+  if (!check)
     {
-      endo_eqs_incidence.clear();
+      cout << "Normalization failed with cutoff, trying symbolic normalization..." << endl;
+      //if no non-singular normalization can be found, try to find a normalization even with a potential singularity
+      jacob_map tmp_normalized_contemporaneous_jacobian;
       set<pair<int, int> > endo;
-      for (int i = 0; i < equation_number(); i++)
+      for (int i = 0; i < n; i++)
         {
           endo.clear();
           equations[i]->collectEndogenous(endo);
           for (set<pair<int, int> >::const_iterator it = endo.begin(); it != endo.end(); it++)
-            endo_eqs_incidence.insert(make_pair(i, it->first));
+            tmp_normalized_contemporaneous_jacobian[make_pair(i, it->first)] = 1;
         }
-
-      try
+      check = computeNormalization(tmp_normalized_contemporaneous_jacobian, true);
+      if (check)
         {
-          computeNormalization(endo_eqs_incidence);
-        }
-      catch (NormalizationException &e)
-        {
-          cerr << "ERROR: Could not normalize the model even with zero cutoff. Variable "
-               << symbol_table.getName(e.symb_id)
-               << " is not in the maximum cardinality matching." << endl;
-          exit(EXIT_FAILURE);
+          // Update the jacobian matrix
+          for (jacob_map::const_iterator it = tmp_normalized_contemporaneous_jacobian.begin(); it != tmp_normalized_contemporaneous_jacobian.end(); it++)
+            {
+              if (static_jacobian.find(make_pair(it->first.first, it->first.second)) == static_jacobian.end())
+                static_jacobian[make_pair(it->first.first, it->first.second)] = 0;
+              if (dynamic_jacobian.find(make_pair(0, make_pair(it->first.first, it->first.second))) == dynamic_jacobian.end())
+                dynamic_jacobian[make_pair(0, make_pair(it->first.first, it->first.second))] = 0;
+              if (contemporaneous_jacobian.find(make_pair(it->first.first, it->first.second)) == contemporaneous_jacobian.end())
+                contemporaneous_jacobian[make_pair(it->first.first, it->first.second)] = 0;
+            }
         }
     }
+
+  if (!check)
+    {
+      cerr << "No normalization could be computed. Aborting." << endl;
+      exit(EXIT_FAILURE);
+    }
 }
 
 void
diff --git a/ModelTree.hh b/ModelTree.hh
index 7b1d7036..4614a12c 100644
--- a/ModelTree.hh
+++ b/ModelTree.hh
@@ -136,24 +136,21 @@ protected:
   //! for each block contains pair< max_lag, max_lead>
   t_lag_lead_vector block_lag_lead;
 
-  //! Exception thrown when normalization fails
-  class NormalizationException
-  {
-  public:
-    //! A variable missing from the maximum cardinal matching
-    int symb_id;
-    NormalizationException(int symb_id_arg) : symb_id(symb_id_arg)
-    {
-    }
-  };
-
   //! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
-  /*! \param endo_eqs_incidence A set indicating which endogenous appear in which equation. First element of pairs is equation number, second is type specific endo ID */
-  void computeNormalization(const set<pair<int, int> > &endo_eqs_incidence) throw (NormalizationException);
+  /*!
+    \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 &contemporaneous_jacobian, bool verbose);
+
   //! Try to compute the matching between endogenous and variable using a decreasing cutoff
-  /*! applied to the jacobian contemporaneous_jacobian and stop when a matching is found.*/
-  /*! if no matching is found with a cutoff close to zero an error message is printout */
-  void computePossiblySingularNormalization(const jacob_map &contemporaneous_jacobian, bool try_symbolic);
+  /*!
+    Applied to the jacobian contemporaneous_jacobian and stop when a matching is found.
+    If no matching is found using a strictly positive cutoff, then a zero cutoff is applied (i.e. use a symbolic normalization); in that case, the method adds zeros in the jacobian matrices to reflect all the edges in the symbolic incidence matrix.
+    If no matching is found with a zero cutoff close to zero an error message is printout.
+  */
+  void computeNonSingularNormalization(jacob_map &contemporaneous_jacobian, double cutoff, jacob_map &static_jacobian, dynamic_jacob_map &dynamic_jacobian);
+
   //! Try to normalized each unnormalized equation (matched endogenous variable only on the LHS)
   void computeNormalizedEquations(multimap<int, int> &endo2eqs) const;
   //! Evaluate the jacobian and suppress all the elements below the cutoff
diff --git a/StaticModel.cc b/StaticModel.cc
index 784403e7..6bce4e2b 100644
--- a/StaticModel.cc
+++ b/StaticModel.cc
@@ -45,7 +45,7 @@ StaticModel::StaticModel(SymbolTable &symbol_table_arg,
 }
 
 void
-StaticModel::compileDerivative(ofstream &code_file, int eq, int symb_id, int lag, map_idx_type &map_idx) const
+StaticModel::compileDerivative(ofstream &code_file, int eq, int symb_id, map_idx_type &map_idx) const
 {
   first_derivatives_type::const_iterator it = first_derivatives.find(make_pair(eq, symbol_table.getID(eEndogenous, symb_id)));
   if (it != first_derivatives.end())
@@ -539,7 +539,7 @@ StaticModel::writeModelEquationsCodeOrdered(const string file_name, const string
             {
             case SOLVE_BACKWARD_SIMPLE:
             case SOLVE_FORWARD_SIMPLE:
-              compileDerivative(code_file, getBlockEquationID(block, 0), getBlockVariableID(block, 0), 0, map_idx);
+              compileDerivative(code_file, getBlockEquationID(block, 0), getBlockVariableID(block, 0), map_idx);
               {
                 FSTPG_ fstpg(0);
                 fstpg.write(code_file);
@@ -727,7 +727,7 @@ StaticModel::computingPass(const eval_context_type &eval_context, bool no_tmp_te
 
       evaluateAndReduceJacobian(eval_context, contemporaneous_jacobian, static_jacobian, dynamic_jacobian, cutoff, false);
 
-      computePossiblySingularNormalization(contemporaneous_jacobian, cutoff == 0);
+      computeNonSingularNormalization(contemporaneous_jacobian, cutoff, static_jacobian, dynamic_jacobian);
 
       computePrologueAndEpilogue(static_jacobian, equation_reordered, variable_reordered, prologue, epilogue);
 
diff --git a/StaticModel.hh b/StaticModel.hh
index 5b82ab54..1dbfb07d 100644
--- a/StaticModel.hh
+++ b/StaticModel.hh
@@ -74,7 +74,7 @@ private:
 
   void computeTemporaryTermsOrdered();
   //! Write derivative code of an equation w.r. to a variable
-  void compileDerivative(ofstream &code_file, int eq, int symb_id, int lag, map_idx_type &map_idx) const;
+  void compileDerivative(ofstream &code_file, int eq, int symb_id, map_idx_type &map_idx) const;
   //! Write chain rule derivative code of an equation w.r. to a variable
   void compileChainRuleDerivative(ofstream &code_file, int eq, int var, int lag, map_idx_type &map_idx) const;
 
-- 
GitLab