diff --git a/preprocessor/ExprNode.cc b/preprocessor/ExprNode.cc index a12d16f6e..5f278ce1e 100644 --- a/preprocessor/ExprNode.cc +++ b/preprocessor/ExprNode.cc @@ -382,6 +382,12 @@ NumConstNode::maxExoLag() const return 0; } +int +NumConstNode::maxLead() const +{ + return 0; +} + expr_t NumConstNode::decreaseLeadsLags(int n) const { @@ -445,6 +451,12 @@ NumConstNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +bool +NumConstNode::containsEndogenous(void) const +{ + return false; +} + expr_t NumConstNode::replaceTrendVar() const { @@ -1007,6 +1019,22 @@ VariableNode::maxExoLag() const } } +int +VariableNode::maxLead() const +{ + switch (type) + { + case eEndogenous: + return lag; + case eExogenous: + return lag; + case eModelLocalVariable: + return datatree.local_variables_table[symb_id]->maxLead(); + default: + return 0; + } +} + expr_t VariableNode::decreaseLeadsLags(int n) const { @@ -1206,6 +1234,15 @@ VariableNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +bool +VariableNode::containsEndogenous(void) const +{ + if (type == eEndogenous) + return true; + else + return false; +} + expr_t VariableNode::replaceTrendVar() const { @@ -2109,6 +2146,12 @@ UnaryOpNode::maxExoLag() const return arg->maxExoLag(); } +int +UnaryOpNode::maxLead() const +{ + return arg->maxLead(); +} + expr_t UnaryOpNode::decreaseLeadsLags(int n) const { @@ -2215,23 +2258,30 @@ UnaryOpNode::substituteExpectation(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const { - if (op_code==oLog) + if (op_code==oLog && this->containsEndogenous() ) { subst_table_t::iterator it = subst_table.find(const_cast(this)); if (it != subst_table.end()) return const_cast(it->second); + //take care of any nested log expressions by calling arg->substituteLogPow(.), then decreaseLeadsLags for this oExpectation operator + //arg(lag-period) (holds entire subtree of arg(lag-period) + expr_t substexpr = arg->substituteLogPow(subst_table, neweqs1, neweqs2); + assert(substexpr != NULL); + int k = substexpr->maxLead(); + if (k) + substexpr = substexpr->decreaseLeadsLags(k); + it = subst_table.find(substexpr); + if (it != subst_table.end()) + return (it->second)->decreaseLeadsLags(-k); + //Arriving here, we need to create an auxiliary variable for the argument of the log expression: //AUX_LOG_(arg.idx) int symb_id = datatree.symbol_table.addLogAuxiliaryVar(arg->idx); expr_t newAuxE = datatree.AddVariable(symb_id, 0); assert(dynamic_cast(newAuxE) != NULL); - subst_table[this] = dynamic_cast(newAuxE); + subst_table[substexpr] = dynamic_cast(newAuxE); - //take care of any nested log expressions by calling arg->substituteLogPow(.), then decreaseLeadsLags for this oExpectation operator - //arg(lag-period) (holds entire subtree of arg(lag-period) - expr_t substexpr = arg->substituteLogPow(subst_table, neweqs1, neweqs2); - assert(substexpr != NULL); // auxiliary equation with the exponential of the auxiliary variable expr_t lhs = datatree.AddExp(newAuxE); neweqs1.push_back(dynamic_cast(datatree.AddEqual(lhs, substexpr))); @@ -2239,25 +2289,40 @@ UnaryOpNode::substituteLogPow(subst_table_t &subst_table, vector expr_t definition = datatree.AddLog(substexpr); neweqs2.push_back(dynamic_cast(datatree.AddEqual(newAuxE,definition))); - return newAuxE; + return newAuxE->decreaseLeadsLags(-k); } - else if (op_code==oSqrt) + else if (op_code==oSqrt && this->containsEndogenous() ) { subst_table_t::iterator it = subst_table.find(const_cast(this)); if (it != subst_table.end()) - return const_cast(it->second); + { + // expression to be used instead of sqrt + expr_t constant = datatree.AddNonNegativeConstant("0.5"); + return datatree.AddExp(datatree.AddTimes(constant,const_cast(it->second))); + } + + //take care of any nested log expressions by calling arg->substituteLogPow(.), then decreaseLeadsLags for this oExpectation operator + //arg(lag-period) (holds entire subtree of arg(lag-period) + expr_t substexpr = arg->substituteLogPow(subst_table, neweqs1, neweqs2); + assert(substexpr != NULL); + int k = substexpr->maxLead(); + if (k) + substexpr = substexpr->decreaseLeadsLags(k); + it = subst_table.find(substexpr); + if (it != subst_table.end()) + { + // expression to be used instead of sqrt + expr_t constant = datatree.AddNonNegativeConstant("0.5"); + return datatree.AddExp(datatree.AddTimes(constant,(it->second)->decreaseLeadsLags(-k))); + } //Arriving here, we need to create an auxiliary variable for the argument of the log expression: //AUX_LOG_(arg.idx) int symb_id = datatree.symbol_table.addPowAuxiliaryVar(arg->idx); expr_t newAuxE = datatree.AddVariable(symb_id, 0); assert(dynamic_cast(newAuxE) != NULL); - subst_table[this] = dynamic_cast(newAuxE); + subst_table[substexpr] = dynamic_cast(newAuxE); - //take care of any nested log expressions by calling arg->substituteLogPow(.), then decreaseLeadsLags for this oExpectation operator - //arg(lag-period) (holds entire subtree of arg(lag-period) - expr_t substexpr = arg->substituteLogPow(subst_table, neweqs1, neweqs2); - assert(substexpr != NULL); // auxiliary equation with the exponential of the auxiliary variable expr_t lhs = datatree.AddExp(newAuxE); neweqs1.push_back(dynamic_cast(datatree.AddEqual(lhs, substexpr))); @@ -2267,9 +2332,7 @@ UnaryOpNode::substituteLogPow(subst_table_t &subst_table, vector // expression to be used instead of sqrt expr_t constant = datatree.AddNonNegativeConstant("0.5"); - newAuxE = datatree.AddTimes(constant,newAuxE); - newAuxE = datatree.AddExp(newAuxE); - return newAuxE; + return datatree.AddExp(datatree.AddTimes(constant,newAuxE->decreaseLeadsLags(-k))); } else { @@ -2290,6 +2353,12 @@ UnaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag return false; } +bool +UnaryOpNode::containsEndogenous(void) const +{ + return arg->containsEndogenous(); +} + expr_t UnaryOpNode::replaceTrendVar() const { @@ -3363,6 +3432,12 @@ BinaryOpNode::maxExoLag() const return max(arg1->maxExoLag(), arg2->maxExoLag()); } +int +BinaryOpNode::maxLead() const +{ + return max(arg1->maxLead(), arg2->maxLead()); +} + expr_t BinaryOpNode::decreaseLeadsLags(int n) const { @@ -3494,7 +3569,7 @@ BinaryOpNode::substituteExpectation(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const { - if (op_code==oPower) + if (op_code==oPower && this->containsEndogenous() ) { NumConstNode *arg2_node = dynamic_cast(arg2); if (arg2_node != NULL) @@ -3511,21 +3586,30 @@ BinaryOpNode::substituteLogPow(subst_table_t &subst_table, vector(this)); if (it != subst_table.end()) - return const_cast(it->second); + return datatree.AddExp(datatree.AddTimes(arg2,const_cast(it->second))); - //Arriving here, we need to create an auxiliary variable for the argument of the log expression: - //AUX_LOG_(arg.idx) - int symb_id = datatree.symbol_table.addPowAuxiliaryVar(arg1->idx); - expr_t newAuxE = datatree.AddVariable(symb_id, 0); - assert(dynamic_cast(newAuxE) != NULL); - subst_table[this] = dynamic_cast(newAuxE); - - //take care of any nested pow expressions by calling arg->substituteLogPow(.), then decreaseLeadsLags for this oExpectation operator + //take care of any nested pow expressions by calling arg->substituteLogPow(.), //arg(lag-period) (holds entire subtree of arg(lag-period) expr_t arg1substexpr = arg1->substituteLogPow(subst_table, neweqs1, neweqs2); assert(arg1substexpr != NULL); expr_t arg2substexpr = arg2->substituteLogPow(subst_table, neweqs1, neweqs2); assert(arg2substexpr != NULL); + + // look for identical expression at the current period + int k = arg1substexpr->maxLead(); + if (k) + arg1substexpr = arg1substexpr->decreaseLeadsLags(k); + it = subst_table.find(arg1substexpr); + // if it exists return it with the appropriate lead/lag + if (it != subst_table.end()) + return datatree.AddExp(datatree.AddTimes(arg2substexpr,(it->second)->decreaseLeadsLags(-k))); + // if not, create an auxiliary variable for the argument of the power expression: + //AUX_POW_(arg.idx) + int symb_id = datatree.symbol_table.addPowAuxiliaryVar(arg1->idx); + expr_t newAuxE = datatree.AddVariable(symb_id, 0); + assert(dynamic_cast(newAuxE) != NULL); + subst_table[arg1substexpr] = dynamic_cast(newAuxE); + // auxiliary equation with the exponential of the auxiliary variable expr_t lhs = datatree.AddExp(newAuxE); neweqs1.push_back(dynamic_cast(datatree.AddEqual(lhs, arg1substexpr))); @@ -3533,10 +3617,8 @@ BinaryOpNode::substituteLogPow(subst_table_t &subst_table, vector(datatree.AddEqual(newAuxE,definition))); - // expression to be used instead of sqrt - newAuxE = datatree.AddTimes(arg2substexpr,newAuxE); - newAuxE = datatree.AddExp(newAuxE); - return newAuxE; + // expression to be used instead of power + return datatree.AddExp(datatree.AddTimes(arg2substexpr,newAuxE->decreaseLeadsLags(-k))); } else { @@ -3566,6 +3648,12 @@ BinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +bool +BinaryOpNode::containsEndogenous(void) const +{ + return (arg1->containsEndogenous() || arg2->containsEndogenous()); +} + expr_t BinaryOpNode::replaceTrendVar() const { @@ -4059,6 +4147,12 @@ TrinaryOpNode::maxExoLag() const return max(arg1->maxExoLag(), max(arg2->maxExoLag(), arg3->maxExoLag())); } +int +TrinaryOpNode::maxLead() const +{ + return max(arg1->maxLead(), max(arg2->maxLead(), arg3->maxLead())); +} + expr_t TrinaryOpNode::decreaseLeadsLags(int n) const { @@ -4157,6 +4251,12 @@ TrinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int l return false; } +bool +TrinaryOpNode::containsEndogenous(void) const +{ + return (arg1->containsEndogenous() || arg2->containsEndogenous() || arg3->containsEndogenous()); +} + expr_t TrinaryOpNode::replaceTrendVar() const { @@ -4616,6 +4716,16 @@ ExternalFunctionNode::maxExoLag() const return val; } +int +ExternalFunctionNode::maxLead() const +{ + int val = 0; + for (vector::const_iterator it = arguments.begin(); + it != arguments.end(); it++) + val = max(val, (*it)->maxLead()); + return val; +} + expr_t ExternalFunctionNode::decreaseLeadsLags(int n) const { @@ -4724,6 +4834,15 @@ ExternalFunctionNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id return false; } +bool +ExternalFunctionNode::containsEndogenous(void) const +{ + bool result = false; + for (vector::const_iterator it = arguments.begin(); it != arguments.end(); it++) + result = result || (*it)->containsEndogenous(); + return result; +} + expr_t ExternalFunctionNode::replaceTrendVar() const { diff --git a/preprocessor/ExprNode.hh b/preprocessor/ExprNode.hh index ca518646f..ffe6aff3a 100644 --- a/preprocessor/ExprNode.hh +++ b/preprocessor/ExprNode.hh @@ -235,6 +235,7 @@ public: virtual void collectModelLocalVariables(set &result) const; virtual void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const = 0; + virtual void computeTemporaryTerms(map &reference_count, temporary_terms_t &temporary_terms, map > &first_occurence, @@ -280,6 +281,10 @@ public: /*! Always returns a non-negative value */ virtual int maxExoLag() const = 0; + //! Returns the relative period of the most forward term in this expression + /*! A negative value means that the expression contains only lagged variables */ + virtual int maxLead() const = 0; + //! Returns a new expression where all the leads/lags have been shifted backwards by the same amount /*! Only acts on endogenous, exogenous, exogenous det @@ -368,6 +373,9 @@ public: */ virtual bool isNumConstNodeEqualTo(double value) const = 0; + //! Returns true if the expression contains one or several endogenous variable + virtual bool containsEndogenous(void) const = 0; + //! Return true if the nodeID is a variable withe a type equal to type_arg, a specific variable id aqual to varfiable_id and a lag equal to lag_arg and false otherwise /*! \param[in] the type (type_arg), specifique variable id (variable_id and the lag (lag_arg) @@ -431,6 +439,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; virtual expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; @@ -440,6 +449,7 @@ public: virtual expr_t substituteLogPow(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual expr_t replaceTrendVar() const; virtual expr_t detrend(int symb_id, expr_t trend) const; @@ -490,6 +500,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; virtual expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; @@ -499,6 +510,7 @@ public: virtual expr_t substituteLogPow(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual expr_t replaceTrendVar() const; virtual expr_t detrend(int symb_id, expr_t trend) const; @@ -562,6 +574,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; //! Creates another UnaryOpNode with the same opcode, but with a possibly different datatree and argument @@ -573,6 +586,7 @@ public: virtual expr_t substituteLogPow(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual expr_t replaceTrendVar() const; virtual expr_t detrend(int symb_id, expr_t trend) const; @@ -649,6 +663,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; //! Creates another BinaryOpNode with the same opcode, but with a possibly different datatree and arguments @@ -660,6 +675,7 @@ public: virtual expr_t substituteLogPow(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual expr_t replaceTrendVar() const; virtual expr_t detrend(int symb_id, expr_t trend) const; @@ -716,6 +732,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; //! Creates another TrinaryOpNode with the same opcode, but with a possibly different datatree and arguments @@ -727,6 +744,7 @@ public: virtual expr_t substituteLogPow(subst_table_t &subst_table, vector &neweqs1, vector &neweqs2) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual expr_t replaceTrendVar() const; virtual expr_t detrend(int symb_id, expr_t trend) const; @@ -788,6 +806,7 @@ public: virtual int maxExoLead() const; virtual int maxEndoLag() const; virtual int maxExoLag() const; + virtual int maxLead() const; virtual expr_t decreaseLeadsLags(int n) const; virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const; virtual expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const; @@ -798,6 +817,7 @@ public: virtual expr_t buildSimilarExternalFunctionNode(vector &alt_args, DataTree &alt_datatree) const; virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) const; + virtual bool containsEndogenous(void) const; virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const; virtual void writePrhs(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, deriv_node_temp_terms_t &tef_terms, const string &ending) const; virtual expr_t replaceTrendVar() const; diff --git a/tests/transform_logpow/ramst.mod b/tests/transform_logpow/ramst.mod index da2eabff6..f059ffb5a 100644 --- a/tests/transform_logpow/ramst.mod +++ b/tests/transform_logpow/ramst.mod @@ -16,9 +16,9 @@ end; initval; x = 0; -aa = 1; -k = ((delt+bet)/(1.0*aa*alph))^(1/(alph-1)); -c = aa*k^alph-delt*k; +aa = 3; +k = ((delt+bet)/(1.0*aa*alph))^(1/(alph-1))+50; +c = aa*k^alph-delt*k+10; end; steady(transform_logpow); diff --git a/tests/transform_logpow/ramst0.mod b/tests/transform_logpow/ramst0.mod new file mode 100644 index 000000000..75735babe --- /dev/null +++ b/tests/transform_logpow/ramst0.mod @@ -0,0 +1,40 @@ +var c k aa; +varexo x; + +parameters alph gam delt bet rho; +alph=0.5; +gam=0.5; +delt=0.02; +bet=0.05; +rho=0.9; + +model; +c + k - aa*k(-1)^alph - (1-delt)*k(-1); +c^(-gam) - (1+bet)^(-1)*(aa(+1)*alph*k^(alph-1) + 1 - delt)*c(+1)^(-gam); +log(aa) = rho*log(aa(-1))+x; +end; + +initval; +x = 0; +aa = 3; +k = ((delt+bet)/(1.0*aa*alph))^(1/(alph-1))+50; +c = aa*k^alph-delt*k+10; +end; + +steady; + +check; + +shocks; +var x; +periods 1; +values 0.2; +end; + +simul(periods=200); + +rplot c; +rplot k; + +write_latex_dynamic_model; +write_latex_static_model; \ No newline at end of file