diff --git a/src/DynareBison.yy b/src/DynareBison.yy index 60260678c638fee083fc09d81a81e08668a117e5..4aed10f57910902da4d599927f15c28a9ae95d61 100644 --- a/src/DynareBison.yy +++ b/src/DynareBison.yy @@ -215,7 +215,7 @@ str_tolower(string s) %token ENDVAL_STEADY STEADY_SOLVE_ALGO STEADY_MAXIT STEADY_TOLF STEADY_TOLX STEADY_MARKOWITZ %token HOMOTOPY_MAX_COMPLETION_SHARE HOMOTOPY_MIN_STEP_SIZE HOMOTOPY_INITIAL_STEP_SIZE HOMOTOPY_STEP_SIZE_INCREASE_SUCCESS_COUNT %token HOMOTOPY_LINEARIZATION_FALLBACK HOMOTOPY_MARGINAL_LINEARIZATION_FALLBACK HOMOTOPY_EXCLUDE_VAREXO FROM_INITVAL_TO_ENDVAL -%token STATIC_MFS RELATIVE_TO_INITVAL MATCHED_IRFS MATCHED_IRFS_WEIGHTS WEIGHTS +%token STATIC_MFS RELATIVE_TO_INITVAL MATCHED_IRFS MATCHED_IRFS_WEIGHTS WEIGHTS PERPENDICULAR %token <vector<string>> SYMBOL_VEC @@ -1011,6 +1011,14 @@ equation : hand_side EQUAL hand_side ';' { $$ = driver.add_model_equal($4, $6, $2); } | '[' tag_pair_list ']' hand_side ';' { $$ = driver.add_model_equal_with_zero_rhs($4, $2); } + | hand_side EQUAL hand_side PERPENDICULAR hand_side ';' + { $$ = driver.add_model_equal($1, $3, {}, $5); } + | hand_side PERPENDICULAR hand_side ';' + { $$ = driver.add_model_equal_with_zero_rhs($1, {}, $3); } + | '[' tag_pair_list ']' hand_side EQUAL hand_side PERPENDICULAR hand_side ';' + { $$ = driver.add_model_equal($4, $6, $2, $8); } + | '[' tag_pair_list ']' hand_side PERPENDICULAR hand_side ';' + { $$ = driver.add_model_equal_with_zero_rhs($4, $2, $6); } ; tag_pair_list : tag_pair_list COMMA tag_pair diff --git a/src/DynareFlex.ll b/src/DynareFlex.ll index 618bf379c02cb32ed799fb05feb7f384dfbdbf63..13d14405ef323eca3dab328106bd17456acc988b 100644 --- a/src/DynareFlex.ll +++ b/src/DynareFlex.ll @@ -1016,6 +1016,8 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]) <DYNARE_STATEMENT,DYNARE_BLOCK>nan {return token::NAN_CONSTANT;} <DYNARE_STATEMENT,DYNARE_BLOCK>inf {return token::INF_CONSTANT;} <DYNARE_STATEMENT,DYNARE_BLOCK>constants {return token::CONSTANTS;} +<DYNARE_BLOCK>⟂ {return token::PERPENDICULAR;} +<DYNARE_BLOCK>_\|_ {return token::PERPENDICULAR;} /* options for GSA module by Marco Ratto */ <DYNARE_STATEMENT>identification {return token::IDENTIFICATION;} diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index c8733c18dd3dcd4233ef1e7f221ec429fa3c9a8c..7f351fdac309d52af756b55f56d4b7c8af901bed 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2023 Dynare Team + * Copyright © 2003-2024 Dynare Team * * This file is part of Dynare. * @@ -2626,7 +2626,8 @@ ParsingDriver::extended_path() } expr_t -ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags) +ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags, + expr_t complementarity_condition) { expr_t id = model_tree->AddEqual(arg1, arg2); @@ -2634,6 +2635,28 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_ if (key == "endogenous") declare_or_change_type(SymbolType::endogenous, value); + if (eq_tags.contains("mcp")) + { + if (complementarity_condition) + error("Can't have both an 'mcp' tag and a complementarity condition after the " + "perpendicular symbol"); + else + warning("Specifying complementarity conditions with the 'mcp' tag is obsolete. Please " + "consider switching to the new syntax using the perpendicular symbol."); + } + + if (complementarity_condition) + { + if (auto bcomp = dynamic_cast<BinaryOpNode*>(complementarity_condition); + !(bcomp + && (bcomp->op_code == BinaryOpcode::less || bcomp->op_code == BinaryOpcode::lessEqual + || bcomp->op_code == BinaryOpcode::greater + || bcomp->op_code == BinaryOpcode::greaterEqual))) + error("The complementarity constraint must be an inequality."); + + eq_tags.emplace("mcp", complementarity_condition->toString()); + } + if (eq_tags.contains("static")) { // If the equation is tagged [static] @@ -2723,9 +2746,10 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_ } expr_t -ParsingDriver::add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags) +ParsingDriver::add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags, + expr_t complementarity_condition) { - return add_model_equal(arg, model_tree->Zero, move(eq_tags)); + return add_model_equal(arg, model_tree->Zero, move(eq_tags), complementarity_condition); } void diff --git a/src/ParsingDriver.hh b/src/ParsingDriver.hh index 724aabd86f1d485a403e1ce94ca208ecaf901e38..a664d1c52e5464aab64efae1e573b0f2c06401e7 100644 --- a/src/ParsingDriver.hh +++ b/src/ParsingDriver.hh @@ -1,5 +1,5 @@ /* - * Copyright © 2003-2023 Dynare Team + * Copyright © 2003-2024 Dynare Team * * This file is part of Dynare. * @@ -748,9 +748,11 @@ public: //! Extended path void extended_path(); //! Writes token "arg1=arg2" to model tree - expr_t add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags); + expr_t add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_tags, + expr_t complementarity_condition = nullptr); //! Writes token "arg=0" to model tree - expr_t add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags); + expr_t add_model_equal_with_zero_rhs(expr_t arg, map<string, string> eq_tags, + expr_t complementarity_condition = nullptr); //! Writes token "arg1+arg2" to model tree expr_t add_plus(expr_t arg1, expr_t arg2); //! Writes token "arg1-arg2" to model tree