diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 7bc4574e74f44e2c38073c88b76bd4dca1a53c6a..28ab0c6c8b991af15763e4a622405b6950ed5f1d 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -3663,8 +3663,8 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de int optim_share_index; set<pair<int, pair<int, int>>> ar_params_and_vars; pair<int, pair<vector<int>, vector<bool>>> ec_params_and_vars; - vector<tuple<int, int, int, double>> non_optim_vars_params_and_constants; - tie(lhs_pac_var, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants) = pit.second; + vector<tuple<int, int, int, double>> non_optim_vars_params_and_constants, additive_vars_params_and_constants; + tie(lhs_pac_var, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants) = pit.second; string substruct = pit.first.first + ".equations." + pit.first.second + "."; output << modstruct << "pac." << substruct << "lhs_var = " @@ -3733,6 +3733,43 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de output << get<3>(it) << " "; output << "];" << endl; } + if (!additive_vars_params_and_constants.empty()) + { + output << modstruct << "pac." << substruct << "additive.params = ["; + for (auto & it : additive_vars_params_and_constants) + if (get<2>(it) >= 0) + output << symbol_table.getTypeSpecificID(get<2>(it)) + 1 << " "; + else + output << "NaN "; + output << "];" << endl + << modstruct << "pac." << substruct << "additive.vars = ["; + for (auto & it : additive_vars_params_and_constants) + output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " "; + output << "];" << endl + << modstruct << "pac." << substruct << "additive.isendo = ["; + for (auto & it : additive_vars_params_and_constants) + switch (symbol_table.getType(get<0>(it))) + { + case SymbolType::endogenous: + output << "true "; + break; + case SymbolType::exogenous: + output << "false "; + break; + default: + cerr << "expecting endogenous or exogenous" << endl; + exit(EXIT_FAILURE); + } + output << "];" << endl + << modstruct << "pac." << substruct << "additive.lags = ["; + for (auto & it : additive_vars_params_and_constants) + output << get<1>(it) << " "; + output << "];" << endl + << modstruct << "pac." << substruct << "additive.scaling_factor = ["; + for (auto & it : additive_vars_params_and_constants) + output << get<3>(it) << " "; + output << "];" << endl; + } // Create empty h0 and h1 substructures that will be overwritten later if not empty output << modstruct << "pac." << substruct << "h0_param_indices = [];" << endl << modstruct << "pac." << substruct << "h1_param_indices = [];" << endl; @@ -4384,18 +4421,17 @@ DynamicModel::walkPacParameters(const string &name, map<pair<string, string>, pa pair<int, int> lhs (-1, -1); pair<int, pair<vector<int>, vector<bool>>> ec_params_and_vars; set<pair<int, pair<int, int>>> ar_params_and_vars; - vector<tuple<int, int, int, double>> non_optim_vars_params_and_constants; + vector<tuple<int, int, int, double>> non_optim_vars_params_and_constants, additive_vars_params_and_constants; if (equation->containsPacExpectation()) { - int optim_share_index = -1; - set<int> optim_share; - expr_t optim_part = nullptr; - expr_t non_optim_part = nullptr; + int optim_share_index; + expr_t optim_part, non_optim_part, additive_part; set<pair<int, int>> lhss; equation->arg1->collectDynamicVariables(SymbolType::endogenous, lhss); lhs = *(lhss.begin()); - int lhs_orig_symb_id = lhs.first; + int lhs_symb_id = lhs.first; + int lhs_orig_symb_id = lhs_symb_id; if (symbol_table.isAuxiliaryVariable(lhs_orig_symb_id)) try { @@ -4405,22 +4441,29 @@ DynamicModel::walkPacParameters(const string &name, map<pair<string, string>, pa { } - equation->arg2->getPacOptimizingShareAndExprNodes(optim_share, - optim_part, - non_optim_part); + auto arg2 = dynamic_cast<BinaryOpNode *>(equation->arg2); + if (arg2 == nullptr) + { + cerr << "Pac equation in incorrect format" << endl; + exit(EXIT_FAILURE); + } + tie(optim_share_index, optim_part, non_optim_part, additive_part) = + arg2->getPacOptimizingShareAndExprNodes(lhs_symb_id, lhs_orig_symb_id); + if (optim_part == nullptr) equation->arg2->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); else { - optim_share_index = *(optim_share.begin()); optim_part->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); try { non_optim_vars_params_and_constants = non_optim_part->matchLinearCombinationOfVariables(); + if (additive_part != nullptr) + additive_vars_params_and_constants = additive_part->matchLinearCombinationOfVariables(); } catch (ExprNode::MatchFailureException &e) { - cerr << "Error in parsing non-optimizing agents part of PAC equation: " + cerr << "Error in parsing non-optimizing agents or additive part of PAC equation: " << e.message << endl; exit(EXIT_FAILURE); } @@ -4452,7 +4495,8 @@ DynamicModel::walkPacParameters(const string &name, map<pair<string, string>, pa string eq = "eq" + to_string(i++); pac_equation_info[{name, eq}] = {lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars, - non_optim_vars_params_and_constants}; + non_optim_vars_params_and_constants, + additive_vars_params_and_constants}; eqtag_and_lag[{name, eqtag}] = {eq, 0}; } } diff --git a/src/DynamicModel.hh b/src/DynamicModel.hh index 1293e31dc6f75e20205299ddc7650988d37a1ef1..99759db4c016540dfe6d2574ba7cec500185dd5c 100644 --- a/src/DynamicModel.hh +++ b/src/DynamicModel.hh @@ -487,7 +487,7 @@ public: //! (pac_model_name, standardized_eqtag) -> //! (lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants) map<pair<string, string>, - tuple<pair<int, int>, int, set<pair<int, pair<int, int>>>, pair<int, pair<vector<int>, vector<bool>>>, vector<tuple<int, int, int, double>>>> pac_equation_info; + tuple<pair<int, int>, int, set<pair<int, pair<int, int>>>, pair<int, pair<vector<int>, vector<bool>>>, vector<tuple<int, int, int, double>>, vector<tuple<int, int, int, double>>>> pac_equation_info; //! Table to undiff LHS variables for pac vector z vector<int> getUndiffLHSForPac(const string &aux_model_name, diff --git a/src/ExprNode.cc b/src/ExprNode.cc index c5ccc66ec7ed447b0722d06c89376f8057061dfc..614a8080dd329710432f3a0a9bf8757dc9f07635 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -680,13 +680,6 @@ NumConstNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<i { } -void -NumConstNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ -} - bool NumConstNode::isVarModelReferenced(const string &model_info_name) const { @@ -1981,13 +1974,6 @@ VariableNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<i { } -void -VariableNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ -} - bool VariableNode::isVarModelReferenced(const string &model_info_name) const { @@ -3800,14 +3786,6 @@ UnaryOpNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<in arg->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); } -void -UnaryOpNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ - arg->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); -} - bool UnaryOpNode::isVarModelReferenced(const string &model_info_name) const { @@ -5678,67 +5656,122 @@ BinaryOpNode::isParamTimesEndogExpr() const return false; } -void -BinaryOpNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const +bool +BinaryOpNode::getPacNonOptimizingPartHelper(BinaryOpNode *bopn, int optim_share) const { - if (optim_part != nullptr && non_optim_part != nullptr) - return; + set<int> params; + bopn->collectVariables(SymbolType::parameter, params); + if (params.size() == 1 && *(params.begin()) == optim_share) + return true; + return false; +} - if (op_code == BinaryOpcode::times) - { - auto *test_arg1 = dynamic_cast<VariableNode *>(arg1); - auto *test_arg2 = dynamic_cast<VariableNode *>(arg2); +expr_t +BinaryOpNode::getPacNonOptimizingPart(BinaryOpNode *bopn, int optim_share) const +{ + auto a1 = dynamic_cast<BinaryOpNode *>(bopn->arg1); + auto a2 = dynamic_cast<BinaryOpNode *>(bopn->arg2); + if (a1 == nullptr && a2 == nullptr) + return nullptr; - set<int> params1, params2; - arg1->collectVariables(SymbolType::parameter, params1); - arg2->collectVariables(SymbolType::parameter, params2); + if (a1 != nullptr) + if (getPacNonOptimizingPartHelper(a1, optim_share)) + return bopn->arg2; - if (dynamic_cast<NumConstNode *>(arg1) != nullptr - || dynamic_cast<NumConstNode *>(arg2) != nullptr) + if (a2 != nullptr) + if (getPacNonOptimizingPartHelper(a2, optim_share)) + return bopn->arg1; + + return nullptr; +} + +pair<int, expr_t> +BinaryOpNode::getPacOptimizingShareAndExprNodesHelper(BinaryOpNode *bopn, int lhs_symb_id, int lhs_orig_symb_id) const +{ + int optim_param_symb_id = -1; + expr_t optim_part = nullptr; + set<pair<int, int>> endogs; + bopn->collectDynamicVariables(SymbolType::endogenous, endogs); + int target_symb_id = getPacTargetSymbIdHelper(lhs_symb_id, lhs_orig_symb_id, endogs); + if (target_symb_id >= 0) + { + set<int> params; + if (bopn->arg1->isParamTimesEndogExpr() && !bopn->arg2->isParamTimesEndogExpr()) { - cerr << "Error: Please do not use hard-coded parameter values in the PAC equation" - << endl; - exit(EXIT_FAILURE); + optim_part = bopn->arg1; + bopn->arg2->collectVariables(SymbolType::parameter, params); + optim_param_symb_id = *(params.begin()); + } + else if (bopn->arg2->isParamTimesEndogExpr() && !bopn->arg1->isParamTimesEndogExpr()) + { + optim_part = bopn->arg2; + bopn->arg1->collectVariables(SymbolType::parameter, params); + optim_param_symb_id = *(params.begin()); } + } + return {optim_param_symb_id, optim_part}; +} - if (optim_part == nullptr) - if (test_arg1 != nullptr || test_arg2 != nullptr) - if (params1.size() == 1 || params2.size() == 1) - if (arg2->isParamTimesEndogExpr()) - { - // arg1 is the share of optimizing agents - optim_part = arg2; - optim_share.emplace(*(params1.begin())); - } - else if (arg1->isParamTimesEndogExpr()) - { - optim_part = arg1; - optim_share.emplace(*(params2.begin())); - } - - if (non_optim_part == nullptr) - if (params1.size() == 1 && - arg1 == datatree.AddMinus(datatree.One, datatree.AddVariable(*(params1.begin())))) - // arg1 is the non-optimizing share - non_optim_part = arg2; - else if (params2.size() == 1 && - arg2 == datatree.AddMinus(datatree.One, datatree.AddVariable(*(params2.begin())))) - non_optim_part = arg1; +tuple<int, expr_t, expr_t, expr_t> +BinaryOpNode::getPacOptimizingShareAndExprNodes(int lhs_symb_id, int lhs_orig_symb_id) const +{ + vector<pair<expr_t, int>> terms; + decomposeAdditiveTerms(terms, 1); + for (auto & it : terms) + if (dynamic_cast<PacExpectationNode *>(it.first) != nullptr) + // if the pac_expectation operator is additive in the expression + // there are no optimizing shares + return {-1, nullptr, nullptr, nullptr}; + + int optim_share; + expr_t optim_part, non_optim_part, additive_part; + optim_part = non_optim_part = additive_part = nullptr; + + for (auto it = terms.begin(); it != terms.end(); it++) + { + auto bopn = dynamic_cast<BinaryOpNode *>(it->first); + if (bopn != nullptr) + { + tie(optim_share, optim_part) = + getPacOptimizingShareAndExprNodesHelper(bopn, lhs_symb_id, lhs_orig_symb_id); + if (optim_share >= 0 && optim_part != nullptr) + { + terms.erase(it); + break; + } + } } - else if (op_code == BinaryOpcode::plus) + + if (optim_part == nullptr) + return {-1, nullptr, nullptr, nullptr}; + + for (auto it = terms.begin(); it != terms.end(); it++) { - arg1->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); - arg2->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); + auto bopn = dynamic_cast<BinaryOpNode *>(it->first); + if (bopn != nullptr) + { + non_optim_part = getPacNonOptimizingPart(bopn, optim_share); + if (non_optim_part != nullptr) + { + terms.erase(it); + break; + } + } } - else if (op_code == BinaryOpcode::divide) - return; - else + + if (non_optim_part == nullptr) + return {-1, nullptr, nullptr, nullptr}; + + if (non_optim_part != nullptr) { - cerr << "Notation error in PAC equation" << endl; - exit(EXIT_FAILURE); + additive_part = datatree.Zero; + for (auto it : terms) + additive_part = datatree.AddPlus(additive_part, it.first); + if (additive_part == datatree.Zero) + additive_part = nullptr; } + + return {optim_share, optim_part, non_optim_part, additive_part}; } void @@ -6904,16 +6937,6 @@ TrinaryOpNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector< arg3->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); } -void -TrinaryOpNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ - arg1->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); - arg2->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); - arg3->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); -} - bool TrinaryOpNode::isVarModelReferenced(const string &model_info_name) const { @@ -7470,15 +7493,6 @@ AbstractExternalFunctionNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<in argument->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); } -void -AbstractExternalFunctionNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ - for (auto argument : arguments) - argument->getPacOptimizingShareAndExprNodes(optim_share, optim_part, non_optim_part); -} - bool AbstractExternalFunctionNode::isVarModelReferenced(const string &model_info_name) const { @@ -9110,13 +9124,6 @@ VarExpectationNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<ve { } -void -VarExpectationNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ -} - expr_t VarExpectationNode::substituteStaticAuxiliaryVariable() const { @@ -9595,13 +9602,6 @@ PacExpectationNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<ve { } -void -PacExpectationNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const -{ -} - expr_t PacExpectationNode::substitutePacExpectation(const string & name, expr_t subexpr) { diff --git a/src/ExprNode.hh b/src/ExprNode.hh index 15aab14808b53e976e6ce5d5e28f9e992ac75e4a..fc45c1f0f5adbab026a660e388a4f9fabae4668a 100644 --- a/src/ExprNode.hh +++ b/src/ExprNode.hh @@ -597,13 +597,6 @@ class ExprNode //! param * (endog op endog op ...) + param * (endog op endog op ...) + ... virtual bool isParamTimesEndogExpr() const = 0; - //! Finds the share of optimizing agents in the PAC equation, - //! the expr node associated with it, - //! and the expr node associated with the non-optimizing part - virtual void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const = 0; - //! Fills the AR matrix structure virtual void fillAutoregressiveRow(int eqn, const vector<int> &lhs, map<tuple<int, int, int>, expr_t> &AR) const = 0; @@ -736,9 +729,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -826,9 +816,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -944,9 +931,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -1080,9 +1064,14 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; + + //! Finds the share of optimizing agents in the PAC equation, + //! the expr node associated with it, + //! and the expr node associated with the non-optimizing part + tuple<int, expr_t, expr_t, expr_t> getPacOptimizingShareAndExprNodes(int lhs_symb_id, int lhs_orig_symb_id) const; + pair<int, expr_t> getPacOptimizingShareAndExprNodesHelper(BinaryOpNode *bopn, int lhs_symb_id, int lhs_orig_symb_id) const; + expr_t getPacNonOptimizingPart(BinaryOpNode *bopn, int optim_share) const; + bool getPacNonOptimizingPartHelper(BinaryOpNode *bopn, int optim_share) const; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -1195,9 +1184,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -1322,9 +1308,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -1537,9 +1520,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override; @@ -1625,9 +1605,6 @@ public: bool containsPacExpectation(const string &pac_model_name = "") const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars, set<pair<int, pair<int, int>>> ¶ms_and_vars) const override; - void getPacOptimizingShareAndExprNodes(set<int> &optim_share, - expr_t &optim_part, - expr_t &non_optim_part) const override; bool isParamTimesEndogExpr() const override; bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override;