Commit 0c16f528 authored by sebastien's avatar sebastien
Browse files

v4 parser:

* reshaped DataTree/ModelTree using a more object-oriented approach
* improved expression sharing algorithm (temporary terms in output files), resulting in smaller output files for big models
* optimized performance (both in computing time and memory consumption)
* bugfix: the expressions stored in local parameters of models (pound expressions) are now derived
* bugfix: cosh(0) = 1
* removed some useless parentheses in output


git-svn-id: https://www.dynare.org/svn/dynare/dynare_v4@1148 ac1d8469-bf42-47a9-8791-bf33cf982152
parent 7417d180
/*! \file
\version 1.0
\date 04/09/2004
\par This file implements the DataTree class methodes.
*/
//------------------------------------------------------------------------------
#include <iostream>
#include <string>
#include <vector>
#include <map>
using namespace std;
#include <time.h>
//------------------------------------------------------------------------------
#include "DynareBison.hh"
#include "VariableTable.hh"
#include "NumericalConstants.hh"
#include "DataTree.hh"
DataTree::DataTree(SymbolTable &symbol_table_arg) :
DataTree::DataTree(SymbolTable &symbol_table_arg, NumericalConstants &num_constants_arg) :
symbol_table(symbol_table_arg),
num_constants(num_constants_arg),
variable_table(symbol_table_arg),
NoOpCode(-1), NullID(NULL)
{
offset = 1;
current_order = 0;
Zero = new MetaToken(reinterpret_cast <NodeID> (0), eNumericalConstant, NULL, -1);
Zero->op_name = "";
Zero->reference_count.resize(current_order+1,2);
Zero->idx = 0;
mModelTree.push_back(Zero);
mIndexOfTokens[*Zero]=Zero;
One = new MetaToken(reinterpret_cast <NodeID> (1), eNumericalConstant, NULL, -1); One->op_name = "";
One->op_name = "";
One->reference_count.resize(current_order+1,1);
One->idx = 1;
mModelTree.push_back(One);
mIndexOfTokens[*One]=One;
MinusOne = new MetaToken(One, eTempResult, NULL, token::UMINUS);
MinusOne->op_name = OperatorTable::str(token::UMINUS);
MinusOne->reference_count.resize(current_order+1,1);
MinusOne->idx = 2;
mModelTree.push_back(MinusOne);
mIndexOfTokens[*MinusOne]=MinusOne;
// Pushing "0=0" into mModelTree
ZeroEqZero = new MetaToken(Zero, eTempResult, Zero, token::EQUAL);
ZeroEqZero->op_name = OperatorTable::str(token::EQUAL);
ZeroEqZero->reference_count.resize(current_order+1,1);
ZeroEqZero->idx = 3;
mModelTree.push_back(ZeroEqZero);
mIndexOfTokens[*ZeroEqZero]=ZeroEqZero;
// Initialise global node counter
nodeCounter = 4;
BeginModel = mModelTree.end();
BeginModel--;
}
//------------------------------------------------------------------------------
offset(1)
{
Zero = AddNumConstant("0.0");
One = AddNumConstant("1.0");
MinusOne = AddUMinus(One);
}
DataTree::~DataTree()
{
for (TreeIterator it = mModelTree.begin(); it != mModelTree.end(); it++)
for (node_list_type::iterator it = node_list.begin(); it != node_list.end(); it++)
delete *it;
}
NodeID
DataTree::AddNumConstant(const string &value)
{
int id = num_constants.AddConstant(value);
num_const_node_map_type::iterator it = num_const_node_map.find(id);
if (it != num_const_node_map.end())
return it->second;
else
return new NumConstNode(*this, id);
}
NodeID
DataTree::AddVariable(const string &name, int lag)
{
if (!symbol_table.Exist(name))
{
cerr << "Unknown symbol: " << name << endl;
exit(-1);
}
symbol_table.SetReferenced(name);
Type type = symbol_table.getType(name);
int id;
if (type == eEndogenous
|| type == eExogenousDet
|| type == eExogenous
|| type == eRecursiveVariable)
id = variable_table.AddVariable(name, lag);
else
id = symbol_table.getID(name);
variable_node_map_type::iterator it = variable_node_map.find(make_pair(id, type));
if (it != variable_node_map.end())
return it->second;
else
return new VariableNode(*this, id, type);
}
NodeID
DataTree::AddPlus(NodeID iArg1, NodeID iArg2)
{
if (iArg1 != Zero && iArg2 != Zero)
{
// Simplify x+(-y) in x-y
UnaryOpNode *uarg2 = dynamic_cast<UnaryOpNode *>(iArg2);
if (uarg2 != NULL && uarg2->op_code == oUminus)
return AddMinus(iArg1, uarg2->arg);
// To treat commutativity of "+"
// Nodes iArg1 and iArg2 are sorted by index
if (iArg1->idx > iArg2->idx)
{
NodeID tmp = iArg1;
iArg1 = iArg2;
iArg2 = tmp;
}
return AddBinaryOp(iArg1, oPlus, iArg2);
}
else if (iArg1 != Zero)
return iArg1;
else if (iArg2 != Zero)
return iArg2;
else
return Zero;
}
NodeID
DataTree::AddMinus(NodeID iArg1, NodeID iArg2)
{
if (iArg1 != Zero && iArg2 != Zero)
return AddBinaryOp(iArg1, oMinus, iArg2);
else if (iArg1 != Zero)
return iArg1;
else if (iArg2 != Zero)
return AddUMinus(iArg2);
else
return Zero;
}
NodeID
DataTree::AddUMinus(NodeID iArg1)
{
if (iArg1 != Zero)
{
// Simplify -(-x) in x
UnaryOpNode *uarg = dynamic_cast<UnaryOpNode *>(iArg1);
if (uarg != NULL && uarg->op_code == oUminus)
return uarg->arg;
return AddUnaryOp(oUminus, iArg1);
}
else
return Zero;
}
NodeID
DataTree::AddTimes(NodeID iArg1, NodeID iArg2)
{
if (iArg1 == MinusOne)
return AddUMinus(iArg2);
else if (iArg2 == MinusOne)
return AddUMinus(iArg1);
else if (iArg1 != Zero && iArg1 != One && iArg2 != Zero && iArg2 != One)
{
// To treat commutativity of "*"
// Nodes iArg1 and iArg2 are sorted by index
if (iArg1->idx > iArg2->idx)
{
NodeID tmp = iArg1;
iArg1 = iArg2;
iArg2 = tmp;
}
return AddBinaryOp(iArg1, oTimes, iArg2);
}
else if (iArg1 != Zero && iArg1 != One && iArg2 == One)
return iArg1;
else if (iArg2 != Zero && iArg2 != One && iArg1 == One)
return iArg2;
else if (iArg2 == One && iArg1 == One)
return One;
else
return Zero;
}
NodeID
DataTree::AddDivide(NodeID iArg1, NodeID iArg2)
{
if (iArg1 != Zero && iArg2 != Zero && iArg2 != One)
return AddBinaryOp(iArg1, oDivide, iArg2);
else if (iArg2 == One)
return iArg1;
else if (iArg1 == Zero && iArg2 != Zero)
return Zero;
else
{
if (*it != NullID) delete *it;
cerr << "Division by zero!" << endl;
exit(-1);
}
}
NodeID
DataTree::AddPower(NodeID iArg1, NodeID iArg2)
{
if (iArg1 != Zero && iArg2 != Zero && iArg2 != One)
return AddBinaryOp(iArg1, oPower, iArg2);
else if (iArg2 == One)
return iArg1;
else if (iArg2 == Zero)
return One;
else
return Zero;
}
NodeID
DataTree::AddExp(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oExp, iArg1);
else
return One;
}
NodeID
DataTree::AddLog(NodeID iArg1)
{
if (iArg1 != Zero && iArg1 != One)
return AddUnaryOp(oLog, iArg1);
else if (iArg1 == One)
return Zero;
else
{
cerr << "log(0) isn't available" << endl;
exit(-1);
}
}
NodeID DataTree::AddLog10(NodeID iArg1)
{
if (iArg1 != Zero && iArg1 != One)
return AddUnaryOp(oLog10, iArg1);
else if (iArg1 == One)
return Zero;
else
{
cerr << "log10(0) isn't available" << endl;
exit(-1);
}
}
NodeID
DataTree::AddCos(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oCos, iArg1);
else
return One;
}
NodeID
DataTree::AddSin(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oSin, iArg1);
else
return Zero;
}
NodeID
DataTree::AddTan(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oTan, iArg1);
else
return Zero;
}
NodeID
DataTree::AddACos(NodeID iArg1)
{
if (iArg1 != One)
return AddUnaryOp(oAcos, iArg1);
else
return Zero;
}
NodeID
DataTree::AddASin(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oAsin, iArg1);
else
return Zero;
}
NodeID
DataTree::AddATan(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oAtan, iArg1);
else
return Zero;
}
NodeID
DataTree::AddCosH(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oCosh, iArg1);
else
return One;
}
NodeID
DataTree::AddSinH(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oSinh, iArg1);
else
return Zero;
}
NodeID
DataTree::AddTanH(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oTanh, iArg1);
else
return Zero;
}
NodeID
DataTree::AddACosH(NodeID iArg1)
{
if (iArg1 != One)
return AddUnaryOp(oAcosh, iArg1);
else
return Zero;
}
NodeID
DataTree::AddASinH(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oAsinh, iArg1);
else
return Zero;
}
NodeID
DataTree::AddATanH(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oAtanh, iArg1);
else
return Zero;
}
NodeID
DataTree::AddSqRt(NodeID iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(oSqrt, iArg1);
else
return Zero;
}
NodeID
DataTree::AddEqual(NodeID iArg1, NodeID iArg2)
{
return AddBinaryOp(iArg1, oEqual, iArg2);
}
void
DataTree::AddLocalParameter(const string &name, NodeID value) throw (LocalParameterException)
{
int id = symbol_table.getID(name);
// Throw an exception if symbol already declared
map<int, NodeID>::iterator it = local_parameters_table.find(id);
if (it != local_parameters_table.end())
throw LocalParameterException(name);
local_parameters_table[id] = value;
}
......@@ -8,7 +8,7 @@ using namespace std;
class ParsingDriver;
#include "SymbolTableTypes.hh"
#include "ModelTypes.hh"
#include "ExprNode.hh"
//! Type for semantic value of non-derivable expressions
typedef pair<int, Type> ExpObj;
......@@ -74,9 +74,6 @@ typedef pair<int, Type> ExpObj;
%left UMINUS
%nonassoc POWER
%token EXP LOG LOG10 SIN COS TAN ASIN ACOS ATAN SINH COSH TANH ASINH ACOSH ATANH SQRT
/* isn't parsed from the *.mod file, but used to distinguish EQUAL in equation and EQUAL in assignment in operation codes
*/
%token ASSIGN
%type <exp_val> expression comma_expression
%type <model_val> equation hand_side model_var
......
#include <iostream>
#include <iterator>
#include <algorithm>
#include "ExprNode.hh"
#include "DataTree.hh"
ExprNode::ExprNode(DataTree &datatree_arg) : datatree(datatree_arg)
{
// Add myself to datatree
datatree.node_list.push_back(this);
// Set my index and increment counter
idx = datatree.node_counter++;
}
ExprNode::~ExprNode()
{
}
NodeID
ExprNode::getDerivative(int varID)
{
// Return zero if derivative is necessarily null (using symbolic a priori)
set<int>::const_iterator it = non_null_derivatives.find(varID);
if (it == non_null_derivatives.end())
return datatree.Zero;
// If derivative is stored in cache, use the cached value, otherwise compute it (and cache it)
map<int, NodeID>::const_iterator it2 = derivatives.find(varID);
if (it2 != derivatives.end())
return it2->second;
else
{
NodeID d = computeDerivative(varID);
derivatives[varID] = d;
return d;
}
}
int
ExprNode::precedence(const temporary_terms_type &temporary_terms) const
{
// For a constant, a variable, or a unary op, the precedence is maximal
return 100;
}
int
ExprNode::cost(temporary_terms_type &temporary_terms) const
{
// For a terminal node, the cost is null
return 0;
}
void
ExprNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
temporary_terms_type &temporary_terms) const
{
// Nothing to do for a terminal node
}
NumConstNode::NumConstNode(DataTree &datatree_arg, int id_arg) :
ExprNode(datatree_arg),
id(id_arg)
{
// Add myself to the num const map
datatree.num_const_node_map[id] = this;
// All derivatives are null, so non_null_derivatives is left empty
}
NodeID
NumConstNode::computeDerivative(int varID)
{
return datatree.Zero;
}
void
NumConstNode::writeOutput(ostream &output, bool is_dynamic,
const temporary_terms_type &temporary_terms) const
{
temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<NumConstNode *>(this));
if (it != temporary_terms.end())
output << "T" << idx;
else
output << datatree.num_constants.get(id);
}
VariableNode::VariableNode(DataTree &datatree_arg, int id_arg, Type type_arg) :
ExprNode(datatree_arg),
id(id_arg),
type(type_arg)
{
// Add myself to the variable map
datatree.variable_node_map[make_pair(id, type)] = this;
// Fill in non_null_derivatives
switch(type)
{
case eEndogenous:
case eExogenous:
case eExogenousDet:
case eRecursiveVariable:
// For a variable, the only non-null derivative is with respect to itself
non_null_derivatives.insert(id);
break;
case eParameter:
// All derivatives are null, do nothing
break;
case eLocalParameter:
// Non null derivatives are those of the value of the local parameter
non_null_derivatives = datatree.local_parameters_table[id]->non_null_derivatives;
break;
case eNumericalConstant:
case eUNDEF:
case eTempResult:
// Impossible cases
cerr << "Incorrect symbol type used in VariableNode" << endl;
exit(-1);
}
}
NodeID
VariableNode::computeDerivative(int varID)
{
switch(type)
{
case eEndogenous:
case eExogenous:
case eExogenousDet:
case eRecursiveVariable:
if (varID == id)
return datatree.One;
else
return datatree.Zero;
case eParameter:
return datatree.Zero;
case eLocalParameter:
return datatree.local_parameters_table[id]->getDerivative(varID);
case eNumericalConstant:
case eUNDEF:
case eTempResult:
// Impossible cases
cerr << "Incorrect symbol type used in VariableNode" << endl;
exit(-1);
}
cerr << "Impossible case!" << endl;
exit(-1);
}
void
VariableNode::writeOutput(ostream &output, bool is_dynamic,
const temporary_terms_type &temporary_terms) const
{
// If node is a temporary term
temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<VariableNode *>(this));
if (it != temporary_terms.end())
{
output << "T" << idx;
return;
}
char &lpar = datatree.lpar;
char &rpar = datatree.rpar;
int idx;
switch(type)
{
case eParameter:
output << "params" << lpar << id + datatree.offset << rpar;
break;
case eLocalParameter:
output << datatree.symbol_table.getNameByID(eLocalParameter, id);
break;
case eEndogenous:
if (is_dynamic)
{
idx = datatree.variable_table.getPrintIndex(id) + datatree.offset;
output << "y" << lpar << idx << rpar;
}
else
{
idx = datatree.variable_table.getSymbolID(id) + datatree.offset;
output << "y" << lpar << idx << rpar;
}
break;
case eExogenous:
idx = datatree.variable_table.getSymbolID(id) + datatree.offset;
if (is_dynamic)
{
int lag = datatree.variable_table.getLag(id);