From 2af26ee2c2815f2ec9d75a48fd562b8e90d37e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= <sebastien@dynare.org> Date: Fri, 13 Dec 2019 17:15:03 +0100 Subject: [PATCH] Ramsey: use information from transformed model for filling M_.nonzero_hessian_eqs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit 9c9e8f816f056fb4f9f2b17234ba7c100f3a996a, it’s the information from the original model which was in this field, which is not what is expected. By the way, do not output this field (and the related M_.hessian_eq_zero) when the Hessian is not computed by the preprocessor (i.e. in practice for perfect foresight), since they would otherwise contain incorrect information. Ref. dynare#1681 --- src/DynamicModel.cc | 30 +++++++------------------- src/DynamicModel.hh | 18 +++++++++++++--- src/ModFile.cc | 51 ++++++++++++++++++++++++++------------------- src/ModelTree.hh | 11 ++++++++++ 4 files changed, 63 insertions(+), 47 deletions(-) diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 767f4cb5..5fe95c94 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -1875,33 +1875,12 @@ DynamicModel::printNonZeroHessianEquations(ostream &output) const { if (it != nonzero_hessian_eqs.begin()) output << " "; - output << it->first; + output << *it; } if (nonzero_hessian_eqs.size() != 1) output << "]"; } -void -DynamicModel::setNonZeroHessianEquations(map<int, string> &eqs) -{ - for (const auto &it : derivatives[2]) - { - int eq = it.first[0]; - if (nonzero_hessian_eqs.find(eq) == nonzero_hessian_eqs.end()) - { - nonzero_hessian_eqs[eq] = ""; - for (auto & equation_tag : equation_tags) - if (equation_tag.first == eq) - if (equation_tag.second.first == "name") - { - nonzero_hessian_eqs[eq] = equation_tag.second.second; - break; - } - } - } - eqs = nonzero_hessian_eqs; -} - void DynamicModel::Write_Inf_To_Bin_File_Block(const string &basename, const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries, const bool linear_decomposition) const @@ -5003,6 +4982,13 @@ DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsO computeDerivatives(derivsOrder, vars); + if (derivsOrder > 1) + { + hessian_computed = true; + for (const auto &it : derivatives[2]) + nonzero_hessian_eqs.insert(it.first[0]); + } + if (paramsDerivsOrder > 0) { cout << "Computing dynamic model derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl; diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 575c72ae..b7973aa4 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -98,7 +98,9 @@ private: map<pair<int, int>, set<int>> xref_exo_det; //! Nonzero equations in the Hessian - map<int, string> nonzero_hessian_eqs; + set<int> nonzero_hessian_eqs; + //! Whether the hessian has actually been computed + bool hessian_computed{false}; //! Number of columns of dynamic jacobian /*! Set by computeDerivID()s and computeDynJacobianCols() */ @@ -354,8 +356,18 @@ public: //! Print equations that have non-zero second derivatives void printNonZeroHessianEquations(ostream &output) const; - //! Set the equations that have non-zero second derivatives - void setNonZeroHessianEquations(map<int, string> &eqs); + //! Tells whether Hessian has been computed + /*! This is needed to know whether no non-zero equation in Hessian means a + zero Hessian or Hessian not computed */ + inline bool isHessianComputed() const + { + return hessian_computed; + } + //! Returns equations that have non-zero second derivatives + inline set<int> getNonZeroHessianEquations() const + { + return nonzero_hessian_eqs; + } //! Fill Autoregressive Matrix for var_model map<string, map<tuple<int, int, int>, expr_t>> fillAutoregressiveMatrix(bool is_var) const; diff --git a/src/ModFile.cc b/src/ModFile.cc index 7f1e5d4a..14f776a5 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -802,24 +802,31 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri else // No computing task requested, compute derivatives up to 2nd order by default dynamic_model.computingPass(true, 2, 0, global_eval_context, no_tmp_terms, block, use_dll, byte_code, linear_decomposition); - map<int, string> eqs; - if (mod_file_struct.ramsey_model_present) - orig_ramsey_dynamic_model.setNonZeroHessianEquations(eqs); - else - dynamic_model.setNonZeroHessianEquations(eqs); - - if (linear && !eqs.empty()) + /* Check that the model is linear. + FIXME: this check always passes if derivsOrder = 1, i.e. for a perfect + foresight model, because the Hessian is not computed in that case. */ + if (linear) { - cerr << "ERROR: If the model is declared linear the second derivatives must be equal to zero." << endl - << " The following equations had non-zero second derivatives:" << endl; - for (map<int, string >::const_iterator it = eqs.begin(); it != eqs.end(); it++) + set<int> eqs; + if (mod_file_struct.ramsey_model_present) + eqs = orig_ramsey_dynamic_model.getNonZeroHessianEquations(); + else + eqs = dynamic_model.getNonZeroHessianEquations(); + + if (!eqs.empty()) { - cerr << " * Eq # " << it->first+1; - if (!it->second.empty()) - cerr << " [" << it->second << "]"; - cerr << endl; + cerr << "ERROR: If the model is declared linear the second derivatives must be equal to zero." << endl + << " The following equations have non-zero second derivatives:" << endl; + for (const auto &it : eqs) + { + cerr << " * Eq # " << it+1; + auto tags = dynamic_model.getEquationTags(it); + if (auto it2 = tags.find("name"); it2 != tags.end()) + cerr << " [" << it2->second << "]"; + cerr << endl; + } + exit(EXIT_FAILURE); } - exit(EXIT_FAILURE); } } @@ -992,13 +999,13 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all, bool clear_glo mOutputFile << "};" << endl; } - mOutputFile << "M_.nonzero_hessian_eqs = "; - if (mod_file_struct.ramsey_model_present) - orig_ramsey_dynamic_model.printNonZeroHessianEquations(mOutputFile); - else - dynamic_model.printNonZeroHessianEquations(mOutputFile); - mOutputFile << ";" << endl - << "M_.hessian_eq_zero = isempty(M_.nonzero_hessian_eqs);" << endl; + if (dynamic_model.isHessianComputed()) + { + mOutputFile << "M_.nonzero_hessian_eqs = "; + dynamic_model.printNonZeroHessianEquations(mOutputFile); + mOutputFile << ";" << endl + << "M_.hessian_eq_zero = isempty(M_.nonzero_hessian_eqs);" << endl; + } if (!onlymodel) config_file.writeCluster(mOutputFile); diff --git a/src/ModelTree.hh b/src/ModelTree.hh index a0914aff..e9b9d4a9 100644 --- a/src/ModelTree.hh +++ b/src/ModelTree.hh @@ -382,6 +382,17 @@ public: /*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[2]] If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[3]] */ void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const; + + //! Returns all the equation tags associated to an equation + inline map<string, string> getEquationTags(int eq) const + { + map<string, string> r; + for (auto &[eq2, tagpair]: equation_tags) + if (eq2 == eq) + r[tagpair.first] = tagpair.second; + return r; + } + inline static std::string c_Equation_Type(int type) { -- GitLab