diff --git a/preprocessor/DataTree.cc b/preprocessor/DataTree.cc index 24621f334..e6ae3fcde 100644 --- a/preprocessor/DataTree.cc +++ b/preprocessor/DataTree.cc @@ -596,3 +596,14 @@ DataTree::isSecondDerivExternalFunctionUsed(int symb_id) const return false; } + +int +DataTree::minLagForSymbol(int symb_id) const +{ + int r = 0; + for (variable_node_map_t::const_iterator it = variable_node_map.begin(); + it != variable_node_map.end(); ++it) + if (it->first.first == symb_id && it->first.second < r) + r = it->first.second; + return r; +} diff --git a/preprocessor/DataTree.hh b/preprocessor/DataTree.hh index 648c62c7d..814284a54 100644 --- a/preprocessor/DataTree.hh +++ b/preprocessor/DataTree.hh @@ -208,6 +208,9 @@ public: bool isFirstDerivExternalFunctionUsed(int symb_id) const; //! Checks if a given second derivative external function is used somewhere in the data tree bool isSecondDerivExternalFunctionUsed(int symb_id) const; + //! Returns the minimum lag (as a negative number) of the given symbol in the whole data tree (and not only in the equations !!) + /*! Returns 0 if the symbol is not used */ + int minLagForSymbol(int symb_id) const; //! Thrown when trying to access an unknown variable by deriv_id class UnknownDerivIDException { diff --git a/preprocessor/NumericalInitialization.cc b/preprocessor/NumericalInitialization.cc index ceccb9733..e15f2724c 100644 --- a/preprocessor/NumericalInitialization.cc +++ b/preprocessor/NumericalInitialization.cc @@ -193,21 +193,27 @@ HistValStatement::writeOutput(ostream &output, const string &basename) const const expr_t expression = it->second; SymbolType type = symbol_table.getType(symb_id); - if (type == eEndogenous && lag < 0) - { - const int new_symb_id = symbol_table.searchAuxiliaryVars(symb_id,lag); - if (new_symb_id != -1) - { - symb_id = new_symb_id; - lag = 0; - } - else if (symbol_table.AuxVarsSize() > 0) - { - cerr << "Histval: this variable doesn't exist with such a lag in the model" << endl; - exit(EXIT_FAILURE); - } - - } + + // For a lag greater than 1, lookup for auxiliary variable + if ((type == eEndogenous || type == eExogenous) && lag < 0) + { + try + { + symb_id = symbol_table.searchAuxiliaryVars(symb_id, lag); + lag = 0; + } + catch (SymbolTable::SearchFailedException &e) + { + if (type == eEndogenous) + { + cerr << "HISTVAL: internal error of Dynare, please contact the developers"; + exit(EXIT_FAILURE); + } + // We don't fail for exogenous, because they are not replaced by + // auxiliary variables in deterministic mode. + } + } + int tsid = symbol_table.getTypeSpecificID(symb_id) + 1; if (type == eEndogenous) diff --git a/preprocessor/ParsingDriver.cc b/preprocessor/ParsingDriver.cc index f0652bebb..a719334af 100644 --- a/preprocessor/ParsingDriver.cc +++ b/preprocessor/ParsingDriver.cc @@ -21,6 +21,7 @@ #include #include #include +#include #include "ParsingDriver.hh" #include "Statement.hh" @@ -392,11 +393,18 @@ ParsingDriver::hist_val(string *name, string *lag, expr_t rhs) if (type != eEndogenous && type != eExogenous && type != eExogenousDet) - error("hist_val: " + *name + " should be an endogenous or exogenous variable"); + error("histval: " + *name + " should be an endogenous or exogenous variable"); int ilag = atoi(lag->c_str()); pair key(symb_id, ilag); + if (mod_file->dynamic_model.minLagForSymbol(symb_id) > ilag - 1) + { + ostringstream s; + s << ilag-1; + error("histval: variable " + *name + " does not appear in the model with the lag " + s.str() + " (see the reference manual for the timing convention in 'histval')"); + } + if (hist_values.find(key) != hist_values.end()) error("hist_val: (" + *name + ", " + *lag + ") declared twice"); diff --git a/preprocessor/SymbolTable.cc b/preprocessor/SymbolTable.cc index 7043de839..aba5c399c 100644 --- a/preprocessor/SymbolTable.cc +++ b/preprocessor/SymbolTable.cc @@ -368,13 +368,13 @@ SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, const st } int -SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const +SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const throw (SearchFailedException) { - for (int i=0; i < aux_vars.size();++i) + for (size_t i = 0; i < aux_vars.size(); i++) if ((aux_vars[i].get_type() == avEndoLag || aux_vars[i].get_type() == avExoLag) && aux_vars[i].get_orig_symb_id() == orig_symb_id && aux_vars[i].get_orig_lead_lag() == orig_lead_lag) return aux_vars[i].get_symb_id(); - return -1; + throw SearchFailedException(orig_symb_id, orig_lead_lag); } void diff --git a/preprocessor/SymbolTable.hh b/preprocessor/SymbolTable.hh index ad0579cdd..0925c5eab 100644 --- a/preprocessor/SymbolTable.hh +++ b/preprocessor/SymbolTable.hh @@ -47,8 +47,8 @@ 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 + int orig_symb_id; //!< Symbol ID of the endo of the original model represented by this aux var. Only used for avEndoLag and avExoLag. + int orig_lead_lag; //!< Lead/lag of the endo of the original model represented by this aux var. Only used for avEndoLag and avExoLag. 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); @@ -161,6 +161,16 @@ public: class NotYetFrozenException { }; + //! Thrown when searchAuxiliaryVars() failed + class SearchFailedException + { + public: + int orig_symb_id, orig_lead_lag; + SearchFailedException(int orig_symb_id_arg, int orig_lead_lag_arg) : orig_symb_id(orig_symb_id_arg), + orig_lead_lag(orig_lead_lag_arg) + { + } + }; private: //! Factorized code for adding aux lag variables @@ -204,11 +214,13 @@ public: \return the symbol ID of the new symbol */ int addExpectationAuxiliaryVar(int information_set, int index, const string &information_set_name) throw (FrozenException); - //! Searches auxiliary variables by symbol_id and lead_lag + //! Searches auxiliary variables which are substitutes for a given symbol_id and lead/lag /*! - \return the symbol ID of the auxiliary variable and -1 if not found + The search is only performed among auxiliary variables of endo/exo lag. + \return the symbol ID of the auxiliary variable + Throws an exception if match not found. */ - int searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const; + int searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const throw (SearchFailedException); //! Returns the number of auxiliary variables int AuxVarsSize() const {return aux_vars.size();}; //! Tests if symbol already exists diff --git a/tests/Makefile.am b/tests/Makefile.am index e54f4cb52..1b7514d67 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -17,6 +17,8 @@ OCTAVE_MODS = \ predetermined_variables.mod \ fs2000_ssfile.mod \ comments.mod \ + histval_sto.mod \ + histval_det.mod \ steady_state_operator/standard.mod \ steady_state_operator/use_dll.mod \ steady_state_operator/block.mod \ diff --git a/tests/histval_det.mod b/tests/histval_det.mod new file mode 100644 index 000000000..12c5f2cc7 --- /dev/null +++ b/tests/histval_det.mod @@ -0,0 +1,38 @@ +// Tests the histval block in deterministic setup +// In particular test if it works on endos and exos substituted by an aux var + +var c k z; +varexo x; + +parameters alph gam delt bet aa; +alph=0.5; +gam=0.5; +delt=0.02; +bet=0.05; +aa=0.5; + + +model; +c + k - aa*x*k(-1)^alph - (1-delt)*k(-1); +z = 0.9*z(-2); +c^(-gam) - (1+bet)^(-1)*(aa*alph*x(-1)*k^(alph-1) + 1 - delt)*c(+1)^(-gam); +end; + +initval; +x = 1; +k = ((delt+bet)/(1.0*aa*alph))^(1/(alph-1)); +c = aa*k^alph-delt*k; +z = 0; +end; + +steady; + +check; + +histval; +k(0) = 0.6; +x(0) = 0.9; +z(-1) = 0.1; +end; + +simul(periods=200); diff --git a/tests/histval_sto.mod b/tests/histval_sto.mod new file mode 100644 index 000000000..830e47fa1 --- /dev/null +++ b/tests/histval_sto.mod @@ -0,0 +1,52 @@ +// Tests the histval block in stochastic setup +// In particular test if it works on endos and exos substituted by an aux var + +var y, c, k, a, h, b; +varexo e, u; + +parameters beta, rho, alpha, delta, theta, psi, tau; + +alpha = 0.36; +rho = 0.95; +tau = 0.025; +beta = 0.99; +delta = 0.025; +psi = 0; +theta = 2.95; + +phi = 0.1; + +model; +c*theta*h^(1+psi)=(1-alpha)*y; +k = beta*(((exp(b)*c)/(exp(b(+1))*c(+1))) + *(exp(b(+1))*alpha*y(+1)+(1-delta)*k)); +y = exp(a)*(k(-1)^alpha)*(h^(1-alpha)); +k = exp(b)*(y-c)+(1-delta)*k(-1); +a = rho*a(-1)+tau*b(-1)+0.01*b(-2) + e; +b = tau*a(-1)+rho*b(-1)+0.01*a(-2) + u(-2); +end; + +initval; +y = 1.08068253095672; +c = 0.80359242014163; +h = 0.29175631001732; +k = 11.08360443260358; +a = 0; +b = 0; +e = 0; +u = 0; +end; + +shocks; +var e; stderr 0.009; +var u; stderr 0.009; +var e, u = phi*0.009*0.009; +end; + +histval; +b(0) = 0.1; +a(-1) = 0.3; +u(-1) = 0.1; +end; + +stoch_simul(nograph);