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)
return new NumConstNode(*this, id);
}
NodeID
DataTree::AddVariableInternal(const string &name, int lag)
VariableNode *
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));
if (it != variable_node_map.end())
return it->second;
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)
{
int symb_id = symbol_table.getID(name);
return AddVariable(symb_id, lag);
}
VariableNode *
DataTree::AddVariable(int symb_id, int lag)
{
assert(lag == 0);
return AddVariableInternal(name, lag);
return AddVariableInternal(symb_id, lag);
}
NodeID
......@@ -445,25 +450,6 @@ DataTree::AddUnknownFunction(const string &function_name, const vector<NodeID> &
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
DataTree::isSymbolUsed(int symb_id) const
{
......@@ -478,12 +464,6 @@ DataTree::isSymbolUsed(int symb_id) const
return false;
}
int
DataTree::computeDerivID(int symb_id, int lag)
{
return -1;
}
int
DataTree::getDerivID(int symb_id, int lag) const throw (UnknownDerivIDException)
{
......
......@@ -49,26 +49,24 @@ protected:
//! Reference to numerical constants table
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;
//! 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;
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;
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;
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;
//! Stores local variables value (maps symbol ID to corresponding node)
map<int, NodeID> local_variables_table;
//! 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:
typedef list<NodeID> node_list_type;
//! The list of nodes
......@@ -100,7 +98,9 @@ public:
NodeID AddNumConstant(const string &value);
//! Adds a variable
/*! 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
NodeID AddPlus(NodeID iArg1, NodeID iArg2);
//! Adds "arg1-arg2" to model tree
......@@ -172,8 +172,6 @@ public:
//! Adds an unknown function node
/*! \todo Use a map to share identical nodes */
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
bool isSymbolUsed(int symb_id) const;
//! Thrown when trying to access an unknown variable by deriv_id
......
......@@ -48,10 +48,10 @@ DynamicModel::DynamicModel(SymbolTable &symbol_table_arg,
{
}
NodeID
DynamicModel::AddVariable(const string &name, int lag)
VariableNode *
DynamicModel::AddVariable(int symb_id, int lag)
{
return AddVariableInternal(name, lag);
return AddVariableInternal(symb_id, lag);
}
void
......@@ -2292,7 +2292,10 @@ DynamicModel::computingPass(bool jacobianExo, bool hessian, bool thirdDerivative
{
assert(jacobianExo || !(hessian || thirdDerivatives || paramsDerivatives));
// Computes dynamic jacobian columns
// Prepare for derivation
computeDerivIDs();
// Computes dynamic jacobian columns, must be done after computeDerivIDs()
computeDynJacobianCols(jacobianExo);
// Compute derivatives w.r. to all endogenous, and possibly exogenous and exogenous deterministic
......@@ -2408,6 +2411,11 @@ DynamicModel::toStatic(StaticModel &static_model) const
for (vector<BinaryOpNode *>::const_iterator it = equations.begin();
it != equations.end(); it++)
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
......@@ -2424,60 +2432,65 @@ DynamicModel::toStaticDll(StaticDllModel &static_model) const
static_model.addEquation((*it)->toStatic(static_model));
}
int
DynamicModel::computeDerivID(int symb_id, int lag)
void
DynamicModel::computeDerivIDs()
{
// Setting maximum and minimum lags
if (max_lead < lag)
max_lead = lag;
else if (-max_lag > lag)
max_lag = -lag;
set<pair<int, int> > dynvars;
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:
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;
case eParameter:
// We wan't to compute a derivation ID for parameters
break;
default:
return -1;
equations[i]->collectVariables(eExogenous, dynvars);
equations[i]->collectVariables(eExogenousDet, dynvars);
equations[i]->collectVariables(eParameter, dynvars);
}
// Check if dynamic variable already has a deriv_id
pair<int, int> key = make_pair(symb_id, lag);
deriv_id_table_t::const_iterator it = deriv_id_table.find(key);
if (it != deriv_id_table.end())
return it->second;
for(set<pair<int, int> >::const_iterator it = dynvars.begin();
it != dynvars.end(); it++)
{
int lag = it->second;
SymbolType type = symbol_table.getType(it->first);
// Create a new deriv_id
int deriv_id = deriv_id_table.size();
// Setting maximum and minimum lags
if (max_lead < lag)
max_lead = lag;
else if (-max_lag > lag)
max_lag = -lag;
deriv_id_table[key] = deriv_id;
inv_deriv_id_table.push_back(key);
switch (type)
{
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)
dynJacobianColsNbr++;
// Create a new deriv_id
int deriv_id = deriv_id_table.size();
return deriv_id;
deriv_id_table[*it] = deriv_id;
inv_deriv_id_table.push_back(*it);
}
}
SymbolType
......@@ -2814,4 +2827,100 @@ DynamicModel::hessianHelper(ostream &output, int row_nb, int col_nb, ExprNodeOut
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;
//! Stores a dynamic model
class DynamicModel : public ModelTree
{
public:
private:
typedef map<pair<int, int>, int> deriv_id_table_t;
//! Maps a pair (symbol_id, lag) to a deriv ID
......@@ -44,20 +43,20 @@ private:
map<int, int> dyn_jacobian_cols_table;
//! Maximum lag and lead over all types of variables (positive values)
/*! Set by computeDerivID() */
/*! Set by computeDerivIDs() */
int max_lag, max_lead;
//! Maximum lag and lead over endogenous variables (positive values)
/*! Set by computeDerivID() */
/*! Set by computeDerivIDs() */
int max_endo_lag, max_endo_lead;
//! Maximum lag and lead over exogenous variables (positive values)
/*! Set by computeDerivID() */
/*! Set by computeDerivIDs() */
int max_exo_lag, max_exo_lead;
//! 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;
//! Number of columns of dynamic jacobian
/*! Set by computeDerivID() and computeDynJacobianCols() */
/*! Set by computeDerivID()s and computeDynJacobianCols() */
int dynJacobianColsNbr;
//! Derivatives of the residuals w.r. to parameters
......@@ -113,7 +112,6 @@ private:
//! 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;
virtual int computeDerivID(int symb_id, int lag);
//! Get the type corresponding to a derivation ID
SymbolType getTypeByDerivID(int deriv_id) const throw (UnknownDerivIDException);
//! Get the lag corresponding to a derivation ID
......@@ -131,6 +129,10 @@ private:
//! Collect only the first derivatives
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
/*! 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;
......@@ -147,7 +149,7 @@ public:
DynamicModel(SymbolTable &symbol_table_arg, NumericalConstants &num_constants);
//! Adds a variable node
/*! 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
double cutoff;
//! Compute the minimum feedback set in the dynamic model:
......@@ -196,6 +198,15 @@ public:
//! Returns true indicating that this is a dynamic model
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
......@@ -35,6 +35,9 @@ main2(stringstream &in, string &basename, bool debug, bool clear_all, bool no_tm
// Run checking pass
mod_file->checkPass();
// Perform transformations on the model (creation of auxiliary vars and equations)
mod_file->transformPass();
// Evaluate parameters initialization, initval, endval and pounds
mod_file->evalAllExpressions();
......
This diff is collapsed.
......@@ -31,6 +31,8 @@ using namespace std;
#include "CodeInterpreter.hh"
class DataTree;
class VariableNode;
class BinaryOpNode;
typedef class ExprNode *NodeID;
......@@ -120,6 +122,9 @@ protected:
//! Index number
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<int> non_null_derivatives;
......@@ -134,6 +139,9 @@ public:
ExprNode(DataTree &datatree_arg);
virtual ~ExprNode();
//! Initializes data member non_null_derivatives
virtual void prepareForDerivation() = 0;
//! 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)
For an equal node, returns the derivative of lhs minus rhs */
......@@ -216,6 +224,50 @@ public:
virtual NodeID toStatic(DataTree &static_datatree) const = 0;
//! Try to normalize an equation linear in its endogenous variable
virtual pair<int, NodeID> normalizeEquation(int symb_id_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const = 0;
//! Returns the maximum lead of endogenous in this expression
/*! Always returns a non-negative value */
virtual int maxEndoLead() const = 0;
//! Returns a new expression where all the leads/lags have been shifted backwards by the same amount
/*!
Only acts on endogenous, exogenous, exogenous det
\param[in] n The number of lags by which to shift
\return The same expression except that leads/lags have been shifted backwards
*/
virtual NodeID decreaseLeadsLags(int n) const = 0;
//! Type for the substitution map used in the process of creating auxiliary vars for leads >= 2
typedef map<const ExprNode *, const VariableNode *> subst_table_t;
//! Creates auxiliary lead variables corresponding to this expression
/*!
If maximum endogenous lead >= 3, this method will also create intermediary auxiliary var, and will add the equations of the form aux1 = aux2(+1) to the substitution table.
\pre This expression is assumed to have maximum endogenous lead >= 2
\param[in,out] subst_table The table to which new auxiliary variables and their correspondance will be added
\return The new variable node corresponding to the current expression
*/
VariableNode *createLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
//! Constructs a new expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
/*!
\param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
\param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
If the method detects a sub-expr which needs to be substituted, two cases are possible:
- if this expr is in the table, then it will use the corresponding variable and return the substituted expression
- if this expr is not in the table, then it will create an auxiliary endogenous variable, add the substitution in the table and return the substituted expression
\return A new equivalent expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
*/
virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
//! Constructs a new expression where endo variables with max endo lag >= 2 have been replaced by auxiliary variables
/*!
\param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
\param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
*/
virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
};
//! Object used to compare two nodes (using their indexes)
......@@ -237,6 +289,7 @@ private:
virtual NodeID computeDerivative(int deriv_id);
public:
NumConstNode(DataTree &datatree_arg, int id_arg);
virtual void prepareForDerivation();
virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
virtual void collectVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
virtual void collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const;
......@@ -245,6 +298,10 @@ public:
virtual NodeID toStatic(DataTree &static_datatree) const;
virtual pair<int, NodeID> normalizeEquation(int symb_id_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const;
virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
virtual int maxEndoLead() const;
virtual NodeID decreaseLeadsLags(int n) const;
virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
};
//! Symbol or variable node
......@@ -255,11 +312,10 @@ private:
const int symb_id;
const SymbolType type;
const int lag;
//! Derivation ID
const int deriv_id;
virtual NodeID computeDerivative(int deriv_id_arg);
virtual NodeID computeDerivative(int deriv_id);
public:
VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg, int deriv_id_arg);
VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg);
virtual void prepareForDerivation();
virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
virtual void collectVariables(SymbolType type_arg, set<pair<int, int> > &result) const;
virtual void computeTemporaryTerms(map<NodeID, int> &reference_count,
......@@ -276,6 +332,10 @@ public:
int get_symb_id() const { return symb_id; };
virtual pair<int, NodeID> normalizeEquation(int symb_id_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const;
virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
virtual int maxEndoLead() const;
virtual NodeID decreaseLeadsLags(int n) const;
virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
};
//! Unary operator node
......@@ -290,6 +350,7 @@ private:
NodeID composeDerivatives(NodeID darg);
public:
UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg);
virtual void prepareForDerivation();
virtual void computeTemporaryTerms(map<NodeID, int> &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;
virtual void computeTemporaryTerms(map<NodeID, int> &reference_count,
......@@ -311,6 +372,12 @@ public:
virtual NodeID toStatic(DataTree &static_datatree) const;
virtual pair<int, NodeID> normalizeEquation(int symb_id_endo, vector<pair<int, pair<NodeID, NodeID> > > &List_of_Op_RHS) const;
virtual NodeID getChainRuleDerivative(int deriv_id, const map<int, NodeID> &recursive_variables);
virtual int maxEndoLead() const;
virtual NodeID decreaseLeadsLags(int n) const;
virtual NodeID substituteLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
//! Creates another UnaryOpNode with the same opcode, but with a possibly different datatree and argument
NodeID buildSimilarUnaryOpNode(NodeID alt_arg, DataTree &alt_datatree) const;
virtual NodeID substituteLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;
};
//! Binary operator node
......@@ -326,6 +393,7 @@ private:
public:
BinaryOpNode(DataTree &datatree_arg, const NodeID arg1_arg,
BinaryOpcode op_code_arg, const NodeID arg2_arg);
virtual void prepareForDerivation();
virtual int precedence(ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const;
virtual void computeTemporaryTerms(map<NodeID, int> &reference_count, temporary_terms_type &temporary_terms, bool is_matlab) const;
virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const