From 16a97a96fd3523e59c3cef8083f4fd739e37406b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Villemot?= Date: Tue, 27 Nov 2018 18:53:28 +0100 Subject: [PATCH] Rewrite engine for matching the non-optimizing agents part in PAC The engine is now more robust and should reject any expression that does not conform to the expected form. It is also able to deal with more cases, such as terms appearing with a minus sign, or variables in the middle of a three-factors product. BTW, use a std::tuple for storing the result of the matching inside PacExpectationNode, and change the order of components within the structure (variable first, scalar last). --- src/DynamicModel.cc | 6 +- src/ExprNode.cc | 341 ++++++++++++++++++++++---------------------- src/ExprNode.hh | 85 ++++++----- 3 files changed, 223 insertions(+), 209 deletions(-) diff --git a/src/DynamicModel.cc b/src/DynamicModel.cc index 156c696b..d4a3a672 100644 --- a/src/DynamicModel.cc +++ b/src/DynamicModel.cc @@ -4243,7 +4243,7 @@ DynamicModel::walkPacParameters() pair lhs (-1, -1); pair, vector>> ec_params_and_vars; set>> ar_params_and_vars; - set, double>>> non_optim_params_vars_and_scaling_factor; + vector> non_optim_vars_params_and_constants; if (equation->containsPacExpectation()) { @@ -4271,12 +4271,12 @@ DynamicModel::walkPacParameters() { optim_share_index = *(optim_share.begin()); optim_part->getPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); - non_optim_part->getPacNonOptimizingPart(non_optim_params_vars_and_scaling_factor); + non_optim_vars_params_and_constants = non_optim_part->getPacNonOptimizingPart(); } equation->addParamInfoToPac(lhs, optim_share_index, ec_params_and_vars, ar_params_and_vars, - non_optim_params_vars_and_scaling_factor); + non_optim_vars_params_and_constants); } } } diff --git a/src/ExprNode.cc b/src/ExprNode.cc index 27fd7876..2ebdfa0d 100644 --- a/src/ExprNode.cc +++ b/src/ExprNode.cc @@ -675,13 +675,7 @@ NumConstNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -NumConstNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ -} - -void -NumConstNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +NumConstNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { } @@ -1951,23 +1945,6 @@ VariableNode::isParamTimesEndogExpr() const return false; } -void -VariableNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - if (get_type() != SymbolType::endogenous - && get_type() != SymbolType::exogenous) - { - cerr << "ERROR VariableNode::getPacNonOptimizingPart: Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); - } - - params_vars_and_scaling_factor.emplace(make_pair(-1, - make_pair(make_pair(symb_id, lag), - 1.0))); -} - void VariableNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> &ar_params_and_vars) const @@ -1982,7 +1959,7 @@ VariableNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -VariableNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +VariableNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { } @@ -3767,12 +3744,6 @@ UnaryOpNode::isParamTimesEndogExpr() const return arg->isParamTimesEndogExpr(); } -void -UnaryOpNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - arg->getPacNonOptimizingPart(params_vars_and_scaling_factor); -} void UnaryOpNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, @@ -3790,9 +3761,9 @@ UnaryOpNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -UnaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +UnaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { - arg->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); + arg->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); } void @@ -5570,83 +5541,6 @@ BinaryOpNode::getPacOptimizingPart(int lhs_orig_symb_id, pairgetPacOptimizingPart(lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars); } -void -BinaryOpNode::getPacNonOptimizingPartHelper(const expr_t arg1, const expr_t arg2, - set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - eval_context_t ec; - set params; - set> vars; - arg1->collectDynamicVariables(SymbolType::endogenous, vars); - arg1->collectDynamicVariables(SymbolType::exogenous, vars); - - if (vars.size() == 0) - return; - - if (vars.size() > 1) - { - cerr << "ERROR BinaryOpNode::getPacNonOptimizingPartHelper: Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); - } - ec[(*(vars.begin())).first] = 1.0; - - arg2->collectVariables(SymbolType::parameter, params); - if (params.size() > 1) - { - cerr << "ERROR BinaryOpNode::getPacNonOptimizingPartHelper: 2 Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); - } - - int param_idx; - if (params.size() == 1) - { - param_idx = *(params.begin()); - ec[param_idx] = 1.0; - } - else - param_idx = -1; - - double scaling_factor = 1.0; - try - { - scaling_factor = this->eval(ec); - } - catch (...) - { - } - - params_vars_and_scaling_factor.emplace(param_idx, - make_pair(*(vars.begin()), scaling_factor)); -} - -void -BinaryOpNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - if (op_code == BinaryOpcode::times - || op_code == BinaryOpcode::divide) - { - size_t orig_size = params_vars_and_scaling_factor.size(); - getPacNonOptimizingPartHelper(arg1, arg2, params_vars_and_scaling_factor); - if (orig_size == params_vars_and_scaling_factor.size()) - getPacNonOptimizingPartHelper(arg2, arg1, params_vars_and_scaling_factor); - if (orig_size == params_vars_and_scaling_factor.size()) - { - cerr << "ERROR BinaryOpNode::getPacNonOptimizingPart: Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); - } - } - else - { - arg1->getPacNonOptimizingPart(params_vars_and_scaling_factor); - arg2->getPacNonOptimizingPart(params_vars_and_scaling_factor); - } -} - bool BinaryOpNode::isParamTimesEndogExpr() const { @@ -5895,10 +5789,10 @@ BinaryOpNode::getPacLHS(pair &lhs) } void -BinaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +BinaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { - arg1->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); - arg2->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); + arg1->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); + arg2->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); } void @@ -6790,15 +6684,6 @@ TrinaryOpNode::isParamTimesEndogExpr() const || arg3->isParamTimesEndogExpr(); } -void -TrinaryOpNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - arg1->getPacNonOptimizingPart(params_vars_and_scaling_factor); - arg2->getPacNonOptimizingPart(params_vars_and_scaling_factor); - arg3->getPacNonOptimizingPart(params_vars_and_scaling_factor); -} - void TrinaryOpNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> &ar_params_and_vars) const @@ -6819,11 +6704,11 @@ TrinaryOpNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -TrinaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +TrinaryOpNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { - arg1->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); - arg2->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); - arg3->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); + arg1->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); + arg2->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); + arg3->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); } void @@ -7344,15 +7229,6 @@ AbstractExternalFunctionNode::isParamTimesEndogExpr() const return false; } -void -AbstractExternalFunctionNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - cerr << "ERROR AbstractExternalFunctionNode::getPacNonOptimizingPart(: Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); -} - void AbstractExternalFunctionNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> &ar_params_and_vars) const @@ -7371,10 +7247,10 @@ AbstractExternalFunctionNode::getPacOptimizingShareAndExprNodes(set &optim_ } void -AbstractExternalFunctionNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +AbstractExternalFunctionNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { for (auto argument : arguments) - argument->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, params_vars_and_scaling_factor_arg); + argument->addParamInfoToPac(lhs_arg, optim_share_arg, ec_params_and_vars_arg, ar_params_and_vars_arg, non_optim_vars_params_and_constants); } void @@ -8973,15 +8849,6 @@ VarExpectationNode::isParamTimesEndogExpr() const return false; } -void -VarExpectationNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ - cerr << "ERROR VarExpectationNode::getPacNonOptimizingPart(: Error in parsing PAC equation" - << endl; - exit(EXIT_FAILURE); -} - void VarExpectationNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> &ar_params_and_vars) const @@ -8996,7 +8863,7 @@ VarExpectationNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -VarExpectationNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +VarExpectationNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) { } @@ -9146,45 +9013,45 @@ PacExpectationNode::writeOutput(ostream &output, ExprNodeOutputType output_type, output << it->second.second; } output << "];" << endl; - if (!params_vars_and_scaling_factor.empty()) + if (!non_optim_vars_params_and_constants.empty()) { output << "M_.pac." << model_name << ".non_optimizing_behaviour.params = ["; - for (auto it = params_vars_and_scaling_factor.begin(); - it != params_vars_and_scaling_factor.end(); it++) + for (auto it = non_optim_vars_params_and_constants.begin(); + it != non_optim_vars_params_and_constants.end(); ++it) { - if (it != params_vars_and_scaling_factor.begin()) + if (it != non_optim_vars_params_and_constants.begin()) output << " "; - if (it->first >= 0) - output << datatree.symbol_table.getTypeSpecificID(it->first) + 1; + if (get<2>(*it) >= 0) + output << datatree.symbol_table.getTypeSpecificID(get<2>(*it)) + 1; else output << "NaN"; } output << "];" << "M_.pac." << model_name << ".non_optimizing_behaviour.vars = ["; - for (auto it = params_vars_and_scaling_factor.begin(); - it != params_vars_and_scaling_factor.end(); it++) + for (auto it = non_optim_vars_params_and_constants.begin(); + it != non_optim_vars_params_and_constants.end(); ++it) { - if (it != params_vars_and_scaling_factor.begin()) + if (it != non_optim_vars_params_and_constants.begin()) output << " "; - output << datatree.symbol_table.getTypeSpecificID(it->second.first.first) + 1; + output << datatree.symbol_table.getTypeSpecificID(get<0>(*it)) + 1; } output << "];" << endl << "M_.pac." << model_name << ".non_optimizing_behaviour.lags = ["; - for (auto it = params_vars_and_scaling_factor.begin(); - it != params_vars_and_scaling_factor.end(); it++) + for (auto it = non_optim_vars_params_and_constants.begin(); + it != non_optim_vars_params_and_constants.end(); ++it) { - if (it != params_vars_and_scaling_factor.begin()) + if (it != non_optim_vars_params_and_constants.begin()) output << " "; - output << it->second.first.second; + output << get<1>(*it); } output << "];" << endl << "M_.pac." << model_name << ".non_optimizing_behaviour.scaling_factor = ["; - for (auto it = params_vars_and_scaling_factor.begin(); - it != params_vars_and_scaling_factor.end(); it++) + for (auto it = non_optim_vars_params_and_constants.begin(); + it != non_optim_vars_params_and_constants.end(); ++it) { - if (it != params_vars_and_scaling_factor.begin()) + if (it != non_optim_vars_params_and_constants.begin()) output << " "; - output << it->second.second; + output << get<3>(*it); } output << "];" << endl; } @@ -9550,12 +9417,6 @@ PacExpectationNode::isParamTimesEndogExpr() const return false; } -void -PacExpectationNode::getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const -{ -} - void PacExpectationNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> &ar_params_and_vars) const @@ -9570,7 +9431,7 @@ PacExpectationNode::getPacOptimizingShareAndExprNodes(set &optim_share, } void -PacExpectationNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) +PacExpectationNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants_arg) { if (lhs_arg.first == -1) { @@ -9588,7 +9449,7 @@ PacExpectationNode::addParamInfoToPac(pair &lhs_arg, int optim_share_a optim_share_index = optim_share_arg; ar_params_and_vars = ar_params_and_vars_arg; ec_params_and_vars = ec_params_and_vars_arg; - params_vars_and_scaling_factor = params_vars_and_scaling_factor_arg; + non_optim_vars_params_and_constants = non_optim_vars_params_and_constants_arg; } @@ -9669,3 +9530,137 @@ PacExpectationNode::substitutePacExpectation(map> &terms, int current_sign) const +{ + terms.emplace_back(const_cast(this), current_sign); +} + +void +UnaryOpNode::decomposeAdditiveTerms(vector> &terms, int current_sign) const +{ + if (op_code == UnaryOpcode::uminus) + arg->decomposeAdditiveTerms(terms, -current_sign); + else + ExprNode::decomposeAdditiveTerms(terms, current_sign); +} + +void +BinaryOpNode::decomposeAdditiveTerms(vector> &terms, int current_sign) const +{ + if (op_code == BinaryOpcode::plus || op_code == BinaryOpcode::minus) + { + arg1->decomposeAdditiveTerms(terms, current_sign); + if (op_code == BinaryOpcode::plus) + arg2->decomposeAdditiveTerms(terms, current_sign); + else + arg2->decomposeAdditiveTerms(terms, -current_sign); + } + else + ExprNode::decomposeAdditiveTerms(terms, current_sign); +} + +tuple +ExprNode::matchVariableTimesConstantTimesParam() const +{ + int variable_id = -1, lag = 0, param_id = -1; + double constant = 1.0; + matchVTCTPHelper(variable_id, lag, param_id, constant, false); + if (variable_id == -1) + throw MatchFailureException{"No variable in this expression"}; + return make_tuple(variable_id, lag, param_id, constant); +} + +void +ExprNode::matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const +{ + throw MatchFailureException{"Expression not allowed in linear combination of variables"}; +} + +void +NumConstNode::matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const +{ + double myvalue = eval({}); + if (at_denominator) + constant /= myvalue; + else + constant *= myvalue; +} + +void +VariableNode::matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const +{ + if (at_denominator) + throw MatchFailureException{"A variable or parameter cannot appear at denominator"}; + + SymbolType type = get_type(); + if (type == SymbolType::endogenous || type == SymbolType::exogenous) + { + if (var_id != -1) + throw MatchFailureException{"More than one variable in this expression"}; + var_id = symb_id; + lag = this->lag; + } + else if (type == SymbolType::parameter) + { + if (param_id != -1) + throw MatchFailureException{"More than one parameter in this expression"}; + param_id = symb_id; + } + else + throw MatchFailureException{"Symbol " + datatree.symbol_table.getName(symb_id) + " not allowed here"}; +} + +void +UnaryOpNode::matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const +{ + if (op_code == UnaryOpcode::uminus) + { + constant = -constant; + arg->matchVTCTPHelper(var_id, lag, param_id, constant, at_denominator); + } + else + throw MatchFailureException{"Operator not allowed in this expression"}; +} + +void +BinaryOpNode::matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const +{ + if (op_code == BinaryOpcode::times || op_code == BinaryOpcode::divide) + { + arg1->matchVTCTPHelper(var_id, lag, param_id, constant, at_denominator); + if (op_code == BinaryOpcode::times) + arg2->matchVTCTPHelper(var_id, lag, param_id, constant, at_denominator); + else + arg2->matchVTCTPHelper(var_id, lag, param_id, constant, !at_denominator); + } + else + throw MatchFailureException{"Operator not allowed in this expression"}; +} + +vector> +ExprNode::getPacNonOptimizingPart() const +{ + vector> terms; + decomposeAdditiveTerms(terms); + + vector> result; + + for (const auto &it : terms) + try + { + expr_t term = it.first; + int sign = it.second; + auto m = term->matchVariableTimesConstantTimesParam(); + get<3>(m) *= sign; + result.push_back(m); + } + catch (MatchFailureException &e) + { + cerr << "ExprNode::getPacNonOptimizingPart: Error in parsing PAC equation: " + << e.message << endl; + exit(EXIT_FAILURE); + } + return result; +} diff --git a/src/ExprNode.hh b/src/ExprNode.hh index 077e475a..8cba78d1 100644 --- a/src/ExprNode.hh +++ b/src/ExprNode.hh @@ -205,6 +205,10 @@ class ExprNode bool checkIfTemporaryTermThenWrite(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs) const; + + // Internal helper for matchVariableTimesConstantTimesParam() + virtual void matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const; + public: ExprNode(DataTree &datatree_arg, int idx_arg); virtual ~ExprNode() = default; @@ -556,9 +560,11 @@ class ExprNode virtual void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const = 0; - //! Fills info for non optimizing part of PAC equation - virtual void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const = 0; + //! Analyzes the non optimizing part of PAC equation + /*! Returns a list of (variable_id, lag, param_id, constant) + corresponding to the terms in the expression. When there is no + parameter in a term, param_id == -1 */ + vector> getPacNonOptimizingPart() const; //! Returns true if expression is of the form: //! param * (endog op endog op ...) + param * (endog op endog op ...) + ... virtual bool isParamTimesEndogExpr() const = 0; @@ -570,7 +576,7 @@ class ExprNode expr_t &optim_part, expr_t &non_optim_part) const = 0; //! Adds PAC equation param info to pac_expectation - virtual void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) = 0; + virtual void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) = 0; //! Fills var_model info for pac_expectation node virtual void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) = 0; @@ -587,7 +593,33 @@ class ExprNode //! Fills map virtual void getEndosAndMaxLags(map &model_endos_and_lags) const = 0; - }; + + //! Decompose an expression into its additive terms + /*! Returns a list of terms, with their sign (either 1 or -1, depending + on whether the terms appears with a plus or a minus). + The current_sign argument should normally be left to 1. + If current_sign == -1, then all signs are inverted */ + virtual void decomposeAdditiveTerms(vector> &terms, int current_sign = 1) const; + + // Matches an expression of the form variable*constant*parameter + /* Returns a tuple (variable_id, lag, param_id, constant). + The variable must be an exogenous or an endogenous. + The constant is optional (in which case 1 is returned); there can be + several multiplicative constants; constants can also appear at the + denominator (i.e. after a divide sign). + The parameter is optional (in which case param_id == -1). + If the expression is not of the expected form, throws a + MatchFailureException */ + tuple matchVariableTimesConstantTimesParam() const; + + //! Exception thrown by matchVariableTimesConstantTimesParam when matching fails + class MatchFailureException + { + public: + const string message; + MatchFailureException(string message_arg) : message{move(message_arg)} {}; + }; +}; //! Object used to compare two nodes (using their indexes) /*! Note that in this ordering, a subexpression is always less than the @@ -667,13 +699,11 @@ public: expr_t clone(DataTree &datatree) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -683,6 +713,7 @@ public: bool isVarModelReferenced(const string &model_info_name) const override; void getEndosAndMaxLags(map &model_endos_and_lags) const override; expr_t substituteStaticAuxiliaryVariable() const override; + void matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const override; }; //! Symbol or variable node @@ -764,13 +795,11 @@ public: expr_t clone(DataTree &datatree) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -781,6 +810,7 @@ public: void getEndosAndMaxLags(map &model_endos_and_lags) const override; //! Substitute auxiliary variables by their expression in static model expr_t substituteStaticAuxiliaryVariable() const override; + void matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const override; }; //! Unary operator node @@ -890,13 +920,11 @@ public: expr_t clone(DataTree &datatree) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -907,6 +935,8 @@ public: void getEndosAndMaxLags(map &model_endos_and_lags) const override; //! Substitute auxiliary variables by their expression in static model expr_t substituteStaticAuxiliaryVariable() const override; + void decomposeAdditiveTerms(vector> &terms, int current_sign) const override; + void matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const override; }; //! Binary operator node @@ -984,11 +1014,6 @@ public: { return powerDerivOrder; } - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; - void getPacNonOptimizingPartHelper(const expr_t arg1, const expr_t arg2, - set, double>>> - ¶ms_vars_and_scaling_factor) const; void getPacOptimizingPartHelper(const expr_t arg1, const expr_t arg2, int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, @@ -1044,7 +1069,7 @@ public: //! Returns the non-zero hand-side of an equation (that must have a hand side equal to zero) expr_t getNonZeroPartofEquation() const; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRowHelper(expr_t arg1, expr_t arg2, int eqn, const vector &lhs, map, expr_t> &AR) const; @@ -1066,6 +1091,8 @@ public: expr_t substituteStaticAuxiliaryVariable() const override; //! Substitute auxiliary variables by their expression in static model auxiliary variable definition expr_t substituteStaticAuxiliaryDefinition() const; + void decomposeAdditiveTerms(vector> &terms, int current_sign) const override; + void matchVTCTPHelper(int &var_id, int &lag, int ¶m_id, double &constant, bool at_denominator) const override; }; //! Trinary operator node @@ -1159,13 +1186,11 @@ public: expr_t clone(DataTree &datatree) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -1284,13 +1309,11 @@ public: expr_t clone(DataTree &datatree) const override = 0; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -1497,13 +1520,11 @@ public: expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share, @@ -1532,7 +1553,7 @@ private: int optim_share_index; pair, vector>> ec_params_and_vars; set>> ar_params_and_vars; - set, double>>> params_vars_and_scaling_factor; + vector> non_optim_vars_params_and_constants; public: PacExpectationNode(DataTree &datatree_arg, int idx_arg, string model_name); void computeTemporaryTerms(map> &reference_count, @@ -1596,13 +1617,11 @@ public: expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override; expr_t removeTrendLeadLag(map trend_symbols_map) const override; bool isInStaticForm() const override; - void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg) override; + void addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> ¶ms_and_vars_arg, const vector> &non_optim_vars_params_and_constants) override; void fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg) override; void fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const override; void fillErrorCorrectionRow(int eqn, const vector &nontrend_lhs, const vector &trend_lhs, map, expr_t> &EC) const override; bool containsPacExpectation(const string &pac_model_name = "") const override; - void getPacNonOptimizingPart(set, double>>> - ¶ms_vars_and_scaling_factor) const override; void getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars, set>> ¶ms_and_vars) const override; void getPacOptimizingShareAndExprNodes(set &optim_share,