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
......
This diff is collapsed.
......@@ -50,7 +50,8 @@ COMMON_OBJ=\
ParsingDriver.o\
DataTree.o \
ModFile.o \
Statement.o
Statement.o \
ExprNode.o
MATLAB_OBJ = InterfaceMatlab.o
......
#include <iostream>
#include <fstream>
#include "ModFile.hh"
#include "Interface.hh"
......@@ -56,7 +59,7 @@ ModFile::computingPass()
}
void
ModFile::writeOutputFiles(const string &basename, bool clear_all)
ModFile::writeOutputFiles(const string &basename, bool clear_all) const
{
ofstream mOutputFile;
......@@ -135,7 +138,7 @@ ModFile::writeOutputFiles(const string &basename, bool clear_all)
model_tree.writeDynamicFile(basename);
// Print statements
for(vector<Statement *>::iterator it = statements.begin();
for(vector<Statement *>::const_iterator it = statements.begin();
it != statements.end(); it++)
(*it)->writeOutput(mOutputFile, basename);
......
This diff is collapsed.
......@@ -42,7 +42,6 @@ ParsingDriver::parse(const string &f)
{
mod_file = new ModFile();
mod_file->model_tree.error = error;
mod_file->symbol_table.error = error;
expression.setNumericalConstants(&mod_file->num_constants);
......@@ -118,16 +117,16 @@ ParsingDriver::add_expression_constant(string *constant)
NodeID
ParsingDriver::add_model_constant(string *constant)
{
int id = mod_file->num_constants.AddConstant(*constant);
NodeID id = model_tree->AddNumConstant(*constant);
delete constant;
return model_tree->AddTerminal((NodeID) id, eNumericalConstant);
return id;
}
NodeID
ParsingDriver::add_model_variable(string *name)
{
check_symbol_existence(*name);
NodeID id = model_tree->AddTerminal(*name);
NodeID id = model_tree->AddVariable(*name);
delete name;
return id;
}
......@@ -145,7 +144,7 @@ ParsingDriver::add_model_variable(string *name, string *olag)
<< *name
<< " has lag " << lag << endl;
}
NodeID id = model_tree->AddTerminal(*name, lag);
NodeID id = model_tree->AddVariable(*name, lag);
delete name;
delete olag;
return id;
......@@ -920,8 +919,8 @@ void
ParsingDriver::end_planner_objective(NodeID expr)
{
// Add equation corresponding to expression
model_tree->AddEqual(expr, model_tree->Zero);
model_tree->eq_nbr++;
NodeID eq = model_tree->AddEqual(expr, model_tree->Zero);
model_tree->addEquation(eq);
mod_file->addStatement(new PlannerObjectiveStatement(model_tree));
}
......@@ -938,7 +937,7 @@ NodeID
ParsingDriver::add_model_equal(NodeID arg1, NodeID arg2)
{
NodeID id = model_tree->AddEqual(arg1, arg2);
model_tree->eq_nbr++;
model_tree->addEquation(id);
return id;
}
......@@ -952,8 +951,14 @@ void
ParsingDriver::declare_and_init_local_parameter(string *name, NodeID rhs)
{
mod_file->symbol_table.AddSymbolDeclar(*name, eLocalParameter, *name);
NodeID id = model_tree->AddTerminal(*name);
model_tree->AddAssign(id, rhs);
try
{
model_tree->AddLocalParameter(*name, rhs);
}
catch(DataTree::LocalParameterException &e)
{
error("Local parameter " + e.name + " declared twice");
}
delete name;
}
......
......@@ -100,7 +100,7 @@ Reference SymbolTable::isReferenced(const std::string &name) const
}
void
SymbolTable::writeOutput(ostream &output)
SymbolTable::writeOutput(ostream &output) const
{
if (exo_nbr > 0)
{
......
This diff is collapsed.
#ifndef _EXPR_NODE_HH
#define _EXPR_NODE_HH
using namespace std;
#include <set>
#include <map>
#include "SymbolTableTypes.hh"
class DataTree;
typedef class ExprNode *NodeID;
struct ExprNodeLess;
//! Type for set of temporary terms
/*! They are ordered by index number thanks to ExprNodeLess */
typedef set<NodeID, ExprNodeLess> temporary_terms_type;
//! Base class for expression nodes
class ExprNode
{
friend class DataTree;
friend class ModelTree;
friend class ExprNodeLess;
friend class NumConstNode;
friend class VariableNode;
friend class UnaryOpNode;
friend class BinaryOpNode;
private:
//! Computes derivative w.r. to variable varID (but doesn't store it in derivatives map)
/*! You shoud use getDerivative() to get the benefit of symbolic a priori and of caching */
virtual NodeID computeDerivative(int varID) = 0;
protected:
//! Reference to the enclosing DataTree
DataTree &datatree;
//! Index number
int idx;
//! Set of variable IDs with respect to which the derivative is potentially non-null
set<int> non_null_derivatives;
//! Used for caching of first order derivatives (when non-null)
map<int, NodeID> derivatives;
//! Cost of computing current node
/*! Nodes included in temporary_terms are considered having a null cost */
virtual int cost(temporary_terms_type &temporary_terms) const;
public:
ExprNode(DataTree &datatree_arg);
virtual ~ExprNode();
//! Returns derivative w.r. to variable varID
/*! 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 */
NodeID getDerivative(int varID);
//! Returns precedence of node
/*! Equals 100 for constants, variables, unary ops, and temporary terms */
virtual int precedence(const temporary_terms_type &temporary_terms) const;
//! Fills temporary_terms set, using reference counts
/*! A node will be marked as a temporar