diff --git a/preprocessor/DataTree.cc b/preprocessor/DataTree.cc index 712d4e90b..01050a25a 100644 --- a/preprocessor/DataTree.cc +++ b/preprocessor/DataTree.cc @@ -426,6 +426,12 @@ DataTree::AddExpectation(int iArg1, NodeID iArg2) return AddUnaryOp(oExpectation, iArg2, iArg1); } +NodeID +DataTree::AddExpectation(string *iArg1, NodeID iArg2) +{ + return AddUnaryOp(oExpectation, iArg2, 0, *iArg1); +} + NodeID DataTree::AddEqual(NodeID iArg1, NodeID iArg2) { diff --git a/preprocessor/DataTree.hh b/preprocessor/DataTree.hh index 039aae26d..05fe6047c 100644 --- a/preprocessor/DataTree.hh +++ b/preprocessor/DataTree.hh @@ -78,7 +78,7 @@ private: int node_counter; inline NodeID AddPossiblyNegativeConstant(double val); - inline NodeID AddUnaryOp(UnaryOpcode op_code, NodeID arg, int arg_exp_info_set = 0); + inline NodeID AddUnaryOp(UnaryOpcode op_code, NodeID arg, int arg_exp_info_set = 0, const string &arg_exp_info_set_name=""); inline NodeID AddBinaryOp(NodeID arg1, BinaryOpcode op_code, NodeID arg2); inline NodeID AddTrinaryOp(NodeID arg1, TrinaryOpcode op_code, NodeID arg2, NodeID arg3); @@ -132,6 +132,8 @@ public: NodeID AddPower(NodeID iArg1, NodeID iArg2); //! Adds "E(arg1)(arg2)" to model tree NodeID AddExpectation(int iArg1, NodeID iArg2); + //! Adds "E(arg1)(arg2)" to model tree + NodeID AddExpectation(string *iArg1, NodeID iArg2); //! Adds "exp(arg)" to model tree NodeID AddExp(NodeID iArg1); //! Adds "log(arg)" to model tree @@ -220,7 +222,7 @@ DataTree::AddPossiblyNegativeConstant(double v) } inline NodeID -DataTree::AddUnaryOp(UnaryOpcode op_code, NodeID arg, int arg_exp_info_set) +DataTree::AddUnaryOp(UnaryOpcode op_code, NodeID arg, int arg_exp_info_set, const string &arg_exp_info_set_name) { // If the node already exists in tree, share it unary_op_node_map_type::iterator it = unary_op_node_map.find(make_pair(arg, op_code)); @@ -242,7 +244,7 @@ DataTree::AddUnaryOp(UnaryOpcode op_code, NodeID arg, int arg_exp_info_set) { } } - return new UnaryOpNode(*this, op_code, arg, arg_exp_info_set); + return new UnaryOpNode(*this, op_code, arg, arg_exp_info_set, arg_exp_info_set_name); } inline NodeID diff --git a/preprocessor/DynamicModel.cc b/preprocessor/DynamicModel.cc index 1bfb09d63..9e39502b8 100644 --- a/preprocessor/DynamicModel.cc +++ b/preprocessor/DynamicModel.cc @@ -2734,6 +2734,9 @@ DynamicModel::substituteLeadLagInternal(aux_var_t type) case avExpectation: cout << "expectation"; break; + case avExpectationRIS: + cout << "expectation conditional on a restricted information set"; + break; } cout << ": added " << neweqs.size() << " auxiliary variables and equations." << endl; } @@ -2765,7 +2768,7 @@ DynamicModel::substituteExpectation(bool partial_information_model) // 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) + if (subst_table.size() > 0) { if (partial_information_model) cout << "Substitution of Expectation operator: added " << subst_table.size() << " auxiliary variables and " << neweqs.size() << " auxiliary equations." << endl; diff --git a/preprocessor/DynareBison.yy b/preprocessor/DynareBison.yy index e5254ae90..c8097a79a 100644 --- a/preprocessor/DynareBison.yy +++ b/preprocessor/DynareBison.yy @@ -117,7 +117,7 @@ class ParsingDriver; %token PARAMETERS PARAMETER_SET PARTIAL_INFORMATION PERIODS PLANNER_OBJECTIVE PLOT_CONDITIONAL_FORECAST PLOT_PRIORS PREFILTER PRESAMPLE %token PRINT PRIOR_MC PRIOR_TRUNC PRIOR_ANALYSIS PRIOR_MODE PRIOR_MEAN POSTERIOR_ANALYSIS POSTERIOR_MODE POSTERIOR_MEAN POSTERIOR_MEDIAN %token QUOTED_STRING -%token QZ_CRITERIUM +%token QZ_CRITERIUM FULL %token RELATIVE_IRF REPLIC RPLOT SAVE_PARAMS_AND_STEADY_STATE %token SHOCKS SHOCK_DECOMPOSITION SIGMA_E SIMUL SIMUL_ALGO SIMUL_SEED SMOOTHER STACK_SOLVE_ALGO SOLVE_ALGO %token STDERR STEADY STOCH_SIMUL @@ -162,7 +162,7 @@ class ParsingDriver; %type expression expression_or_empty %type equation hand_side model_var %type signed_float signed_integer prior -%type filename symbol +%type filename symbol expectation_input %type value value1 %type vec_value_1 vec_value %type calib_arg2 range number @@ -530,7 +530,7 @@ hand_side : '(' hand_side ')' { $$ = driver.add_different($1, $3); } | hand_side POWER hand_side { $$ = driver.add_power($1, $3); } - | EXPECTATION '(' signed_integer ')''(' hand_side ')' + | EXPECTATION '(' expectation_input ')''(' hand_side ')' { $$ = driver.add_expectation($3, $6); } | MINUS hand_side %prec UMINUS { $$ = driver.add_uminus($2); } @@ -570,6 +570,11 @@ hand_side : '(' hand_side ')' { $$ = driver.add_steady_state($3); } ; +expectation_input : signed_integer + | VAROBS { string *varobs = new string("varobs"); $$ = varobs; } + | FULL { string *full = new string("full"); $$ = full; } + ; + pound_expression: '#' symbol EQUAL hand_side ';' { driver.declare_and_init_model_local_variable($2, $4); }; diff --git a/preprocessor/DynareFlex.ll b/preprocessor/DynareFlex.ll index 113a73e7f..aca60f356 100644 --- a/preprocessor/DynareFlex.ll +++ b/preprocessor/DynareFlex.ll @@ -463,6 +463,8 @@ int sigma_e = 0; normcdf {return token::NORMCDF;} steady_state {return token::STEADY_STATE;} expectation {return token::EXPECTATION;} +varobs {return token::VAROBS;} +full {return token::FULL;} nan {return token::NAN_CONSTANT;} inf {return token::INF_CONSTANT;} diff --git a/preprocessor/ExprNode.cc b/preprocessor/ExprNode.cc index d9183d711..ea9a3f589 100644 --- a/preprocessor/ExprNode.cc +++ b/preprocessor/ExprNode.cc @@ -976,10 +976,11 @@ VariableNode::substituteExpectation(subst_table_t &subst_table, vector(this); } -UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg, const int expectation_information_set_arg) : +UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg, const int expectation_information_set_arg, const string &expectation_information_set_name_arg) : ExprNode(datatree_arg), arg(arg_arg), expectation_information_set(expectation_information_set_arg), + expectation_information_set_name(expectation_information_set_name_arg), op_code(op_code_arg) { // Add myself to the unary op map @@ -1697,35 +1698,59 @@ UnaryOpNode::substituteExpectation(subst_table_t &subst_table, vector(this)); - if (it != subst_table.end()) return const_cast(it->second); //Arriving here, we need to create an auxiliary variable for this Expectation Operator: - int symb_id = datatree.symbol_table.addExpectationAuxiliaryVar(expectation_information_set, arg->idx); //AUXE_period_arg.idx + //AUX_EXPECT_(LEAD/LAG)_(period)_(arg.idx) OR + //AUX_EXPECT_(info_set_name)_(arg.idx) + int symb_id = datatree.symbol_table.addExpectationAuxiliaryVar(expectation_information_set, arg->idx, expectation_information_set_name); NodeID newAuxE = datatree.AddVariable(symb_id, 0); if (partial_information_model && expectation_information_set == 0) { - //Ensure x is a single variable as opposed to an expression if (dynamic_cast(arg) == NULL) { - cerr << "ERROR: In Partial Information models, EXPECTATION(0)(X) can only be used when X is a single variable." << endl; + cerr << "ERROR: In Partial Information models, EXPECTATION("; + if (expectation_information_set_name.empty()) + cerr << 0; + else + cerr << expectation_information_set_name; + cerr << ")(X) can only be used when X is a single variable." << endl; exit(EXIT_FAILURE); } } + + if (!expectation_information_set_name.empty()) + { + if (!partial_information_model) + { + cerr << "ERROR: EXPECTATION(" << expectation_information_set_name << ")(X) is only valid in models with partial information." << endl; + exit(EXIT_FAILURE); + } + + if (expectation_information_set != 0) + { + cerr << "ERROR: UnaryOpNode::substituteExpectation() should not arrive here. Please inform Dynare Team." << endl; + exit(EXIT_FAILURE); + } + else if (dynamic_cast(arg)->get_lag()!=0) + { + cerr << "ERROR: EXPECTATION(" << expectation_information_set_name << ")(X) requres that X be from the current period." << endl; + exit(EXIT_FAILURE); + } + //Will not have nested Expectation operators of this type since we require that X be a single endogenous variable. + //Hence, the newAuxE with lag = 0 is all we need here. + } else { //take care of any nested expectation operators by calling arg->substituteExpectation(.), then decreaseLeadsLags for this oExpectation operator //arg(lag-period) (holds entire subtree of arg(lag-period) NodeID substexpr = (arg->substituteExpectation(subst_table, neweqs, partial_information_model))->decreaseLeadsLags(expectation_information_set); assert(substexpr != NULL); - neweqs.push_back(dynamic_cast(datatree.AddEqual(newAuxE, substexpr))); //AUXE_period_arg.idx = arg(lag-period) - newAuxE = datatree.AddVariable(symb_id, expectation_information_set); } - assert(dynamic_cast(newAuxE) != NULL); subst_table[this] = dynamic_cast(newAuxE); return newAuxE; diff --git a/preprocessor/ExprNode.hh b/preprocessor/ExprNode.hh index 4781dde95..f305c6111 100644 --- a/preprocessor/ExprNode.hh +++ b/preprocessor/ExprNode.hh @@ -387,6 +387,7 @@ public: { return symb_id; }; + int get_lag() const { return lag; }; virtual pair normalizeEquation(int symb_id_endo, vector > > &List_of_Op_RHS) const; virtual NodeID getChainRuleDerivative(int deriv_id, const map &recursive_variables); virtual int maxEndoLead() const; @@ -407,13 +408,15 @@ private: const NodeID arg; //! Stores the information set. Only used for expectation operator const int expectation_information_set; + //! Stores the information set name. Only used for expectation operator + const string expectation_information_set_name; const UnaryOpcode op_code; virtual NodeID computeDerivative(int deriv_id); virtual int cost(const temporary_terms_type &temporary_terms, bool is_matlab) const; //! Returns the derivative of this node if darg is the derivative of the argument NodeID composeDerivatives(NodeID darg); public: - UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg, const int expectation_information_set_arg); + UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg, const int expectation_information_set_arg, const string &expectation_information_set_name_arg); virtual void prepareForDerivation(); virtual void computeTemporaryTerms(map &reference_count, temporary_terms_type &temporary_terms, bool is_matlab) const; virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const; diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc index dfdd62f26..d14aea299 100644 --- a/preprocessor/ParsingDriver.cc +++ b/preprocessor/ParsingDriver.cc @@ -1465,7 +1465,18 @@ ParsingDriver::add_power(NodeID arg1, NodeID arg2) NodeID ParsingDriver::add_expectation(string *arg1, NodeID arg2) { - NodeID expectationNode = data_tree->AddExpectation(atoi(arg1->c_str()), arg2); + NodeID expectationNode; + if ("varobs"==*arg1 || "full"==*arg1) + if (dynamic_cast(arg2) == NULL) + error("EXPECTATION(" + *arg1 + ")(X) can only be used when X is a single variable."); + else + if (mod_file->symbol_table.getType(dynamic_cast(arg2)->get_symb_id()) != eEndogenous) + error(mod_file->symbol_table.getName(dynamic_cast(arg2)->get_symb_id()) + " is not endogenous."); + else + expectationNode = data_tree->AddExpectation(arg1, arg2); + else + expectationNode = data_tree->AddExpectation(atoi(arg1->c_str()), arg2); + delete arg1; return expectationNode; } diff --git a/preprocessor/SymbolTable.cc b/preprocessor/SymbolTable.cc index 74ae98165..8a9d850ce 100644 --- a/preprocessor/SymbolTable.cc +++ b/preprocessor/SymbolTable.cc @@ -24,6 +24,15 @@ #include "SymbolTable.hh" +AuxVarInfo::AuxVarInfo(int symb_id_arg, aux_var_t type_arg, int orig_symb_id_arg, int orig_lead_lag_arg, string expectation_information_set_name_arg) : + symb_id(symb_id_arg), + type(type_arg), + orig_symb_id(orig_symb_id_arg), + orig_lead_lag(orig_lead_lag_arg), + expectation_information_set_name(expectation_information_set_name_arg) +{ +} + SymbolTable::SymbolTable() : frozen(false), size(0) { } @@ -209,18 +218,21 @@ SymbolTable::writeOutput(ostream &output) const throw (NotYetFrozenException) else for (int i = 0; i < (int) aux_vars.size(); i++) { - output << "M_.aux_vars(" << i+1 << ").endo_index = " << getTypeSpecificID(aux_vars[i].symb_id)+1 << ";" << endl - << "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].type << ";" << endl; - switch (aux_vars[i].type) + output << "M_.aux_vars(" << i+1 << ").endo_index = " << getTypeSpecificID(aux_vars[i].get_symb_id())+1 << ";" << endl + << "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].get_type() << ";" << endl; + switch (aux_vars[i].get_type()) { case avEndoLead: case avExoLead: case avExpectation: break; + case avExpectationRIS: + output << "M_.aux_vars(" << i+1 << ").expectation_information_set_name = '" << aux_vars[i].get_expectation_information_set_name() << "';" << endl; + break; case avEndoLag: case avExoLag: - output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].orig_symb_id)+1 << ";" << endl - << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].orig_lead_lag << ";" << endl; + output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl + << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl; break; } } @@ -255,10 +267,7 @@ SymbolTable::addLeadAuxiliaryVarInternal(bool endo, int index) throw (FrozenExce exit(EXIT_FAILURE); } - AuxVarInfo avi; - avi.symb_id = symb_id; - avi.type = (endo ? avEndoLead : avExoLead); - aux_vars.push_back(avi); + aux_vars.push_back(AuxVarInfo(symb_id, (endo ? avEndoLead : avExoLead), 0, 0, "")); return symb_id; } @@ -284,12 +293,7 @@ SymbolTable::addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_le exit(EXIT_FAILURE); } - AuxVarInfo avi; - avi.symb_id = symb_id; - avi.type = (endo ? avEndoLag : avExoLag); - avi.orig_symb_id = orig_symb_id; - avi.orig_lead_lag = orig_lead_lag; - aux_vars.push_back(avi); + aux_vars.push_back(AuxVarInfo(symb_id, (endo ? avEndoLag : avExoLag), orig_symb_id, orig_lead_lag, "")); return symb_id; } @@ -319,12 +323,17 @@ SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag) throw (F } int -SymbolTable::addExpectationAuxiliaryVar(int information_set, int index) throw (FrozenException) +SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, const string &information_set_name) throw (FrozenException) { ostringstream varname; - varname << "AUX_EXPECT_" << (information_set < 0 ? "LAG" : "LEAD") << "_" - << abs(information_set) << "_" << index; int symb_id; + + if (information_set_name.empty()) + varname << "AUX_EXPECT_" << (information_set < 0 ? "LAG" : "LEAD") << "_" + << abs(information_set) << "_" << index; + else + varname << "AUX_EXPECT_" << information_set_name << "_" << index; + try { symb_id = addSymbol(varname.str(), eEndogenous); @@ -335,10 +344,7 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index) throw (F exit(EXIT_FAILURE); } - AuxVarInfo avi; - avi.symb_id = symb_id; - avi.type = avExpectation; - aux_vars.push_back(avi); + aux_vars.push_back(AuxVarInfo(symb_id, (information_set_name.empty() ? avExpectation : avExpectationRIS), 0, 0, information_set_name)); return symb_id; } diff --git a/preprocessor/SymbolTable.hh b/preprocessor/SymbolTable.hh index 7346e679b..1fd4ceac3 100644 --- a/preprocessor/SymbolTable.hh +++ b/preprocessor/SymbolTable.hh @@ -33,20 +33,30 @@ using namespace std; //! Types of auxiliary variables enum aux_var_t { - 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 - avExpectation = 4 //!< Substitute for Expectation Operator + 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 + avExpectation = 4, //!< Substitute for Expectation Operator + avExpectationRIS = 5 //!< Substitute for Expectation Operator Conditional on Restricted Information Set }; //! Information on some auxiliary variables -struct AuxVarInfo +class AuxVarInfo { +private: 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. Not used for avEndoLead int orig_lead_lag; //!< Lead/lag of the endo of the original model represented by this aux var. Not used for avEndoLead + string expectation_information_set_name; //!< Stores 'full' or 'varobs' for avExpectationRIS. Not used otherwise. +public: + AuxVarInfo(int symb_id_arg, aux_var_t type_arg, int orig_symb_id, int orig_lead_lag, string expectation_information_set_name_arg); + int get_symb_id() const { return symb_id; }; + aux_var_t get_type() const { return type; }; + int get_orig_symb_id() const { return orig_symb_id; }; + int get_orig_lead_lag() const { return orig_lead_lag; }; + string get_expectation_information_set_name() const { return expectation_information_set_name; }; }; //! Stores the symbol table @@ -190,7 +200,7 @@ public: \param[in] index Used to construct the variable name \return the symbol ID of the new symbol */ - int addExpectationAuxiliaryVar(int information_set, int index) throw (FrozenException); + int addExpectationAuxiliaryVar(int information_set, int index, const string &information_set_name) throw (FrozenException); //! Tests if symbol already exists inline bool exists(const string &name) const; //! Get symbol name (by ID)