Commit 2f1382fa authored by sebastien's avatar sebastien

preprocessor:

* In stochastic mode, now transforms the model by removing leads and lags greater or equal to 2 (creating auxiliary variables and equations in the process)
* Information about these variables is in structure M_.aux_vars
* Automatically add the necessary initialization for auxiliary vars after the initval block or load_params_and_steady_state


git-svn-id: https://www.dynare.org/svn/dynare/trunk@3002 ac1d8469-bf42-47a9-8791-bf33cf982152
parent b051e0b5
...@@ -59,23 +59,28 @@ DataTree::AddNumConstant(const string &value) ...@@ -59,23 +59,28 @@ DataTree::AddNumConstant(const string &value)
return new NumConstNode(*this, id); return new NumConstNode(*this, id);
} }
NodeID VariableNode *
DataTree::AddVariableInternal(const string &name, int lag) DataTree::AddVariableInternal(int symb_id, int lag)
{ {
int symb_id = symbol_table.getID(name);
variable_node_map_type::iterator it = variable_node_map.find(make_pair(symb_id, lag)); variable_node_map_type::iterator it = variable_node_map.find(make_pair(symb_id, lag));
if (it != variable_node_map.end()) if (it != variable_node_map.end())
return it->second; return it->second;
else else
return new VariableNode(*this, symb_id, lag, computeDerivID(symb_id, lag)); return new VariableNode(*this, symb_id, lag);
} }
NodeID VariableNode *
DataTree::AddVariable(const string &name, int lag) DataTree::AddVariable(const string &name, int lag)
{
int symb_id = symbol_table.getID(name);
return AddVariable(symb_id, lag);
}
VariableNode *
DataTree::AddVariable(int symb_id, int lag)
{ {
assert(lag == 0); assert(lag == 0);
return AddVariableInternal(name, lag); return AddVariableInternal(symb_id, lag);
} }
NodeID NodeID
...@@ -445,25 +450,6 @@ DataTree::AddUnknownFunction(const string &function_name, const vector<NodeID> & ...@@ -445,25 +450,6 @@ DataTree::AddUnknownFunction(const string &function_name, const vector<NodeID> &
return new UnknownFunctionNode(*this, id, arguments); return new UnknownFunctionNode(*this, id, arguments);
} }
void
DataTree::fillEvalContext(eval_context_type &eval_context) const
{
for(map<int, NodeID>::const_iterator it = local_variables_table.begin();
it != local_variables_table.end(); it++)
{
try
{
const NodeID expression = it->second;
double val = expression->eval(eval_context);
eval_context[it->first] = val;
}
catch(ExprNode::EvalException &e)
{
// Do nothing
}
}
}
bool bool
DataTree::isSymbolUsed(int symb_id) const DataTree::isSymbolUsed(int symb_id) const
{ {
...@@ -478,12 +464,6 @@ DataTree::isSymbolUsed(int symb_id) const ...@@ -478,12 +464,6 @@ DataTree::isSymbolUsed(int symb_id) const
return false; return false;
} }
int
DataTree::computeDerivID(int symb_id, int lag)
{
return -1;
}
int int
DataTree::getDerivID(int symb_id, int lag) const throw (UnknownDerivIDException) DataTree::getDerivID(int symb_id, int lag) const throw (UnknownDerivIDException)
{ {
......
...@@ -49,26 +49,24 @@ protected: ...@@ -49,26 +49,24 @@ protected:
//! Reference to numerical constants table //! Reference to numerical constants table
NumericalConstants &num_constants; NumericalConstants &num_constants;
typedef map<int, NodeID> num_const_node_map_type; typedef map<int, NumConstNode *> num_const_node_map_type;
num_const_node_map_type num_const_node_map; num_const_node_map_type num_const_node_map;
//! Pair (symbol_id, lag) used as key //! Pair (symbol_id, lag) used as key
typedef map<pair<int, int>, NodeID> variable_node_map_type; typedef map<pair<int, int>, VariableNode *> variable_node_map_type;
variable_node_map_type variable_node_map; variable_node_map_type variable_node_map;
typedef map<pair<NodeID, int>, NodeID> unary_op_node_map_type; typedef map<pair<NodeID, int>, UnaryOpNode *> unary_op_node_map_type;
unary_op_node_map_type unary_op_node_map; unary_op_node_map_type unary_op_node_map;
typedef map<pair<pair<NodeID, NodeID>, int>, NodeID> binary_op_node_map_type; typedef map<pair<pair<NodeID, NodeID>, int>, BinaryOpNode *> binary_op_node_map_type;
binary_op_node_map_type binary_op_node_map; binary_op_node_map_type binary_op_node_map;
typedef map<pair<pair<pair<NodeID, NodeID>,NodeID>, int>, NodeID> trinary_op_node_map_type; typedef map<pair<pair<pair<NodeID, NodeID>,NodeID>, int>, TrinaryOpNode *> trinary_op_node_map_type;
trinary_op_node_map_type trinary_op_node_map; trinary_op_node_map_type trinary_op_node_map;
//! Stores local variables value (maps symbol ID to corresponding node) //! Stores local variables value (maps symbol ID to corresponding node)
map<int, NodeID> local_variables_table; map<int, NodeID> local_variables_table;
//! Internal implementation of AddVariable(), without the check on the lag //! Internal implementation of AddVariable(), without the check on the lag
NodeID AddVariableInternal(const string &name, int lag); VariableNode *AddVariableInternal(int symb_id, int lag);
//! Computes a new deriv_id, or returns -1 if the variable is not one w.r. to which to derive
virtual int computeDerivID(int symb_id, int lag);
private: private:
typedef list<NodeID> node_list_type; typedef list<NodeID> node_list_type;
//! The list of nodes //! The list of nodes
...@@ -100,7 +98,9 @@ public: ...@@ -100,7 +98,9 @@ public:
NodeID AddNumConstant(const string &value); NodeID AddNumConstant(const string &value);
//! Adds a variable //! Adds a variable
/*! The default implementation of the method refuses any lag != 0 */ /*! The default implementation of the method refuses any lag != 0 */
virtual NodeID AddVariable(const string &name, int lag = 0); virtual VariableNode *AddVariable(int symb_id, int lag = 0);
//! Adds a variable, using its symbol name
VariableNode *AddVariable(const string &name, int lag = 0);
//! Adds "arg1+arg2" to model tree //! Adds "arg1+arg2" to model tree
NodeID AddPlus(NodeID iArg1, NodeID iArg2); NodeID AddPlus(NodeID iArg1, NodeID iArg2);
//! Adds "arg1-arg2" to model tree //! Adds "arg1-arg2" to model tree
...@@ -172,8 +172,6 @@ public: ...@@ -172,8 +172,6 @@ public:
//! Adds an unknown function node //! Adds an unknown function node
/*! \todo Use a map to share identical nodes */ /*! \todo Use a map to share identical nodes */
NodeID AddUnknownFunction(const string &function_name, const vector<NodeID> &arguments); NodeID AddUnknownFunction(const string &function_name, const vector<NodeID> &arguments);
//! Fill eval context with values of local variables
void fillEvalContext(eval_context_type &eval_context) const;
//! Checks if a given symbol is used somewhere in the data tree //! Checks if a given symbol is used somewhere in the data tree
bool isSymbolUsed(int symb_id) const; bool isSymbolUsed(int symb_id) const;
//! Thrown when trying to access an unknown variable by deriv_id //! Thrown when trying to access an unknown variable by deriv_id
......
...@@ -48,10 +48,10 @@ DynamicModel::DynamicModel(SymbolTable &symbol_table_arg, ...@@ -48,10 +48,10 @@ DynamicModel::DynamicModel(SymbolTable &symbol_table_arg,
{ {
} }
NodeID VariableNode *
DynamicModel::AddVariable(const string &name, int lag) DynamicModel::AddVariable(int symb_id, int lag)
{ {
return AddVariableInternal(name, lag); return AddVariableInternal(symb_id, lag);
} }
void void
...@@ -2292,7 +2292,10 @@ DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivative ...@@ -2292,7 +2292,10 @@ DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivative
{ {
assert(jacobianExo || !(hessian || thirdDerivatives || paramsDerivatives)); assert(jacobianExo || !(hessian || thirdDerivatives || paramsDerivatives));
// Computes dynamic jacobian columns // Prepare for derivation
computeDerivIDs();
// Computes dynamic jacobian columns, must be done after computeDerivIDs()
computeDynJacobianCols(jacobianExo); computeDynJacobianCols(jacobianExo);
// Compute derivatives w.r. to all endogenous, and possibly exogenous and exogenous deterministic // Compute derivatives w.r. to all endogenous, and possibly exogenous and exogenous deterministic
...@@ -2408,6 +2411,11 @@ DynamicModel::toStatic(StaticModel &static_model) const ...@@ -2408,6 +2411,11 @@ DynamicModel::toStatic(StaticModel &static_model) const
for (vector<BinaryOpNode *>::const_iterator it = equations.begin(); for (vector<BinaryOpNode *>::const_iterator it = equations.begin();
it != equations.end(); it++) it != equations.end(); it++)
static_model.addEquation((*it)->toStatic(static_model)); static_model.addEquation((*it)->toStatic(static_model));
// Convert auxiliary equations
for (deque<BinaryOpNode *>::const_iterator it = aux_equations.begin();
it != aux_equations.end(); it++)
static_model.addAuxEquation((*it)->toStatic(static_model));
} }
void void
...@@ -2424,60 +2432,65 @@ DynamicModel::toStaticDll(StaticDllModel &static_model) const ...@@ -2424,60 +2432,65 @@ DynamicModel::toStaticDll(StaticDllModel &static_model) const
static_model.addEquation((*it)->toStatic(static_model)); static_model.addEquation((*it)->toStatic(static_model));
} }
int void
DynamicModel::computeDerivID(int symb_id, int lag) DynamicModel::computeDerivIDs()
{ {
// Setting maximum and minimum lags set<pair<int, int> > dynvars;
if (max_lead < lag)
max_lead = lag;
else if (-max_lag > lag)
max_lag = -lag;
SymbolType type = symbol_table.getType(symb_id); for(int i = 0; i < (int) equations.size(); i++)
equations[i]->collectVariables(eEndogenous, dynvars);
switch (type) dynJacobianColsNbr = dynvars.size();
for(int i = 0; i < (int) equations.size(); i++)
{ {
case eEndogenous: equations[i]->collectVariables(eExogenous, dynvars);
if (max_endo_lead < lag) equations[i]->collectVariables(eExogenousDet, dynvars);
max_endo_lead = lag; equations[i]->collectVariables(eParameter, dynvars);
else if (-max_endo_lag > lag)
max_endo_lag = -lag;
break;
case eExogenous:
if (max_exo_lead < lag)
max_exo_lead = lag;
else if (-max_exo_lag > lag)
max_exo_lag = -lag;
break;
case eExogenousDet:
if (max_exo_det_lead < lag)
max_exo_det_lead = lag;
else if (-max_exo_det_lag > lag)
max_exo_det_lag = -lag;
break;
case eParameter:
// We wan't to compute a derivation ID for parameters
break;
default:
return -1;
} }
// Check if dynamic variable already has a deriv_id for(set<pair<int, int> >::const_iterator it = dynvars.begin();
pair<int, int> key = make_pair(symb_id, lag); it != dynvars.end(); it++)
deriv_id_table_t::const_iterator it = deriv_id_table.find(key); {
if (it != deriv_id_table.end()) int lag = it->second;
return it->second; SymbolType type = symbol_table.getType(it->first);
// Create a new deriv_id // Setting maximum and minimum lags
int deriv_id = deriv_id_table.size(); if (max_lead < lag)
max_lead = lag;
else if (-max_lag > lag)
max_lag = -lag;
deriv_id_table[key] = deriv_id; switch (type)
inv_deriv_id_table.push_back(key); {
case eEndogenous:
if (max_endo_lead < lag)
max_endo_lead = lag;
else if (-max_endo_lag > lag)
max_endo_lag = -lag;
break;
case eExogenous:
if (max_exo_lead < lag)
max_exo_lead = lag;
else if (-max_exo_lag > lag)
max_exo_lag = -lag;
break;
case eExogenousDet:
if (max_exo_det_lead < lag)
max_exo_det_lead = lag;
else if (-max_exo_det_lag > lag)
max_exo_det_lag = -lag;
break;
default:
break;
}
if (type == eEndogenous) // Create a new deriv_id
dynJacobianColsNbr++; int deriv_id = deriv_id_table.size();
return deriv_id; deriv_id_table[*it] = deriv_id;
inv_deriv_id_table.push_back(*it);
}
} }
SymbolType SymbolType
...@@ -2814,4 +2827,100 @@ DynamicModel::hessianHelper(ostream &output, int row_nb, int col_nb, ExprNodeOut ...@@ -2814,4 +2827,100 @@ DynamicModel::hessianHelper(ostream &output, int row_nb, int col_nb, ExprNodeOut
output << RIGHT_ARRAY_SUBSCRIPT(output_type); output << RIGHT_ARRAY_SUBSCRIPT(output_type);
} }
void
DynamicModel::substituteLeadGreaterThanTwo()
{
ExprNode::subst_table_t subst_table;
vector<BinaryOpNode *> neweqs;
// Substitute in model local variables
for(map<int, NodeID>::iterator it = local_variables_table.begin();
it != local_variables_table.end(); it++)
it->second = it->second->substituteLeadGreaterThanTwo(subst_table, neweqs);
// Substitute in equations
for(int i = 0; i < (int) equations.size(); i++)
{
BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->substituteLeadGreaterThanTwo(subst_table, neweqs));
assert(substeq != NULL);
equations[i] = substeq;
}
// Add new equations
for(int i = 0; i < (int) neweqs.size(); i++)
addEquation(neweqs[i]);
// 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)
cout << "Substitution of leads >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl;
}
void
DynamicModel::substituteLagGreaterThanTwo()
{
ExprNode::subst_table_t subst_table;
vector<BinaryOpNode *> neweqs;
// Substitute in model local variables
for(map<int, NodeID>::iterator it = local_variables_table.begin();
it != local_variables_table.end(); it++)
it->second = it->second->substituteLagGreaterThanTwo(subst_table, neweqs);
// Substitute in equations
for(int i = 0; i < (int) equations.size(); i++)
{
BinaryOpNode *substeq = dynamic_cast<BinaryOpNode *>(equations[i]->substituteLagGreaterThanTwo(subst_table, neweqs));
assert(substeq != NULL);
equations[i] = substeq;
}
// Add new equations
for(int i = 0; i < (int) neweqs.size(); i++)
addEquation(neweqs[i]);
// 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)
cout << "Substitution of lags >= 2: added " << neweqs.size() << " auxiliary variables and equations." << endl;
}
void
DynamicModel::fillEvalContext(eval_context_type &eval_context) const
{
// First, auxiliary variables
for(deque<BinaryOpNode *>::const_iterator it = aux_equations.begin();
it != aux_equations.end(); it++)
{
assert((*it)->get_op_code() == oEqual);
VariableNode *auxvar = dynamic_cast<VariableNode *>((*it)->get_arg1());
assert(auxvar != NULL);
try
{
double val = (*it)->get_arg2()->eval(eval_context);
eval_context[auxvar->get_symb_id()] = val;
}
catch(ExprNode::EvalException &e)
{
// Do nothing
}
}
// Second, model local variables
for(map<int, NodeID>::const_iterator it = local_variables_table.begin();
it != local_variables_table.end(); it++)
{
try
{
const NodeID expression = it->second;
double val = expression->eval(eval_context);
eval_context[it->first] = val;
}
catch(ExprNode::EvalException &e)
{
// Do nothing
}
}
}
...@@ -31,7 +31,6 @@ using namespace std; ...@@ -31,7 +31,6 @@ using namespace std;
//! Stores a dynamic model //! Stores a dynamic model
class DynamicModel : public ModelTree class DynamicModel : public ModelTree
{ {
public:
private: private:
typedef map<pair<int, int>, int> deriv_id_table_t; typedef map<pair<int, int>, int> deriv_id_table_t;
//! Maps a pair (symbol_id, lag) to a deriv ID //! Maps a pair (symbol_id, lag) to a deriv ID
...@@ -44,20 +43,20 @@ private: ...@@ -44,20 +43,20 @@ private:
map<int, int> dyn_jacobian_cols_table; map<int, int> dyn_jacobian_cols_table;
//! Maximum lag and lead over all types of variables (positive values) //! Maximum lag and lead over all types of variables (positive values)
/*! Set by computeDerivID() */ /*! Set by computeDerivIDs() */
int max_lag, max_lead; int max_lag, max_lead;
//! Maximum lag and lead over endogenous variables (positive values) //! Maximum lag and lead over endogenous variables (positive values)
/*! Set by computeDerivID() */ /*! Set by computeDerivIDs() */
int max_endo_lag, max_endo_lead; int max_endo_lag, max_endo_lead;
//! Maximum lag and lead over exogenous variables (positive values) //! Maximum lag and lead over exogenous variables (positive values)
/*! Set by computeDerivID() */ /*! Set by computeDerivIDs() */
int max_exo_lag, max_exo_lead; int max_exo_lag, max_exo_lead;
//! Maximum lag and lead over deterministic exogenous variables (positive values) //! Maximum lag and lead over deterministic exogenous variables (positive values)
/*! Set by computeDerivID() */ /*! Set by computeDerivIDs() */
int max_exo_det_lag, max_exo_det_lead; int max_exo_det_lag, max_exo_det_lead;
//! Number of columns of dynamic jacobian //! Number of columns of dynamic jacobian
/*! Set by computeDerivID() and computeDynJacobianCols() */ /*! Set by computeDerivID()s and computeDynJacobianCols() */
int dynJacobianColsNbr; int dynJacobianColsNbr;
//! Derivatives of the residuals w.r. to parameters //! Derivatives of the residuals w.r. to parameters
...@@ -113,7 +112,6 @@ private: ...@@ -113,7 +112,6 @@ private:
//! Write chain rule derivative code of an equation w.r. to a variable //! Write chain rule derivative code of an equation w.r. to a variable
void compileChainRuleDerivative(ofstream &code_file, int eq, int var, int lag, map_idx_type &map_idx) const; void compileChainRuleDerivative(ofstream &code_file, int eq, int var, int lag, map_idx_type &map_idx) const;
virtual int computeDerivID(int symb_id, int lag);
//! Get the type corresponding to a derivation ID //! Get the type corresponding to a derivation ID
SymbolType getTypeByDerivID(int deriv_id) const throw (UnknownDerivIDException); SymbolType getTypeByDerivID(int deriv_id) const throw (UnknownDerivIDException);
//! Get the lag corresponding to a derivation ID //! Get the lag corresponding to a derivation ID
...@@ -131,6 +129,10 @@ private: ...@@ -131,6 +129,10 @@ private:
//! Collect only the first derivatives //! Collect only the first derivatives
map<pair<int, pair<int, int> >, NodeID> collect_first_order_derivatives_endogenous(); map<pair<int, pair<int, int> >, NodeID> collect_first_order_derivatives_endogenous();
//! Allocates the derivation IDs for all dynamic variables of the model
/*! Also computes max_{endo,exo}_{lead_lag}, and initializes dynJacobianColsNbr to the number of dynamic endos */
void computeDerivIDs();
//! Helper for writing the Jacobian elements in MATLAB and C //! Helper for writing the Jacobian elements in MATLAB and C
/*! Writes either (i+1,j+1) or [i+j*no_eq] */ /*! Writes either (i+1,j+1) or [i+j*no_eq] */
void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const; void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
...@@ -147,7 +149,7 @@ public: ...@@ -147,7 +149,7 @@ public:
DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants); DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants);
//! Adds a variable node //! Adds a variable node
/*! This implementation allows for non-zero lag */ /*! This implementation allows for non-zero lag */
virtual NodeID AddVariable(const string &name, int lag = 0); virtual VariableNode *AddVariable(int symb_id, int lag = 0);
//! Absolute value under which a number is considered to be zero //! Absolute value under which a number is considered to be zero
double cutoff; double cutoff;
//! Compute the minimum feedback set in the dynamic model: //! Compute the minimum feedback set in the dynamic model:
...@@ -196,6 +198,15 @@ public: ...@@ -196,6 +198,15 @@ public:
//! Returns true indicating that this is a dynamic model //! Returns true indicating that this is a dynamic model
virtual bool isDynamic() const { return true; }; virtual bool isDynamic() const { return true; };
//! Transforms the model by removing all leads greater or equal than 2
void substituteLeadGreaterThanTwo();
//! Transforms the model by removing all lags greater or equal than 2
void substituteLagGreaterThanTwo();
//! Fills eval context with values of model local variables and auxiliary variables
void fillEvalContext(eval_context_type &eval_context) const;
}; };
#endif #endif
...@@ -35,6 +35,9 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm ...@@ -35,6 +35,9 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm
// Run checking pass // Run checking pass
mod_file->checkPass(); mod_file->checkPass();
// Perform transformations on the model (creation of auxiliary vars and equations)
mod_file->transformPass();
// Evaluate parameters initialization, initval, endval and pounds // Evaluate parameters initialization, initval, endval and pounds
mod_file->evalAllExpressions(); mod_file->evalAllExpressions();
......
This diff is collapsed.
...@@ -31,6 +31,8 @@ using namespace std; ...@@ -31,6 +31,8 @@ using namespace std;
#include "CodeInterpreter.hh" #include "CodeInterpreter.hh"
class DataTree; class DataTree;
class VariableNode;
class BinaryOpNode;
typedef class ExprNode *NodeID; typedef class ExprNode *NodeID;
...@@ -120,6 +122,9 @@ protected: ...@@ -120,6 +122,9 @@ protected:
//! Index number //! Index number
int idx; int idx;
//! Is the data member non_null_derivatives initialized ?
bool preparedForDerivation;
//! Set of derivation IDs with respect to which the derivative is potentially non-null //! Set of derivation IDs with respect to which the derivative is potentially non-null
set<int> non_null_derivatives; set<int> non_null_derivatives;
...@@ -134,6 +139,9 @@ public: ...@@ -134,6 +139,9 @@ public:
ExprNode(DataTree &datatree_arg); ExprNode(DataTree &datatree_arg);
virtual ~ExprNode(); virtual ~ExprNode();
//! Initializes data member non_null_derivatives
virtual void prepareForDerivation() = 0;
//! Returns derivative w.r. to derivation ID //! Returns derivative w.r. to derivation ID
/*! Uses a symbolic a priori to pre-detect null derivatives, and caches the result for other derivatives (to avoid computing it several times) /*! Uses a symbolic a priori to pre-detect null derivatives, and caches the result for other derivatives (to avoid computing it several times)
For an equal node, returns the derivative of lhs minus rhs */ For an equal node, returns the derivative of lhs minus rhs */
...@@ -216,6 +224,50 @@ public: ...@@ -216,6 +224,50 @@ public: