From 0c1373bc5e796858533b4b8ded6cb72936111a4f Mon Sep 17 00:00:00 2001 From: Houtan Bastani <houtan@dynare.org> Date: Tue, 10 Sep 2019 12:37:11 +0200 Subject: [PATCH] stop processing when certain functions are used in a linear context on endogenous/exogenous variables. closes dynare#1537 --- src/DataTree.cc | 28 ++++++++++++++++++++++++++++ src/DataTree.hh | 6 +++++- src/ModFile.cc | 48 ++++++++++++++++++++++++++++++++++++------------ 3 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/DataTree.cc b/src/DataTree.cc index 4c6a4151..28dbbc6d 100644 --- a/src/DataTree.cc +++ b/src/DataTree.cc @@ -765,6 +765,20 @@ DataTree::isUnaryOpUsed(UnaryOpcode opcode) const return false; } +bool +DataTree::isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const +{ + set<int> var; + for (const auto & it : unary_op_node_map) + if (get<1>(it.first) == opcode) + { + it.second->collectVariables(type, var); + if (!var.empty()) + return true; + } + return false; +} + bool DataTree::isBinaryOpUsed(BinaryOpcode opcode) const { @@ -775,6 +789,20 @@ DataTree::isBinaryOpUsed(BinaryOpcode opcode) const return false; } +bool +DataTree::isBinaryOpUsedOnType(SymbolType type, BinaryOpcode opcode) const +{ + set<int> var; + for (const auto & it : binary_op_node_map) + if (get<2>(it.first) == opcode) + { + it.second->collectVariables(type, var); + if (!var.empty()) + return true; + } + return false; +} + bool DataTree::isTrinaryOpUsed(TrinaryOpcode opcode) const { diff --git a/src/DataTree.hh b/src/DataTree.hh index 9b62ad6a..6fb6bb71 100644 --- a/src/DataTree.hh +++ b/src/DataTree.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2018 Dynare Team + * Copyright © 2003-2019 Dynare Team * * This file is part of Dynare. * @@ -261,8 +261,12 @@ public: bool isSymbolUsed(int symb_id) const; //! Checks if a given unary op is used somewhere in the data tree bool isUnaryOpUsed(UnaryOpcode opcode) const; + //! Checks if a given unary op is used somewhere in the data tree on an endogenous variable + bool isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const; //! Checks if a given binary op is used somewhere in the data tree bool isBinaryOpUsed(BinaryOpcode opcode) const; + //! Checks if a given binary op is used somewhere in the data tree on an endogenous variable + bool isBinaryOpUsedOnType(SymbolType type, BinaryOpcode opcode) const; //! Checks if a given trinary op is used somewhere in the data tree bool isTrinaryOpUsed(TrinaryOpcode opcode) const; //! Checks if a given external function is used somewhere in the data tree diff --git a/src/ModFile.cc b/src/ModFile.cc index dfa4d68e..00ea67b1 100644 --- a/src/ModFile.cc +++ b/src/ModFile.cc @@ -307,17 +307,41 @@ ModFile::checkPass(bool nostrict, bool stochastic) warnings << R"(WARNING: you are using a function (max, min, abs, sign) or an operator (<, >, <=, >=, ==, !=) which is unsuitable for a stochastic context; see the reference manual, section about "Expressions", for more details.)" << endl; if (linear - && (dynamic_model.isUnaryOpUsed(UnaryOpcode::sign) - || dynamic_model.isUnaryOpUsed(UnaryOpcode::abs) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::max) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::min) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::greater) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::less) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::greaterEqual) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::lessEqual) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::equalEqual) - || dynamic_model.isBinaryOpUsed(BinaryOpcode::different))) - warnings << "WARNING: you have declared your model 'linear' but you are using a function (max, min, abs, sign) or an operator (<, >, <=, >=, ==, !=) which potentially makes it non-linear." << endl; + && (dynamic_model.isUnaryOpUsedOnType(SymbolType::endogenous, UnaryOpcode::sign) + || dynamic_model.isUnaryOpUsedOnType(SymbolType::endogenous, UnaryOpcode::abs) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::max) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::min) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::greater) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::less) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::greaterEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::lessEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::equalEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::endogenous, BinaryOpcode::different))) + { + cerr << "ERROR: you have declared your model 'linear' but you are using a function " + << "(max, min, abs, sign) or an operator (<, >, <=, >=, ==, !=) on an " + << "endogenous variable." << endl; + exit(EXIT_FAILURE); + } + + if (linear + && !mod_file_struct.perfect_foresight_solver_present + && (dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::sign) + || dynamic_model.isUnaryOpUsedOnType(SymbolType::exogenous, UnaryOpcode::abs) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::max) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::min) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::greater) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::less) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::greaterEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::lessEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::equalEqual) + || dynamic_model.isBinaryOpUsedOnType(SymbolType::exogenous, BinaryOpcode::different))) + { + cerr << "ERROR: you have declared your model 'linear' but you are using a function " + << "(max, min, abs, sign) or an operator (<, >, <=, >=, ==, !=) on an " + << "exogenous variable in a non-perfect-foresight context." << endl; + exit(EXIT_FAILURE); + } // Test if some estimated parameters are used within the values of shocks // statements (see issue #469) @@ -1193,7 +1217,7 @@ ModFile::writeExternalFilesJulia(const string &basename, FileOutputType output) jlOutputFile << endl << "options_ = dynare_options()" << endl << R"(options_.dynare_version = ")" << PACKAGE_VERSION << R"(")" << endl; - if (linear == 1) + if (linear) jlOutputFile << "options_.linear = true" << endl; // Write Model -- GitLab