diff --git a/DynareBison.yy b/DynareBison.yy index 5a54e1c094a9fa726bfe4c52a135c3dea057bac1..8a3b3a18890b938fdece481dbb31b35185926c9b 100644 --- a/DynareBison.yy +++ b/DynareBison.yy @@ -119,7 +119,7 @@ class ParsingDriver; %token <string_val> QUOTED_STRING %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 SHOCKS SHOCK_DECOMPOSITION SIGMA_E SIMUL SIMUL_ALGO SIMUL_SEED SMOOTHER STACK_SOLVE_ALGO STEADY_STATE_MODEL SOLVE_ALGO %token STDERR STEADY STOCH_SIMUL %token TEX RAMSEY_POLICY PLANNER_DISCOUNT %token <string_val> TEX_NAME @@ -240,6 +240,7 @@ statement : parameters | markov_switching | svar | external_function + | steady_state_model ; dsample : DSAMPLE INT_NUMBER ';' @@ -1649,6 +1650,18 @@ conditional_forecast_paths_shock_elem : VAR symbol ';' PERIODS period_list ';' V { driver.add_det_shock($2, true); } ; +steady_state_model : STEADY_STATE_MODEL ';' { driver.begin_steady_state_model(); } + steady_state_equation_list END { driver.reset_data_tree(); } + ; + +steady_state_equation_list : steady_state_equation_list steady_state_equation + | steady_state_equation + ; + +steady_state_equation : symbol EQUAL expression ';' + { driver.add_steady_state_model_equal($1, $3); } + ; + o_dr_algo : DR_ALGO EQUAL INT_NUMBER { if (*$3 == string("0")) driver.warning("dr_algo option is now deprecated, and may be removed in a future version of Dynare"); diff --git a/DynareFlex.ll b/DynareFlex.ll index 1dec133cd6324a412dd11993509e0286c8b8682c..5fd8c51813d011cb6b3115435e059b511d8637d0 100644 --- a/DynareFlex.ll +++ b/DynareFlex.ll @@ -154,6 +154,7 @@ int sigma_e = 0; /* Begin of a Dynare block */ <INITIAL>model {BEGIN DYNARE_BLOCK; return token::MODEL;} +<INITIAL>steady_state_model {BEGIN DYNARE_BLOCK; return token::STEADY_STATE_MODEL;} <INITIAL>initval {BEGIN DYNARE_BLOCK; return token::INITVAL;} <INITIAL>endval {BEGIN DYNARE_BLOCK; return token::ENDVAL;} <INITIAL>histval {BEGIN DYNARE_BLOCK; return token::HISTVAL;} diff --git a/ExprNode.cc b/ExprNode.cc index 0d381ac5d2b1ff6fcd73c731dc4a4d0915fb531d..6588557a77da04d447b846c9eb185a584d3f0617 100644 --- a/ExprNode.cc +++ b/ExprNode.cc @@ -523,14 +523,13 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, switch (type) { case eParameter: - if (output_type == oMatlabOutsideModel) + if (output_type == oMatlabOutsideModel || output_type == oSteadyStateFile) output << "M_.params" << "(" << tsid + 1 << ")"; else output << "params" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + ARRAY_SUBSCRIPT_OFFSET(output_type) << RIGHT_ARRAY_SUBSCRIPT(output_type); break; case eModelLocalVariable: - case eModFileLocalVariable: if (output_type == oMatlabDynamicModelSparse || output_type == oMatlabStaticModelSparse || output_type == oMatlabDynamicModelSparseLocalTemporaryTerms) { output << "("; @@ -541,6 +540,10 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, output << datatree.symbol_table.getName(symb_id); break; + case eModFileLocalVariable: + output << datatree.symbol_table.getName(symb_id); + break; + case eEndogenous: switch (output_type) { @@ -570,6 +573,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, case oMatlabDynamicSteadyStateOperator: output << "oo_.steady_state(" << tsid + 1 << ")"; break; + case oSteadyStateFile: + output << "ys_(" << tsid + 1 << ")"; + break; default: assert(false); } @@ -608,6 +614,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, case oMatlabDynamicSteadyStateOperator: output << "oo_.exo_steady_state(" << i << ")"; break; + case oSteadyStateFile: + output << "exo_(" << i << ")"; + break; default: assert(false); } @@ -646,6 +655,9 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type, case oMatlabDynamicSteadyStateOperator: output << "oo_.exo_det_steady_state(" << tsid + 1 << ")"; break; + case oSteadyStateFile: + output << "exo_(" << i << ")"; + break; default: assert(false); } diff --git a/ExprNode.hh b/ExprNode.hh index 52a6b04bc5ad9c4063488c0143c33c13489c40c8..ecc4cbf9c64e6f8168859d0abf5900ee407e0317 100644 --- a/ExprNode.hh +++ b/ExprNode.hh @@ -71,7 +71,8 @@ enum ExprNodeOutputType oLatexDynamicSteadyStateOperator, //!< LaTeX code, dynamic model steady state declarations oMatlabDynamicSteadyStateOperator, //!< Matlab code, dynamic model steady state declarations oMatlabDynamicModelSparseSteadyStateOperator, //!< Matlab code, dynamic block decomposed model steady state declarations - oMatlabDynamicModelSparseLocalTemporaryTerms //!< Matlab code, dynamic block decomposed model local temporary_terms + oMatlabDynamicModelSparseLocalTemporaryTerms, //!< Matlab code, dynamic block decomposed model local temporary_terms + oSteadyStateFile //!< Matlab code, in the generated steady state file }; #define IS_MATLAB(output_type) ((output_type) == oMatlabStaticModel \ @@ -81,7 +82,8 @@ enum ExprNodeOutputType || (output_type) == oMatlabDynamicModelSparse \ || (output_type) == oMatlabDynamicModelSparseLocalTemporaryTerms \ || (output_type) == oMatlabDynamicSteadyStateOperator \ - || (output_type) == oMatlabDynamicModelSparseSteadyStateOperator) + || (output_type) == oMatlabDynamicModelSparseSteadyStateOperator \ + || (output_type) == oSteadyStateFile) #define IS_C(output_type) ((output_type) == oCDynamicModel) diff --git a/Makefile.am b/Makefile.am index a9d6da685268612c15f5a9b4d278324503aa767d..8c80d0d806fdf5de167276819cc41f6276f49961 100644 --- a/Makefile.am +++ b/Makefile.am @@ -47,7 +47,9 @@ dynare_m_SOURCES = \ CodeInterpreter.hh \ FlexLexer.h \ ExternalFunctionsTable.cc \ - ExternalFunctionsTable.hh + ExternalFunctionsTable.hh \ + SteadyStateModel.hh \ + SteadyStateModel.cc # The -I. is for <FlexLexer.h> dynare_m_CPPFLAGS = $(BOOST_CPPFLAGS) -I. diff --git a/ModFile.cc b/ModFile.cc index c664940419caf1381294b88d5198020e39572aa9..bc754f00f0c3e71379f405c3e45eabf9c5507eb3 100644 --- a/ModFile.cc +++ b/ModFile.cc @@ -24,8 +24,9 @@ #include "ModFile.hh" ModFile::ModFile() : expressions_tree(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), dynamic_model(symbol_table, num_constants, external_functions_table), + static_model(symbol_table, num_constants, external_functions_table), linear(false), block(false), byte_code(false), use_dll(false), no_static(false) { @@ -439,5 +440,8 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all } } + // Create steady state file + steady_state_model.writeSteadyStateFile(basename); + cout << "done" << endl; } diff --git a/ModFile.hh b/ModFile.hh index 01d3d368ce671ec43a9e3932d0c5fb5f6da3abe0..57612a3e79d537e5fee9710a282841b73a0cecc5 100644 --- a/ModFile.hh +++ b/ModFile.hh @@ -30,6 +30,7 @@ using namespace std; #include "NumericalInitialization.hh" #include "StaticModel.hh" #include "DynamicModel.hh" +#include "SteadyStateModel.hh" #include "Statement.hh" #include "ExternalFunctionsTable.hh" @@ -47,10 +48,12 @@ public: NumericalConstants num_constants; //! Expressions outside model block DataTree expressions_tree; - //! Static Dll model - StaticModel static_model; - //! Dynamic model + //! Static model, as declared in the "steady_state_model" block if present + SteadyStateModel steady_state_model; + //! Dynamic model, as declared in the "model" block DynamicModel dynamic_model; + //! Static model, as derived from the "model" block when leads and lags have been removed + StaticModel static_model; //! Option linear bool linear; diff --git a/ParsingDriver.cc b/ParsingDriver.cc index 4be917cbbb90a8f13d950b16ba193333ae2c1e4e..1e6d0796dd1f28ea211af900526dfb65d9cde048 100644 --- a/ParsingDriver.cc +++ b/ParsingDriver.cc @@ -1391,17 +1391,27 @@ ParsingDriver::add_model_equal_with_zero_rhs(NodeID arg) void ParsingDriver::declare_and_init_model_local_variable(string *name, NodeID rhs) { + int symb_id; try { - mod_file->symbol_table.addSymbol(*name, eModelLocalVariable); + symb_id = mod_file->symbol_table.addSymbol(*name, eModelLocalVariable); } catch (SymbolTable::AlreadyDeclaredException &e) { - error("Local model variable " + *name + " declared twice."); + // It can have already been declared in a steady_state_model block, check that it is indeed a ModelLocalVariable + symb_id = mod_file->symbol_table.getID(*name); + if (mod_file->symbol_table.getType(symb_id) != eModelLocalVariable) + error(*name + " has wrong type, you cannot use it within as left-hand side of a pound ('#') expression"); } - int symb_id = mod_file->symbol_table.getID(*name); - model_tree->AddLocalVariable(symb_id, rhs); + try + { + model_tree->AddLocalVariable(symb_id, rhs); + } + catch (DataTree::LocalVariableException &e) + { + error("Local model variable " + *name + " declared twice."); + } delete name; } @@ -1834,3 +1844,43 @@ ParsingDriver::add_native(const char *s) { mod_file->addStatement(new NativeStatement(s)); } + +void +ParsingDriver::begin_steady_state_model() +{ + set_current_data_tree(&mod_file->steady_state_model); +} + +void +ParsingDriver::add_steady_state_model_equal(string *varname, NodeID expr) +{ + int id; + try + { + id = mod_file->symbol_table.getID(*varname); + } + catch (SymbolTable::UnknownSymbolNameException &e) + { + // Unknown symbol, declare it as a ModFileLocalVariable + id = mod_file->symbol_table.addSymbol(*varname, eModFileLocalVariable); + } + + SymbolType type = mod_file->symbol_table.getType(id); + if (type != eEndogenous && type != eModFileLocalVariable) + error(*varname + " has incorrect type"); + + try + { + mod_file->steady_state_model.addDefinition(id, expr); + } + catch(SteadyStateModel::AlreadyDefinedException &e) + { + error(*varname + " has already been defined in the steady state block"); + } + catch(SteadyStateModel::UndefinedVariableException &e) + { + error(e.varname + " is not yet initialized at this point"); + } + + delete varname; +} diff --git a/ParsingDriver.hh b/ParsingDriver.hh index ea91235f87cce737087a1c9d627f0933a2b6e218..43cace79084241ac63bfaa53bb844ff4632a5318 100644 --- a/ParsingDriver.hh +++ b/ParsingDriver.hh @@ -493,6 +493,10 @@ public: void add_native(const char *s); //! Resets data_tree and model_tree pointers to default (i.e. mod_file->expressions_tree) void reset_data_tree(); + //! Begin a steady_state_model block + void begin_steady_state_model(); + //! Add an assignment equation in steady_state_model block + void add_steady_state_model_equal(string *varname, NodeID expr); }; #endif // ! PARSING_DRIVER_HH diff --git a/StaticModel.hh b/StaticModel.hh index d4353b3e7fa0c6dc340cc8baf6b2820feb71e2af..b806bd76e399b1403656b9196a6bab0eecc15fef 100644 --- a/StaticModel.hh +++ b/StaticModel.hh @@ -26,7 +26,7 @@ using namespace std; #include "ModelTree.hh" -//! Stores a static model +//! Stores a static model, as derived from the "model" block when leads and lags have been removed class StaticModel : public ModelTree { private: diff --git a/SteadyStateModel.cc b/SteadyStateModel.cc new file mode 100644 index 0000000000000000000000000000000000000000..b71c94e08032665866a5837ad61cea3e2a4a837c --- /dev/null +++ b/SteadyStateModel.cc @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2010 Dynare Team + * + * This file is part of Dynare. + * + * Dynare is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dynare is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Dynare. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <cassert> +#include <algorithm> + +#include "SteadyStateModel.hh" + +SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table_arg) : + DataTree(symbol_table_arg, num_constants, external_functions_table) +{ +} + +void +SteadyStateModel::addDefinition(int symb_id, NodeID expr) throw (UndefinedVariableException, AlreadyDefinedException) +{ + assert(symbol_table.getType(symb_id) == eEndogenous + || symbol_table.getType(symb_id) == eModFileLocalVariable); + + // Check that symbol is not already defined + if (find(recursive_order.begin(), recursive_order.end(), symb_id) + != recursive_order.end()) + throw AlreadyDefinedException(symbol_table.getName(symb_id)); + + // Check that expression has no undefined symbol + set<pair<int, int> > used_symbols; + expr->collectVariables(eEndogenous, used_symbols); + expr->collectVariables(eModFileLocalVariable, used_symbols); + for(set<pair<int, int> >::const_iterator it = used_symbols.begin(); + it != used_symbols.end(); it++) + if (find(recursive_order.begin(), recursive_order.end(), it->first) + == recursive_order.end()) + throw UndefinedVariableException(symbol_table.getName(it->first)); + + // Add the variable + recursive_order.push_back(symb_id); + def_table[symb_id] = AddEqual(AddVariable(symb_id), expr); +} + +void +SteadyStateModel::writeSteadyStateFile(const string &basename) const +{ + if (recursive_order.size() == 0) + return; + + string filename = basename + "_steadystate.m"; + + ofstream output; + output.open(filename.c_str(), ios::out | ios::binary); + if (!output.is_open()) + { + cerr << "ERROR: Can't open file " << filename << " for writing" << endl; + exit(EXIT_FAILURE); + } + + output << "function [ys_, check_] = " << basename << "_steadystate(ys_orig_, exo_)" << endl + << "% Steady state generated by Dynare preprocessor" << endl + << " global M_" << endl + << " ys_=zeros(" << symbol_table.orig_endo_nbr() << ",1);" << endl; + + for(size_t i = 0; i < recursive_order.size(); i++) + { + output << " "; + map<int, NodeID>::const_iterator it = def_table.find(recursive_order[i]); + it->second->writeOutput(output, oSteadyStateFile); + output << ";" << endl; + } + output << " check_=0;" << endl + << "end" << endl; +} + diff --git a/SteadyStateModel.hh b/SteadyStateModel.hh new file mode 100644 index 0000000000000000000000000000000000000000..9c609cf51c4e8c6c54d83ceadda4b64e50d7a3af --- /dev/null +++ b/SteadyStateModel.hh @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2010 Dynare Team + * + * This file is part of Dynare. + * + * Dynare is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Dynare is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Dynare. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef _STEADY_STATE_MODEL_HH +#define _STEADY_STATE_MODEL_HH + +#include "DataTree.hh" + +class SteadyStateModel : public DataTree +{ +private: + //! Associates a symbol ID to an expression of the form "var = expr" + map<int, NodeID> def_table; + vector<int> recursive_order; + +public: + class AlreadyDefinedException + { + public: + const string &varname; + AlreadyDefinedException(const string &varname_arg) : varname(varname_arg) {} + }; + class UndefinedVariableException + { + public: + const string &varname; + UndefinedVariableException(const string &varname_arg) : varname(varname_arg) {} + }; + + SteadyStateModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants, ExternalFunctionsTable &external_functions_table_arg); + //! Add an expression of the form "var = expr;" + void addDefinition(int symb_id, NodeID expr) throw (UndefinedVariableException, AlreadyDefinedException); + //! Write the steady state file + void writeSteadyStateFile(const string &basename) const; +}; + +#endif