diff --git a/CodeInterpreter.hh b/CodeInterpreter.hh index 8a9ef76ffdb8888791946d716903df17851e9969..b8b65a5300050bb2391326ca1e0f2302189c2fcd 100644 --- a/CodeInterpreter.hh +++ b/CodeInterpreter.hh @@ -136,7 +136,8 @@ enum SymbolType eParameter = 4, //!< Parameter eModelLocalVariable = 10, //!< Local variable whose scope is model (pound expression) eModFileLocalVariable = 11, //!< Local variable whose scope is mod file (model excluded) - eExternalFunction = 12 //!< External (user-defined) function + eExternalFunction = 12, //!< External (user-defined) function + eTrend = 13 //!< Trend variable }; enum ExpressionType diff --git a/DataTree.hh b/DataTree.hh index 0bd3a813ab36bec9993629a27c7738c18f9a6aa8..648c62c7d4001f7534355db8e9244aa272d05fdf 100644 --- a/DataTree.hh +++ b/DataTree.hh @@ -213,6 +213,16 @@ public: { }; + //! Raised when a trend is declared twice + class TrendException + { + public: + string name; + TrendException(const string &name_arg) : name(name_arg) + { + } + }; + //! Returns the derivation ID, or throws an exception if the derivation ID does not exist virtual int getDerivID(int symb_id, int lag) const throw (UnknownDerivIDException); //! Returns the column of the dynamic Jacobian associated to a derivation ID diff --git a/DynamicModel.cc b/DynamicModel.cc index ea4b544ed11e4ac66d0514e81a17f29d7d2fa0d9..e7ecc7751f17e3b39554162c2008b67289bca9d6 100644 --- a/DynamicModel.cc +++ b/DynamicModel.cc @@ -2411,6 +2411,13 @@ DynamicModel::collect_first_order_derivatives_endogenous() return endo_derivatives; } +void +DynamicModel::runTrendTest(const eval_context_t &eval_context) +{ + computeDerivIDs(); + testTrendDerivativesEqualToZero(eval_context); +} + void DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivatives, bool paramsDerivatives, const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode) @@ -2832,6 +2839,29 @@ DynamicModel::writeDynamicFile(const string &basename, bool block, bool bytecode writeDynamicMFile(t_basename); } +void +DynamicModel::cloneDynamic(DynamicModel &dynamic_model) const +{ + /* Ensure that we are using the same symbol table, because at many places we manipulate + symbol IDs rather than strings */ + assert(&symbol_table == &dynamic_model.symbol_table); + + // Convert model local variables (need to be done first) + for (map<int, expr_t>::const_iterator it = local_variables_table.begin(); + it != local_variables_table.end(); it++) + dynamic_model.AddLocalVariable(it->first, it->second->cloneDynamic(dynamic_model)); + + // Convert equations + for (vector<BinaryOpNode *>::const_iterator it = equations.begin(); + it != equations.end(); it++) + dynamic_model.addEquation((*it)->cloneDynamic(dynamic_model)); + + // Convert auxiliary equations + for (deque<BinaryOpNode *>::const_iterator it = aux_equations.begin(); + it != aux_equations.end(); it++) + dynamic_model.addAuxEquation((*it)->cloneDynamic(dynamic_model)); +} + void DynamicModel::toStatic(StaticModel &static_model) const { @@ -2870,6 +2900,7 @@ DynamicModel::computeDerivIDs() equations[i]->collectVariables(eExogenous, dynvars); equations[i]->collectVariables(eExogenousDet, dynvars); equations[i]->collectVariables(eParameter, dynvars); + equations[i]->collectVariables(eTrend, dynvars); } for (set<pair<int, int> >::const_iterator it = dynvars.begin(); @@ -2982,7 +3013,8 @@ DynamicModel::computeDynJacobianCols(bool jacobianExo) dyn_jacobian_cols_table[deriv_id] = dynJacobianColsNbr + symbol_table.exo_nbr() + tsid; break; case eParameter: - // We don't assign a dynamic jacobian column to parameters + case eTrend: + // We don't assign a dynamic jacobian column to parameters or trend variables break; default: // Shut up GCC @@ -3012,6 +3044,34 @@ DynamicModel::getDynJacobianCol(int deriv_id) const throw (UnknownDerivIDExcepti return it->second; } +void +DynamicModel::testTrendDerivativesEqualToZero(const eval_context_t &eval_context) +{ + for (deriv_id_table_t::const_iterator it = deriv_id_table.begin(); + it != deriv_id_table.end(); it++) + if (symbol_table.getType(it->first.first) == eTrend) + for (int eq = 0; eq < (int) equations.size(); eq++) + { + expr_t testeq = AddLog(AddMinus(equations[eq]->get_arg1(), // F: a = b -> ln(a - b) + equations[eq]->get_arg2())); + assert(testeq != NULL); + testeq = testeq->getDerivative(it->second); // d F / d Trend + for (deriv_id_table_t::const_iterator endogit = deriv_id_table.begin(); + endogit != deriv_id_table.end(); endogit++) + if (symbol_table.getType(endogit->first.first) == eEndogenous) + { + double nearZero = testeq->getDerivative(endogit->second)->eval(eval_context); // eval d F / d Trend d Endog + if (nearZero < -ZERO_BAND || nearZero > ZERO_BAND) + { + cerr << "ERROR: the second-order cross partial of equation " << eq + 1 << " w.r.t. trend variable " + << symbol_table.getName(it->first.first) << " and endogenous variable " + << symbol_table.getName(endogit->first.first) << " is not null. " << endl; + exit(EXIT_FAILURE); + } + } + } +} + void DynamicModel::computeParamsDerivatives() { @@ -3467,6 +3527,37 @@ DynamicModel::transformPredeterminedVariables() } } +void +DynamicModel::detrendEquations() +{ + for (trend_symbols_map_t::const_iterator it = nonstationary_symbols_map.begin(); + it != nonstationary_symbols_map.end(); it++) + for (int i = 0; i < (int) equations.size(); i++) + { + BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->detrend(it->first, it->second)); + assert(substeq != NULL); + equations[i] = dynamic_cast<BinaryOpNode *>(substeq); + } + + for (int i = 0; i < (int) equations.size(); i++) + { + BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->removeTrendLeadLag(trend_symbols_map)); + assert(substeq != NULL); + equations[i] = dynamic_cast<BinaryOpNode *>(substeq); + } +} + +void +DynamicModel::removeTrendVariableFromEquations() +{ + for (int i = 0; i < (int) equations.size(); i++) + { + BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->replaceTrendVar()); + assert(substeq != NULL); + equations[i] = dynamic_cast<BinaryOpNode *>(substeq); + } +} + void DynamicModel::fillEvalContext(eval_context_t &eval_context) const { @@ -3503,4 +3594,10 @@ DynamicModel::fillEvalContext(eval_context_t &eval_context) const // Do nothing } } + + //Third, trend variables + vector <int> trendVars = symbol_table.getTrendVarIds(); + for (vector <int>::const_iterator it = trendVars.begin(); + it != trendVars.end(); it++) + eval_context[*it] = 2; //not <= 0 bc of log, not 1 bc of powers } diff --git a/DynamicModel.hh b/DynamicModel.hh index 05189ff9c437235456d0d47453dd183a4811c25f..4d98a97d4e89099de98958861f4cc9c562d1be81 100644 --- a/DynamicModel.hh +++ b/DynamicModel.hh @@ -21,6 +21,7 @@ #define _DYNAMICMODEL_HH using namespace std; +#define ZERO_BAND 1e-8 #include <fstream> @@ -156,6 +157,8 @@ private: void computeDynJacobianCols(bool jacobianExo); //! Computes derivatives of the Jacobian w.r. to parameters void computeParamsDerivatives(); + //! Computes derivatives of the Jacobian w.r. to trend vars and tests that they are equal to zero + void testTrendDerivativesEqualToZero(const eval_context_t &eval_context); //! Computes temporary terms for the file containing parameters derivatives void computeParamsDerivativesTemporaryTerms(); //! Collect only the first derivatives @@ -278,6 +281,10 @@ public: /*! It assumes that the static model given in argument has just been allocated */ void toStatic(StaticModel &static_model) const; + //! Copies a dynamic model (only the equations) + /*! It assumes that the dynamic model given in argument has just been allocated */ + void cloneDynamic(DynamicModel &dynamic_model) const; + //! Writes LaTeX file with the equations of the dynamic model void writeLatexFile(const string &basename) const; @@ -294,6 +301,9 @@ public: return true; }; + //! Drive test of detrended equations + void runTrendTest(const eval_context_t &eval_context); + //! Transforms the model by removing all leads greater or equal than 2 on endos /*! Note that this can create new lags on endos and exos */ void substituteEndoLeadGreaterThanTwo(bool deterministic_model); @@ -314,6 +324,12 @@ public: //! Transforms the model by decreasing the lead/lag of predetermined variables in model equations by one void transformPredeterminedVariables(); + //! Transforms the model by removing trends specified by the user + void detrendEquations(); + + //! Transforms the model by replacing trend variables with a 1 + void removeTrendVariableFromEquations(); + //! Fills eval context with values of model local variables and auxiliary variables void fillEvalContext(eval_context_t &eval_context) const; diff --git a/DynareBison.yy b/DynareBison.yy index 1cdeb212e09b15af353850cbfb348322596e116f..defb9cc9783d49c632d5d873fdc0f87685168407 100644 --- a/DynareBison.yy +++ b/DynareBison.yy @@ -154,7 +154,7 @@ class ParsingDriver; %token COMPUTE_MDD COMPUTE_PROBABILITIES PRINT_DRAWS N_DRAWS THINNING_FACTOR PROPOSAL_DRAWS MARKOV_FILE %token MHM_FILE OUTPUT_FILE_TAG DRAWS_NBR_BURN_IN_1 DRAWS_NBR_BURN_IN_2 DRAWS_NBR_MEAN_VAR_ESTIMATE %token DRAWS_NBR_MODIFIED_HARMONIC_MEAN DIRICHLET_SCALE -%token SBVAR MS_SBVAR +%token SBVAR MS_SBVAR TREND_VAR DEFLATOR GROWTH_FACTOR %token SVAR_IDENTIFICATION EQUATION EXCLUSION LAG UPPER_CHOLESKY LOWER_CHOLESKY %token MARKOV_SWITCHING CHAIN STATE DURATION NUMBER_OF_STATES %token SVAR COEFFICIENTS VARIANCES CONSTANTS EQUATIONS @@ -241,6 +241,7 @@ statement : parameters | svar | external_function | steady_state_model + | trend_var ; dsample : DSAMPLE INT_NUMBER ';' @@ -251,7 +252,42 @@ dsample : DSAMPLE INT_NUMBER ';' rplot : RPLOT symbol_list ';' { driver.rplot(); }; -var : VAR var_list ';'; +trend_var : TREND_VAR '(' GROWTH_FACTOR EQUAL { driver.begin_trend(); } hand_side ')' trend_var_list ';' + { driver.end_trend_var($6); } + ; + +trend_var_list : trend_var_list symbol + { driver.declare_trend_var($2); } + | trend_var_list COMMA symbol + { driver.declare_trend_var($3); } + | symbol + { driver.declare_trend_var($1); } + | trend_var_list symbol TEX_NAME + { driver.declare_trend_var($2, $3); } + | trend_var_list COMMA symbol TEX_NAME + { driver.declare_trend_var($3, $4); } + | symbol TEX_NAME + { driver.declare_trend_var($1, $2); } + ; + +var : VAR var_list ';' + | VAR '(' DEFLATOR EQUAL { driver.begin_trend(); } hand_side ')' nonstationary_var_list ';' + { driver.end_nonstationary_var($6); } + ; + +nonstationary_var_list : nonstationary_var_list symbol + { driver.declare_nonstationary_var($2); } + | nonstationary_var_list COMMA symbol + { driver.declare_nonstationary_var($3); } + | symbol + { driver.declare_nonstationary_var($1); } + | nonstationary_var_list symbol TEX_NAME + { driver.declare_nonstationary_var($2, $3); } + | nonstationary_var_list COMMA symbol TEX_NAME + { driver.declare_nonstationary_var($3, $4); } + | symbol TEX_NAME + { driver.declare_nonstationary_var($1, $2); } + ; varexo : VAREXO varexo_list ';'; @@ -702,7 +738,6 @@ period_list : period_list COMMA INT_NUMBER { driver.add_period($1); } ; - sigma_e : SIGMA_E EQUAL '[' triangular_matrix ']' ';' { driver.do_sigma_e(); }; value_list diff --git a/DynareFlex.ll b/DynareFlex.ll index f2b1b7b97072dd3944f18e6687d01891b304bab6..388f07fd28280091361c016c4d19599a0633f5df 100644 --- a/DynareFlex.ll +++ b/DynareFlex.ll @@ -102,6 +102,7 @@ string eofbuff; <INITIAL>var {BEGIN DYNARE_STATEMENT; return token::VAR;} <INITIAL>varexo {BEGIN DYNARE_STATEMENT; return token::VAREXO;} <INITIAL>varexo_det {BEGIN DYNARE_STATEMENT; return token::VAREXO_DET;} +<INITIAL>trend_var {BEGIN DYNARE_STATEMENT; return token::TREND_VAR;} <INITIAL>predetermined_variables {BEGIN DYNARE_STATEMENT; return token::PREDETERMINED_VARIABLES;} <INITIAL>parameters {BEGIN DYNARE_STATEMENT; return token::PARAMETERS;} <INITIAL>periods {BEGIN DYNARE_STATEMENT; return token::PERIODS;} @@ -360,7 +361,9 @@ string eofbuff; <DYNARE_STATEMENT>filter_covariance {return token::FILTER_COVARIANCE; } <DYNARE_STATEMENT>filter_decomposition {return token::FILTER_DECOMPOSITION; } <DYNARE_STATEMENT>selected_variables_only {return token::SELECTED_VARIABLES_ONLY; } -<DYNARE_STATEMENT>pruning {return token::PRUNING; }; +<DYNARE_STATEMENT>pruning {return token::PRUNING; } +<DYNARE_STATEMENT>deflator {return token::DEFLATOR;} +<DYNARE_STATEMENT>growth_factor {return token::GROWTH_FACTOR;} <DYNARE_STATEMENT>[\$][^$]*[\$] { strtok(yytext+1, "$"); diff --git a/ExprNode.cc b/ExprNode.cc index 40c1cd2a2cb61f7f257e52482c61c52aeb43e924..f652a98cee84cca28cdad3e525d0489930fdda8e 100644 --- a/ExprNode.cc +++ b/ExprNode.cc @@ -329,6 +329,12 @@ NumConstNode::toStatic(DataTree &static_datatree) const return static_datatree.AddNumConstant(datatree.num_constants.get(id)); } +expr_t +NumConstNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + return dynamic_datatree.AddNumConstant(datatree.num_constants.get(id)); +} + int NumConstNode::maxEndoLead() const { @@ -424,6 +430,24 @@ NumConstNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +expr_t +NumConstNode::replaceTrendVar() const +{ + return const_cast<NumConstNode *>(this); +} + +expr_t +NumConstNode::detrend(int symb_id, expr_t trend) const +{ + return const_cast<NumConstNode *>(this); +} + +expr_t +NumConstNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + return const_cast<NumConstNode *>(this); +} + void VariableNode::prepareForDerivation() { @@ -439,6 +463,7 @@ VariableNode::prepareForDerivation() case eExogenous: case eExogenousDet: case eParameter: + case eTrend: // For a variable or a parameter, the only non-null derivative is with respect to itself non_null_derivatives.insert(datatree.getDerivID(symb_id, lag)); break; @@ -465,6 +490,7 @@ VariableNode::computeDerivative(int deriv_id) case eExogenous: case eExogenousDet: case eParameter: + case eTrend: if (deriv_id == datatree.getDerivID(symb_id, lag)) return datatree.One; else @@ -514,7 +540,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, output << "\\bar{"; output << datatree.symbol_table.getTeXName(symb_id); if (output_type == oLatexDynamicModel - && (type == eEndogenous || type == eExogenous || type == eExogenousDet || type == eModelLocalVariable)) + && (type == eEndogenous || type == eExogenous || type == eExogenousDet || type == eModelLocalVariable || type == eTrend)) { output << "_{t"; if (lag != 0) @@ -677,6 +703,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, break; case eExternalFunction: + case eTrend: cerr << "Impossible case" << endl; exit(EXIT_FAILURE); } @@ -812,6 +839,7 @@ VariableNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recur case eExogenous: case eExogenousDet: case eParameter: + case eTrend: if (deriv_id == datatree.getDerivID(symb_id, lag)) return datatree.One; else @@ -856,6 +884,12 @@ VariableNode::toStatic(DataTree &static_datatree) const return static_datatree.AddVariable(symb_id); } +expr_t +VariableNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + return dynamic_datatree.AddVariable(symb_id, lag); +} + int VariableNode::maxEndoLead() const { @@ -920,6 +954,7 @@ VariableNode::decreaseLeadsLags(int n) const case eEndogenous: case eExogenous: case eExogenousDet: + case eTrend: return datatree.AddVariable(symb_id, lag-n); case eModelLocalVariable: return datatree.local_variables_table[symb_id]->decreaseLeadsLags(n); @@ -1104,6 +1139,51 @@ VariableNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +expr_t +VariableNode::replaceTrendVar() const +{ + if (get_type() == eTrend) + return datatree.One; + else + return const_cast<VariableNode *>(this); +} + +expr_t +VariableNode::detrend(int symb_id, expr_t trend) const +{ + if (get_symb_id() != symb_id) + return const_cast<VariableNode *>(this); + + if (get_lag() == 0) + return datatree.AddTimes(const_cast<VariableNode *>(this), trend); + else + return datatree.AddTimes(const_cast<VariableNode *>(this), trend->decreaseLeadsLags(-1*get_lag())); +} + +expr_t +VariableNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + if (get_type() != eTrend || get_lag() == 0) + return const_cast<VariableNode *>(this); + + map<int, expr_t>::const_iterator it = trend_symbols_map.find(symb_id); + expr_t noTrendLeadLagNode = new VariableNode(datatree, it->first, 0); + if (get_lag() > 0) + { + expr_t growthFactorSequence = it->second->decreaseLeadsLags(-1); + for (int i=1; i<get_lag(); i++) + growthFactorSequence = datatree.AddTimes(growthFactorSequence, it->second->decreaseLeadsLags(-1*(i+1))); + return datatree.AddTimes(noTrendLeadLagNode, growthFactorSequence); + } + else //get_lag < 0 + { + expr_t growthFactorSequence = it->second; + for (int i=1; i<abs(get_lag()); i++) + growthFactorSequence = datatree.AddTimes(growthFactorSequence, it->second->decreaseLeadsLags(i)); + return datatree.AddDivide(noTrendLeadLagNode, growthFactorSequence); + } +} + UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const expr_t arg_arg, const int expectation_information_set_arg, const string &expectation_information_set_name_arg) : ExprNode(datatree_arg), arg(arg_arg), @@ -1779,6 +1859,13 @@ UnaryOpNode::toStatic(DataTree &static_datatree) const return buildSimilarUnaryOpNode(sarg, static_datatree); } +expr_t +UnaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + expr_t substarg = arg->cloneDynamic(dynamic_datatree); + return buildSimilarUnaryOpNode(substarg, dynamic_datatree); +} + int UnaryOpNode::maxEndoLead() const { @@ -1948,6 +2035,27 @@ UnaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag return false; } +expr_t +UnaryOpNode::replaceTrendVar() const +{ + expr_t argsubst = arg->replaceTrendVar(); + return buildSimilarUnaryOpNode(argsubst, datatree); +} + +expr_t +UnaryOpNode::detrend(int symb_id, expr_t trend) const +{ + expr_t argsubst = arg->detrend(symb_id, trend); + return buildSimilarUnaryOpNode(argsubst, datatree); +} + +expr_t +UnaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + expr_t argsubst = arg->removeTrendLeadLag(trend_symbols_map); + return buildSimilarUnaryOpNode(argsubst, datatree); +} + BinaryOpNode::BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg, BinaryOpcode op_code_arg, const expr_t arg2_arg) : ExprNode(datatree_arg), @@ -2817,6 +2925,14 @@ BinaryOpNode::toStatic(DataTree &static_datatree) const return buildSimilarBinaryOpNode(sarg1, sarg2, static_datatree); } +expr_t +BinaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + expr_t substarg1 = arg1->cloneDynamic(dynamic_datatree); + expr_t substarg2 = arg2->cloneDynamic(dynamic_datatree); + return buildSimilarBinaryOpNode(substarg1, substarg2, dynamic_datatree); +} + int BinaryOpNode::maxEndoLead() const { @@ -2899,7 +3015,6 @@ BinaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vecto return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs); } } - } expr_t @@ -2982,6 +3097,30 @@ BinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int la return false; } +expr_t +BinaryOpNode::replaceTrendVar() const +{ + expr_t arg1subst = arg1->replaceTrendVar(); + expr_t arg2subst = arg2->replaceTrendVar(); + return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); +} + +expr_t +BinaryOpNode::detrend(int symb_id, expr_t trend) const +{ + expr_t arg1subst = arg1->detrend(symb_id, trend); + expr_t arg2subst = arg2->detrend(symb_id, trend); + return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); +} + +expr_t +BinaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + expr_t arg1subst = arg1->removeTrendLeadLag(trend_symbols_map); + expr_t arg2subst = arg2->removeTrendLeadLag(trend_symbols_map); + return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree); +} + TrinaryOpNode::TrinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg, TrinaryOpcode op_code_arg, const expr_t arg2_arg, const expr_t arg3_arg) : ExprNode(datatree_arg), @@ -3403,6 +3542,15 @@ TrinaryOpNode::toStatic(DataTree &static_datatree) const return buildSimilarTrinaryOpNode(sarg1, sarg2, sarg3, static_datatree); } +expr_t +TrinaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + expr_t substarg1 = arg1->cloneDynamic(dynamic_datatree); + expr_t substarg2 = arg2->cloneDynamic(dynamic_datatree); + expr_t substarg3 = arg3->cloneDynamic(dynamic_datatree); + return buildSimilarTrinaryOpNode(substarg1, substarg2, substarg3, dynamic_datatree); +} + int TrinaryOpNode::maxEndoLead() const { @@ -3516,6 +3664,33 @@ TrinaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int l return false; } +expr_t +TrinaryOpNode::replaceTrendVar() const +{ + expr_t arg1subst = arg1->replaceTrendVar(); + expr_t arg2subst = arg2->replaceTrendVar(); + expr_t arg3subst = arg3->replaceTrendVar(); + return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); +} + +expr_t +TrinaryOpNode::detrend(int symb_id, expr_t trend) const +{ + expr_t arg1subst = arg1->detrend(symb_id, trend); + expr_t arg2subst = arg2->detrend(symb_id, trend); + expr_t arg3subst = arg3->detrend(symb_id, trend); + return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); +} + +expr_t +TrinaryOpNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + expr_t arg1subst = arg1->removeTrendLeadLag(trend_symbols_map); + expr_t arg2subst = arg2->removeTrendLeadLag(trend_symbols_map); + expr_t arg3subst = arg3->removeTrendLeadLag(trend_symbols_map); + return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree); +} + ExternalFunctionNode::ExternalFunctionNode(DataTree &datatree_arg, int symb_id_arg, const vector<expr_t> &arguments_arg) : @@ -3797,6 +3972,16 @@ ExternalFunctionNode::toStatic(DataTree &static_datatree) const return static_datatree.AddExternalFunction(symb_id, static_arguments); } +expr_t +ExternalFunctionNode::cloneDynamic(DataTree &dynamic_datatree) const +{ + vector<expr_t> dynamic_arguments; + for (vector<expr_t>::const_iterator it = arguments.begin(); + it != arguments.end(); it++) + dynamic_arguments.push_back((*it)->cloneDynamic(dynamic_datatree)); + return dynamic_datatree.AddExternalFunction(symb_id, dynamic_arguments); +} + int ExternalFunctionNode::maxEndoLead() const { @@ -3936,6 +4121,33 @@ ExternalFunctionNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id return false; } +expr_t +ExternalFunctionNode::replaceTrendVar() const +{ + vector<expr_t> arguments_subst; + for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++) + arguments_subst.push_back((*it)->replaceTrendVar()); + return buildSimilarExternalFunctionNode(arguments_subst, datatree); +} + +expr_t +ExternalFunctionNode::detrend(int symb_id, expr_t trend) const +{ + vector<expr_t> arguments_subst; + for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++) + arguments_subst.push_back((*it)->detrend(symb_id, trend)); + return buildSimilarExternalFunctionNode(arguments_subst, datatree); +} + +expr_t +ExternalFunctionNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const +{ + vector<expr_t> arguments_subst; + for (vector<expr_t>::const_iterator it = arguments.begin(); it != arguments.end(); it++) + arguments_subst.push_back((*it)->removeTrendLeadLag(trend_symbols_map)); + return buildSimilarExternalFunctionNode(arguments_subst, datatree); +} + FirstDerivExternalFunctionNode::FirstDerivExternalFunctionNode(DataTree &datatree_arg, int top_level_symb_id_arg, const vector<expr_t> &arguments_arg, diff --git a/ExprNode.hh b/ExprNode.hh index 9a4df0e2066af5f83a3c21691330f5cd8fb306dd..de71231eacb932f11ddc0ded7cdc5726ce961b3c 100644 --- a/ExprNode.hh +++ b/ExprNode.hh @@ -356,6 +356,22 @@ public: */ virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const = 0; + //! Replaces the Trend var with datatree.One + virtual expr_t replaceTrendVar() const = 0; + + //! Constructs a new expression where the variable indicated by symb_id has been detrended + /*! + \param[in] symb_id indicating the variable to be detrended + \param[in] expr_t indicating the trend + \param[out] expr_t the new binary op pointing to a detrended variable + */ + virtual expr_t detrend(int symb_id, expr_t trend) const = 0; + + //! Add ExprNodes to the provided datatree + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const = 0; + + //! Move a trend variable with lag/lead to time t by dividing/multiplying by its growth factor + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const = 0; }; //! Object used to compare two nodes (using their indexes) @@ -405,6 +421,10 @@ public: virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; //! Symbol or variable node @@ -458,6 +478,10 @@ public: virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; //! Unary operator node @@ -523,6 +547,10 @@ public: virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; //! Binary operator node @@ -593,6 +621,10 @@ public: virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; //! Trinary operator node @@ -645,6 +677,10 @@ public: virtual expr_t decreaseLeadsLagsPredeterminedVariables() const; virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; //! External function node @@ -703,6 +739,10 @@ public: virtual bool isNumConstNodeEqualTo(double value) 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; + virtual expr_t detrend(int symb_id, expr_t trend) const; + virtual expr_t cloneDynamic(DataTree &dynamic_datatree) const; + virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const; }; class FirstDerivExternalFunctionNode : public ExternalFunctionNode diff --git a/ModFile.cc b/ModFile.cc index f2da960cf81eaf80722229c6af7881cad2ec1f12..e97f5ff51c8fe9e78bd9475beaecb45c176adcbe 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -25,10 +25,11 @@ ModFile::ModFile() : expressions_tree(symbol_table, num_constants, external_functions_table), dynamic_model(symbol_table, num_constants, external_functions_table), + trend_dynamic_model(symbol_table, num_constants, external_functions_table), static_model(symbol_table, num_constants, external_functions_table), steady_state_model(symbol_table, num_constants, external_functions_table, static_model), linear(false), block(false), byte_code(false), - use_dll(false), no_static(false) + use_dll(false), no_static(false), nonstationary_variables(false) { } @@ -212,6 +213,13 @@ ModFile::transformPass() if (symbol_table.predeterminedNbr() > 0) dynamic_model.transformPredeterminedVariables(); + if (nonstationary_variables) + { + dynamic_model.detrendEquations(); + dynamic_model.cloneDynamic(trend_dynamic_model); + dynamic_model.removeTrendVariableFromEquations(); + } + // Create auxiliary vars for Expectation operator dynamic_model.substituteExpectation(mod_file_struct.partial_information); @@ -295,6 +303,9 @@ ModFile::computingPass(bool no_tmp_terms) || mod_file_struct.ramsey_policy_present || mod_file_struct.identification_present; if (dynamic_model.equation_number() > 0) { + if (nonstationary_variables) + trend_dynamic_model.runTrendTest(global_eval_context); + // Compute static model and its derivatives dynamic_model.toStatic(static_model); if(!no_static) diff --git a/ModFile.hh b/ModFile.hh index b2d650dae18e7e6b02286351d203b0252ba5e8c6..a9f354dbfd98936a02e6e06c656dc249f62b4552 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -50,6 +50,8 @@ public: DataTree expressions_tree; //! Dynamic model, as declared in the "model" block DynamicModel dynamic_model; + //! A copy of Dynamic model, for testing trends declared by user + DynamicModel trend_dynamic_model; //! Static model, as derived from the "model" block when leads and lags have been removed StaticModel static_model; //! Static model, as declared in the "steady_state_model" block if present @@ -69,6 +71,9 @@ public: //! Is the static model have to computed (no_static=false) or not (no_static=true). Option of 'model' bool no_static; + //! Are nonstationary variables present ? + bool nonstationary_variables; + //! Global evaluation context /*! Filled using initval blocks and parameters initializations */ eval_context_t global_eval_context; diff --git a/ModelTree.cc b/ModelTree.cc index e4beba9d61f0309697ff35d59710aa5ab656e7da..c51f2ae2778620b616ba4bedde533ac5236abae6 100644 --- a/ModelTree.cc +++ b/ModelTree.cc @@ -1362,3 +1362,29 @@ ModelTree::addAuxEquation(expr_t eq) aux_equations.push_back(beq); } + +void +ModelTree::addTrendVariables(vector<int> trend_vars, expr_t growth_factor) throw (TrendException) +{ + while (!trend_vars.empty()) + if (trend_symbols_map.find(trend_vars.back()) != trend_symbols_map.end()) + throw TrendException(symbol_table.getName(trend_vars.back())); + else + { + trend_symbols_map[trend_vars.back()] = growth_factor; + trend_vars.pop_back(); + } +} + +void +ModelTree::addNonstationaryVariables(vector<int> nonstationary_vars, expr_t deflator) throw (TrendException) +{ + while (!nonstationary_vars.empty()) + if (nonstationary_symbols_map.find(nonstationary_vars.back()) != nonstationary_symbols_map.end()) + throw TrendException(symbol_table.getName(nonstationary_vars.back())); + else + { + nonstationary_symbols_map[nonstationary_vars.back()] = deflator; + nonstationary_vars.pop_back(); + } +} diff --git a/ModelTree.hh b/ModelTree.hh index 47ad302d799db63fee4f49351f36859ee95f8a15..11ac9bf7cb71f619ed9b561e834f606eed14c909 100644 --- a/ModelTree.hh +++ b/ModelTree.hh @@ -45,12 +45,14 @@ typedef vector< pair<pair<int, int>, pair< int, expr_t > > > block_derivatives_e //! for all blocks derivatives description typedef vector<block_derivatives_equation_variable_laglead_nodeid_t> blocks_derivatives_t; +//! for all trends +typedef map<int, expr_t> trend_symbols_map_t; + //! Shared code for static and dynamic models class ModelTree : public DataTree { friend class DynamicModel; friend class StaticModel; - protected: //! Stores declared and generated auxiliary equations vector<BinaryOpNode *> equations; @@ -92,6 +94,10 @@ protected: //! Temporary terms (those which will be noted Txxxx) temporary_terms_t temporary_terms; + //! Trend variables and their growth factors + trend_symbols_map_t trend_symbols_map; + //! Nonstationary variables and their deflators + trend_symbols_map_t nonstationary_symbols_map; //! Computes 1st derivatives /*! \param vars the derivation IDs w.r. to which compute the derivatives */ @@ -233,6 +239,10 @@ public: void addAuxEquation(expr_t eq); //! Returns the number of equations in the model int equation_number() const; + //! Adds a trend variable with its growth factor + void addTrendVariables(vector<int> trend_vars, expr_t growth_factor) throw (TrendException); + //! Adds a nonstationary variable with its deflator + void addNonstationaryVariables(vector<int> nonstationary_vars, expr_t deflator) throw (TrendException); inline static std::string c_Equation_Type(int type) diff --git a/ParsingDriver.cc b/ParsingDriver.cc index 6f17788b7d0052aecd9eec2f4d41a885abd703de..f0652bebb57cef3f5dd751fee397591f21f70651 100644 --- a/ParsingDriver.cc +++ b/ParsingDriver.cc @@ -164,6 +164,37 @@ ParsingDriver::declare_parameter(string *name, string *tex_name) delete tex_name; } +void +ParsingDriver::begin_trend() +{ + set_current_data_tree(&mod_file->dynamic_model); +} + +void +ParsingDriver::declare_trend_var(string *name, string *tex_name) +{ + declare_symbol(name, eTrend, tex_name); + declared_trend_vars.push_back(mod_file->symbol_table.getID(*name)); + delete name; + if (tex_name != NULL) + delete tex_name; +} + +void +ParsingDriver::end_trend_var(expr_t growth_factor) +{ + try + { + dynamic_model->addTrendVariables(declared_trend_vars, growth_factor); + } + catch (DataTree::TrendException &e) + { + error("Trend variable " + e.name + " was declared twice."); + } + declared_trend_vars.clear(); + reset_data_tree(); +} + void ParsingDriver::add_predetermined_variable(string *name) { @@ -260,6 +291,32 @@ ParsingDriver::add_expression_variable(string *name) return id; } +void +ParsingDriver::declare_nonstationary_var(string *name, string *tex_name) +{ + declare_endogenous(new string(*name), tex_name); + declared_nonstationary_vars.push_back(mod_file->symbol_table.getID(*name)); + mod_file->nonstationary_variables = true; + delete name; + if (tex_name != NULL) + delete tex_name; +} + +void +ParsingDriver::end_nonstationary_var(expr_t deflator) +{ + try + { + dynamic_model->addNonstationaryVariables(declared_nonstationary_vars, deflator); + } + catch (DataTree::TrendException &e) + { + error("Variable " + e.name + " was listed more than once as following a trend."); + } + declared_nonstationary_vars.clear(); + reset_data_tree(); +} + void ParsingDriver::periods(string *periods) { diff --git a/ParsingDriver.hh b/ParsingDriver.hh index 597c735490323f3e6b66a88154e010e54be0db3c..32147ee21a5b37ab779e94f580f7d332ea50128e 100644 --- a/ParsingDriver.hh +++ b/ParsingDriver.hh @@ -163,6 +163,10 @@ private: int current_external_function_id; //! Temporary storage for option list provided to external_function() ExternalFunctionsTable::external_function_options current_external_function_options; + //! Temporary storage for declaring trend variables + vector<int> declared_trend_vars; + //! Temporary storage for declaring nonstationary variables + vector<int> declared_nonstationary_vars; //! reset the values for temporary storage void reset_current_external_function_options(); //! Adds a model lagged variable to ModelTree and VariableTable @@ -502,6 +506,16 @@ public: void begin_steady_state_model(); //! Add an assignment equation in steady_state_model block void add_steady_state_model_equal(string *varname, expr_t expr); + //! Switches datatree + void begin_trend(); + //! Declares a trend variable with its growth factor + void declare_trend_var(string *name, string *tex_name = NULL); + //! Ends declaration of trend variable + void end_trend_var(expr_t growth_factor); + //! Declares a nonstationary variable with its deflator + void declare_nonstationary_var(string *name, string *tex_name = NULL); + //! Ends declaration of nonstationary variable + void end_nonstationary_var(expr_t deflator); }; #endif // ! PARSING_DRIVER_HH diff --git a/SymbolTable.cc b/SymbolTable.cc index a1e0d0b1f46d31173554367a18f97ce0504ab29d..071db40d90d52fc98c75200e61bbf37092655713 100644 --- a/SymbolTable.cc +++ b/SymbolTable.cc @@ -433,3 +433,14 @@ SymbolTable::getObservedVariableIndex(int symb_id) const assert(it != varobs.end()); return (int) (it - varobs.begin()); } + +vector <int> +SymbolTable::getTrendVarIds() const +{ + vector <int> trendVars; + for (symbol_table_type::const_iterator it = symbol_table.begin(); + it != symbol_table.end(); it++) + if (getType(it->second) == eTrend) + trendVars.push_back(it->second); + return trendVars; +} diff --git a/SymbolTable.hh b/SymbolTable.hh index 43bdf87ff8ac2fa06b83d5348f8bd89f3f60fe40..ad0579cdd686d39257f04e707b27b964a92a8408 100644 --- a/SymbolTable.hh +++ b/SymbolTable.hh @@ -261,6 +261,7 @@ public: bool isObservedVariable(int symb_id) const; //! Return the index of a given observed variable in the vector of all observed variables int getObservedVariableIndex(int symb_id) const; + vector <int> getTrendVarIds() const; }; inline bool