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,