diff --git a/preprocessor/DynamicModel.cc b/preprocessor/DynamicModel.cc index 46b4d5856..fb22c354b 100644 --- a/preprocessor/DynamicModel.cc +++ b/preprocessor/DynamicModel.cc @@ -2831,7 +2831,25 @@ DynamicModel::hessianHelper(ostream &output, int row_nb, int col_nb, ExprNodeOut } void -DynamicModel::substituteLeadGreaterThanTwo() +DynamicModel::substituteEndoLeadGreaterThanTwo() +{ + substituteLeadLagInternal(0); +} + +void +DynamicModel::substituteEndoLagGreaterThanTwo() +{ + substituteLeadLagInternal(1); +} + +void +DynamicModel::substituteExoLeadLag() +{ + substituteLeadLagInternal(2); +} + +void +DynamicModel::substituteLeadLagInternal(int vars) { ExprNode::subst_table_t subst_table; vector neweqs; @@ -2839,12 +2857,40 @@ DynamicModel::substituteLeadGreaterThanTwo() // Substitute in model local variables for(map::iterator it = local_variables_table.begin(); it != local_variables_table.end(); it++) - it->second = it->second->substituteLeadGreaterThanTwo(subst_table, neweqs); + { + NodeID subst; + switch(vars) + { + case 0: + subst = it->second->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); + break; + case 1: + subst = it->second->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + break; + case 2: + subst = it->second->substituteExoLeadLag(subst_table, neweqs); + break; + } + it->second = subst; + } // Substitute in equations for(int i = 0; i < (int) equations.size(); i++) { - BinaryOpNode *substeq = dynamic_cast(equations[i]->substituteLeadGreaterThanTwo(subst_table, neweqs)); + NodeID subst; + switch(vars) + { + case 0: + subst = equations[i]->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); + break; + case 1: + subst = equations[i]->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + break; + case 2: + subst = equations[i]->substituteExoLeadLag(subst_table, neweqs); + break; + } + BinaryOpNode *substeq = dynamic_cast(subst); assert(substeq != NULL); equations[i] = substeq; } @@ -2857,37 +2903,22 @@ DynamicModel::substituteLeadGreaterThanTwo() copy(neweqs.rbegin(), neweqs.rend(), front_inserter(aux_equations)); if (neweqs.size() > 0) - cout << "Substitution of leads >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl; -} - -void -DynamicModel::substituteLagGreaterThanTwo() -{ - ExprNode::subst_table_t subst_table; - vector neweqs; - - // Substitute in model local variables - for(map::iterator it = local_variables_table.begin(); - it != local_variables_table.end(); it++) - it->second = it->second->substituteLagGreaterThanTwo(subst_table, neweqs); - - // Substitute in equations - for(int i = 0; i < (int) equations.size(); i++) { - BinaryOpNode *substeq = dynamic_cast(equations[i]->substituteLagGreaterThanTwo(subst_table, neweqs)); - assert(substeq != NULL); - equations[i] = substeq; + cout << "Substitution of "; + switch(vars) + { + case 0: + cout << "endo leads >= 2"; + break; + case 1: + cout << "endo lags >= 2"; + break; + case 2: + cout << "exo leads/lags >= 2"; + break; + } + cout << ": added " << neweqs.size() << " auxiliary variables and equations." << endl; } - - // Add new equations - for(int i = 0; i < (int) neweqs.size(); i++) - addEquation(neweqs[i]); - - // Add the new set of equations at the *beginning* of aux_equations - copy(neweqs.rbegin(), neweqs.rend(), front_inserter(aux_equations)); - - if (neweqs.size() > 0) - cout << "Substitution of lags >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl; } void diff --git a/preprocessor/DynamicModel.hh b/preprocessor/DynamicModel.hh index d9fa77dfd..04bf98b5d 100644 --- a/preprocessor/DynamicModel.hh +++ b/preprocessor/DynamicModel.hh @@ -144,6 +144,9 @@ private: //! Write chain rule derivative of a recursive equation w.r. to a variable void writeChainRuleDerivative(ostream &output, int eq, int var, int lag, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const; + //! Factorized code for substitutions of leads/lags + /*! \param[in] vars 0 for endo leads, 1 for endo lags, 2 for exo */ + void substituteLeadLagInternal(int vars); public: DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); @@ -199,11 +202,14 @@ public: //! Returns true indicating that this is a dynamic model virtual bool isDynamic() const { return true; }; - //! Transforms the model by removing all leads greater or equal than 2 - void substituteLeadGreaterThanTwo(); + //! Transforms the model by removing all leads greater or equal than 2 on endos + void substituteEndoLeadGreaterThanTwo(); - //! Transforms the model by removing all lags greater or equal than 2 - void substituteLagGreaterThanTwo(); + //! Transforms the model by removing all lags greater or equal than 2 on endos + void substituteEndoLagGreaterThanTwo(); + + //! Transforms the model by removing all leads and lags on exos + void substituteExoLeadLag(); //! Fills eval context with values of model local variables and auxiliary variables void fillEvalContext(eval_context_type &eval_context) const; diff --git a/preprocessor/ExprNode.cc b/preprocessor/ExprNode.cc index e1329f5dc..089502e31 100644 --- a/preprocessor/ExprNode.cc +++ b/preprocessor/ExprNode.cc @@ -148,7 +148,7 @@ ExprNode::writeOutput(ostream &output) } VariableNode * -ExprNode::createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const +ExprNode::createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const { int n = maxEndoLead(); assert(n >= 2); @@ -168,7 +168,7 @@ ExprNode::createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vectoridx); + int symb_id = datatree.symbol_table.addEndoLeadAuxiliaryVar(orig_expr->idx); neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr))); substexpr = datatree.AddVariable(symb_id, +1); assert(dynamic_cast(substexpr) != NULL); @@ -278,13 +278,19 @@ NumConstNode::decreaseLeadsLags(int n) const } NodeID -NumConstNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { return const_cast(this); } NodeID -NumConstNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +{ + return const_cast(this); +} + +NodeID +NumConstNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const { return const_cast(this); } @@ -766,7 +772,7 @@ VariableNode::decreaseLeadsLags(int n) const } NodeID -VariableNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +VariableNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { NodeID value; switch(type) @@ -775,20 +781,20 @@ VariableNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector(this); else - return createLeadAuxiliaryVarForMyself(subst_table, neweqs); + return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); case eModelLocalVariable: value = datatree.local_variables_table[symb_id]; if (value->maxEndoLead() <= 1) return const_cast(this); else - return value->substituteLeadGreaterThanTwo(subst_table, neweqs); + return value->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); default: return const_cast(this); } } NodeID -VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +VariableNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { VariableNode *substexpr; subst_table_t::const_iterator it; @@ -814,7 +820,7 @@ VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr))); substexpr = datatree.AddVariable(aux_symb_id, -1); subst_table[orig_expr] = substexpr; @@ -827,7 +833,81 @@ VariableNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vectorsubstituteLagGreaterThanTwo(subst_table, neweqs); + return datatree.local_variables_table[symb_id]->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + default: + return const_cast(this); + } +} + +NodeID +VariableNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const +{ + VariableNode *substexpr; + subst_table_t::const_iterator it; + int cur_lag; + switch(type) + { + case eExogenous: + if (lag == 0) + return const_cast(this); + + it = subst_table.find(this); + if (it != subst_table.end()) + return const_cast(it->second); + + if (lag < 0) + { + substexpr = datatree.AddVariable(symb_id, 0); + cur_lag = -1; + + // Each iteration tries to create an auxvar such that auxvar(-1)=curvar(cur_lag) + // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag+1) (resp. curvar(cur_lag)) + while(cur_lag >= lag) + { + VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag); + it = subst_table.find(orig_expr); + if (it == subst_table.end()) + { + int aux_symb_id = datatree.symbol_table.addExoLagAuxiliaryVar(symb_id, cur_lag+1); + neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr))); + substexpr = datatree.AddVariable(aux_symb_id, -1); + subst_table[orig_expr] = substexpr; + } + else + substexpr = const_cast(it->second); + + cur_lag--; + } + return substexpr; + } + else + { + substexpr = datatree.AddVariable(symb_id, 0); + cur_lag = +1; + + // Each iteration tries to create an auxvar such that auxvar(+1)=curvar(cur_lag) + // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag-1) (resp. curvar(cur_lag)) + while(cur_lag <= lag) + { + VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag); + it = subst_table.find(orig_expr); + if (it == subst_table.end()) + { + int aux_symb_id = datatree.symbol_table.addExoLeadAuxiliaryVar(symb_id, cur_lag-1); + neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr))); + substexpr = datatree.AddVariable(aux_symb_id, +1); + subst_table[orig_expr] = substexpr; + } + else + substexpr = const_cast(it->second); + + cur_lag++; + } + return substexpr; + } + + case eModelLocalVariable: + return datatree.local_variables_table[symb_id]->substituteExoLeadLag(subst_table, neweqs); default: return const_cast(this); } @@ -1471,26 +1551,33 @@ UnaryOpNode::decreaseLeadsLags(int n) const } NodeID -UnaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +UnaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { if (op_code == oUminus) { - NodeID argsubst = arg->substituteLeadGreaterThanTwo(subst_table, neweqs); + NodeID argsubst = arg->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); return buildSimilarUnaryOpNode(argsubst, datatree); } else { if (maxEndoLead() >= 2) - return createLeadAuxiliaryVarForMyself(subst_table, neweqs); + return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); else return const_cast(this); } } NodeID -UnaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +UnaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { - NodeID argsubst = arg->substituteLagGreaterThanTwo(subst_table, neweqs); + NodeID argsubst = arg->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + return buildSimilarUnaryOpNode(argsubst, datatree); +} + +NodeID +UnaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const +{ + NodeID argsubst = arg->substituteExoLeadLag(subst_table, neweqs); return buildSimilarUnaryOpNode(argsubst, datatree); } @@ -2365,7 +2452,7 @@ BinaryOpNode::decreaseLeadsLags(int n) const } NodeID -BinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +BinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { NodeID arg1subst, arg2subst; int maxlead1 = arg1->maxEndoLead(), maxlead2 = arg2->maxEndoLead(); @@ -2378,32 +2465,40 @@ BinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector= 2 ? arg1->substituteLeadGreaterThanTwo(subst_table, neweqs) : arg1; - arg2subst = maxlead2 >= 2 ? arg2->substituteLeadGreaterThanTwo(subst_table, neweqs) : arg2; + arg1subst = maxlead1 >= 2 ? arg1->substituteEndoLeadGreaterThanTwo(subst_table, neweqs) : arg1; + arg2subst = maxlead2 >= 2 ? arg2->substituteEndoLeadGreaterThanTwo(subst_table, neweqs) : arg2; return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); case oTimes: case oDivide: if (maxlead1 >= 2 && maxlead2 == 0) { - arg1subst = arg1->substituteLeadGreaterThanTwo(subst_table, neweqs); + arg1subst = arg1->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); return buildSimilarBinaryOpNode(arg1subst, arg2, datatree); } if (maxlead1 == 0 && maxlead2 >= 2 && op_code == oTimes) { - arg2subst = arg2->substituteLeadGreaterThanTwo(subst_table, neweqs); + arg2subst = arg2->substituteEndoLeadGreaterThanTwo(subst_table, neweqs); return buildSimilarBinaryOpNode(arg1, arg2subst, datatree); } - return createLeadAuxiliaryVarForMyself(subst_table, neweqs); + return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); default: - return createLeadAuxiliaryVarForMyself(subst_table, neweqs); + return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); } } NodeID -BinaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +BinaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { - NodeID arg1subst = arg1->substituteLagGreaterThanTwo(subst_table, neweqs); - NodeID arg2subst = arg2->substituteLagGreaterThanTwo(subst_table, neweqs); + NodeID arg1subst = arg1->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + NodeID arg2subst = arg2->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); +} + +NodeID +BinaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const +{ + NodeID arg1subst = arg1->substituteExoLeadLag(subst_table, neweqs); + NodeID arg2subst = arg2->substituteExoLeadLag(subst_table, neweqs); return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); } @@ -2766,20 +2861,29 @@ TrinaryOpNode::decreaseLeadsLags(int n) const } NodeID -TrinaryOpNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +TrinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { if (maxEndoLead() < 2) return const_cast(this); else - return createLeadAuxiliaryVarForMyself(subst_table, neweqs); + return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); } NodeID -TrinaryOpNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +TrinaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { - NodeID arg1subst = arg1->substituteLagGreaterThanTwo(subst_table, neweqs); - NodeID arg2subst = arg2->substituteLagGreaterThanTwo(subst_table, neweqs); - NodeID arg3subst = arg3->substituteLagGreaterThanTwo(subst_table, neweqs); + NodeID arg1subst = arg1->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + NodeID arg2subst = arg2->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + NodeID arg3subst = arg3->substituteEndoLagGreaterThanTwo(subst_table, neweqs); + return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); +} + +NodeID +TrinaryOpNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const +{ + NodeID arg1subst = arg1->substituteExoLeadLag(subst_table, neweqs); + NodeID arg2subst = arg2->substituteExoLeadLag(subst_table, neweqs); + NodeID arg3subst = arg3->substituteExoLeadLag(subst_table, neweqs); return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); } @@ -2932,15 +3036,22 @@ UnknownFunctionNode::decreaseLeadsLags(int n) const } NodeID -UnknownFunctionNode::substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +UnknownFunctionNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { - cerr << "UnknownFunctionNode::substituteLeadGreaterThanTwo: not implemented!" << endl; + cerr << "UnknownFunctionNode::substituteEndoLeadGreaterThanTwo: not implemented!" << endl; exit(EXIT_FAILURE); } NodeID -UnknownFunctionNode::substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const +UnknownFunctionNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const { - cerr << "UnknownFunctionNode::substituteLagGreaterThanTwo: not implemented!" << endl; + cerr << "UnknownFunctionNode::substituteEndoLagGreaterThanTwo: not implemented!" << endl; + exit(EXIT_FAILURE); +} + +NodeID +UnknownFunctionNode::substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const +{ + cerr << "UnknownFunctionNode::substituteExoLeadLag: not implemented!" << endl; exit(EXIT_FAILURE); } diff --git a/preprocessor/ExprNode.hh b/preprocessor/ExprNode.hh index 08bafae8c..a18508c0f 100644 --- a/preprocessor/ExprNode.hh +++ b/preprocessor/ExprNode.hh @@ -240,14 +240,14 @@ public: //! Type for the substitution map used in the process of creating auxiliary vars for leads >= 2 typedef map subst_table_t; - //! Creates auxiliary lead variables corresponding to this expression + //! Creates auxiliary endo lead variables corresponding to this expression /*! If maximum endogenous lead >= 3, this method will also create intermediary auxiliary var, and will add the equations of the form aux1 = aux2(+1) to the substitution table. \pre This expression is assumed to have maximum endogenous lead >= 2 \param[in,out] subst_table The table to which new auxiliary variables and their correspondance will be added \return The new variable node corresponding to the current expression */ - VariableNode *createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const; + VariableNode *createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const; //! Constructs a new expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables /*! @@ -260,14 +260,21 @@ public: \return A new equivalent expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables */ - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const = 0; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const = 0; //! Constructs a new expression where endo variables with max endo lag >= 2 have been replaced by auxiliary variables /*! \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr. \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables. */ - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const = 0; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const = 0; + + //! Constructs a new expression where endo variables with max exo lag >= 2 or max exo lag >= 2 have been replaced by auxiliary variables + /*! + \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr. + \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables. + */ + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const = 0; }; //! Object used to compare two nodes (using their indexes) @@ -300,8 +307,9 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; //! Symbol or variable node @@ -334,8 +342,9 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; //! Unary operator node @@ -374,10 +383,11 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; //! Creates another UnaryOpNode with the same opcode, but with a possibly different datatree and argument NodeID buildSimilarUnaryOpNode(NodeID alt_arg, DataTree &alt_datatree) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; //! Binary operator node @@ -421,10 +431,11 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; //! Creates another BinaryOpNode with the same opcode, but with a possibly different datatree and arguments NodeID buildSimilarBinaryOpNode(NodeID alt_arg1, NodeID alt_arg2, DataTree &alt_datatree) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; //! Trinary operator node @@ -462,10 +473,11 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; //! Creates another TrinaryOpNode with the same opcode, but with a possibly different datatree and arguments NodeID buildSimilarTrinaryOpNode(NodeID alt_arg1, NodeID alt_arg2, NodeID alt_arg3, DataTree &alt_datatree) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; //! Unknown function node @@ -497,8 +509,9 @@ public: virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; virtual NodeID decreaseLeadsLags(int n) const; - virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; - virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; + virtual NodeID substituteExoLeadLag(subst_table_t &subst_table, vector &neweqs) const; }; #endif diff --git a/preprocessor/ModFile.cc b/preprocessor/ModFile.cc index dafba6b26..28660a72c 100644 --- a/preprocessor/ModFile.cc +++ b/preprocessor/ModFile.cc @@ -141,8 +141,9 @@ ModFile::transformPass() || mod_file_struct.osr_present || mod_file_struct.ramsey_policy_present) { - dynamic_model.substituteLeadGreaterThanTwo(); - dynamic_model.substituteLagGreaterThanTwo(); + dynamic_model.substituteEndoLeadGreaterThanTwo(); + dynamic_model.substituteEndoLagGreaterThanTwo(); + dynamic_model.substituteExoLeadLag(); } // Freeze the symbol table diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc index 451653d77..eafc6ae9e 100644 --- a/preprocessor/ParsingDriver.cc +++ b/preprocessor/ParsingDriver.cc @@ -192,9 +192,6 @@ ParsingDriver::add_model_variable(string *name, string *olag) if (type == eUnknownFunction) error("Symbol " + *name + " is a function name unknown to Dynare. It cannot be used inside model."); - if (type == eExogenous && lag != 0 && !mod_file->block) - warning("Exogenous variable " + *name + " has lead/lag " + *olag); - if (type == eModelLocalVariable && lag != 0) error("Model local variable " + *name + " cannot be given a lead or a lag."); diff --git a/preprocessor/SymbolTable.cc b/preprocessor/SymbolTable.cc index d82dc9ff0..ea72365e3 100644 --- a/preprocessor/SymbolTable.cc +++ b/preprocessor/SymbolTable.cc @@ -208,9 +208,11 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException) << "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].type << ";" << endl; switch(aux_vars[i].type) { - case avLead: + case avEndoLead: break; - case avLag: + case avEndoLag: + case avExoLead: + case avExoLag: output << "M_.aux_vars(" << i+1 << ").orig_endo_index = " << getTypeSpecificID(aux_vars[i].orig_symb_id)+1 << ";" << endl << "M_.aux_vars(" << i+1 << ").orig_lag = " << aux_vars[i].orig_lag << ";" << endl; break; @@ -219,10 +221,10 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException) } int -SymbolTable::addLeadAuxiliaryVar(int index) throw (FrozenException) +SymbolTable::addEndoLeadAuxiliaryVar(int index) throw (FrozenException) { ostringstream varname; - varname << "AUXLEAD_" << index; + varname << "AUX_ENDO_LEAD_" << index; int symb_id; try { @@ -236,17 +238,32 @@ SymbolTable::addLeadAuxiliaryVar(int index) throw (FrozenException) AuxVarInfo avi; avi.symb_id = symb_id; - avi.type = avLead; + avi.type = avEndoLead; aux_vars.push_back(avi); return symb_id; } int -SymbolTable::addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException) +SymbolTable::addLeadLagAuxiliaryVarInternal(aux_var_t type, int orig_symb_id, int orig_lag) throw (FrozenException) { ostringstream varname; - varname << "AUXLAG_" << orig_symb_id << "_" << -orig_lag; + switch(type) + { + case avEndoLag: + varname << "AUX_ENDO_LAG_" << orig_symb_id << "_" << -orig_lag; + break; + case avExoLead: + varname << "AUX_EXO_LEAD_" << orig_symb_id << "_" << orig_lag; + break; + case avExoLag: + varname << "AUX_EXO_LAG_" << orig_symb_id << "_" << -orig_lag; + break; + default: + cerr << "Impossible case!" << endl; + exit(EXIT_FAILURE); + } + int symb_id; try { @@ -260,10 +277,28 @@ SymbolTable::addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenExc AuxVarInfo avi; avi.symb_id = symb_id; - avi.type = avLag; + avi.type = type; avi.orig_symb_id = orig_symb_id; avi.orig_lag = orig_lag; aux_vars.push_back(avi); return symb_id; } + +int +SymbolTable::addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException) +{ + return addLeadLagAuxiliaryVarInternal(avEndoLag, orig_symb_id, orig_lag); +} + +int +SymbolTable::addExoLeadAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException) +{ + return addLeadLagAuxiliaryVarInternal(avExoLead, orig_symb_id, orig_lag); +} + +int +SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException) +{ + return addLeadLagAuxiliaryVarInternal(avExoLag, orig_symb_id, orig_lag); +} diff --git a/preprocessor/SymbolTable.hh b/preprocessor/SymbolTable.hh index baed9a621..071ec3a59 100644 --- a/preprocessor/SymbolTable.hh +++ b/preprocessor/SymbolTable.hh @@ -32,8 +32,10 @@ using namespace std; //! Types of auxiliary variables enum aux_var_t { - avLead = 0, //!< Substitute for leads >= 2 - avLag = 1 //!< Substitute for lags >= 2 + avEndoLead = 0, //!< Substitute for endo leads >= 2 + avEndoLag = 1, //!< Substitute for endo lags >= 2 + avExoLead = 2, //!< Substitute for exo leads >= 2 + avExoLag = 3, //!< Substitute for exo lags >= 2 }; //! Information on some auxiliary variables @@ -41,8 +43,8 @@ struct AuxVarInfo { int symb_id; //!< Symbol ID of the auxiliary variable aux_var_t type; //!< Its type - int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Only for avLag - int orig_lag; //!< Lag of the endo of the original model represented by this aux var. Only for avLag + int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Not used for avEndoLead + int orig_lag; //!< Lead/lag of the endo of the original model represented by this aux var. Not used for avEndoLead }; //! Stores the symbol table @@ -88,6 +90,7 @@ private: vector param_ids; //! Information about auxiliary variables vector aux_vars; + public: SymbolTable(); //! Thrown when trying to access an unknown symbol (by name) @@ -132,17 +135,40 @@ public: class NotYetFrozenException { }; + +private: + int addLeadLagAuxiliaryVarInternal(aux_var_t type, int orig_symb_id, int orig_lag) throw (FrozenException); + +public: //! Add a symbol /*! Returns the symbol ID */ int addSymbol(const string &name, SymbolType type, const string &tex_name) throw (AlreadyDeclaredException, FrozenException); //! Add a symbol without its TeX name (will be equal to its name) /*! Returns the symbol ID */ int addSymbol(const string &name, SymbolType type) throw (AlreadyDeclaredException, FrozenException); - //! Adds an auxiliary variable for leads >=2 - /*! Uses the given argument to construct the variable name. - Will exit the preprocessor with an error message if the variable name already declared by the user. Returns the symbol ID. */ - int addLeadAuxiliaryVar(int index) throw (FrozenException); - int addLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException); + //! Adds an auxiliary variable for endogenous with lead >= 2 + /*! + \param[in] index Used to construct the variable name + \return the symbol ID of the new symbol */ + int addEndoLeadAuxiliaryVar(int index) throw (FrozenException); + //! Adds an auxiliary variable for endogenous with lag >= 2 + /*! + \param[in] orig_symb_id symbol ID of the endogenous declared by the user that this new variable will represent + \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag) + \return the symbol ID of the new symbol */ + int addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException); + //! Adds an auxiliary variable for endogenous with lead >= 1 + /*! + \param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable will represent + \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag) + \return the symbol ID of the new symbol */ + int addExoLeadAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException); + //! Adds an auxiliary variable for exogenous with lag >= 1 + /*! + \param[in] orig_symb_id symbol ID of the exogenous declared by the user that this new variable will represent + \param[in] orig_lag lag value such that this new variable will be equivalent to orig_symb_id(orig_lag) + \return the symbol ID of the new symbol */ + int addExoLagAuxiliaryVar(int orig_symb_id, int orig_lag) throw (FrozenException); //! Tests if symbol already exists inline bool exists(const string &name) const; //! Get symbol name (by ID)