Skip to content
Snippets Groups Projects
Select Git revision
  • 688e30019c08369bc6edab9a501146c703d15b13
  • master default protected
  • 6.x protected
  • madysson
  • 5.x protected
  • asm
  • time-varying-information-set
  • 4.6 protected
  • dynare_minreal
  • dragonfly
  • various_fixes
  • 4.5 protected
  • clang+openmp
  • exo_steady_state
  • declare_vars_in_model_block
  • julia
  • error_msg_undeclared_model_vars
  • static_aux_vars
  • slice
  • aux_func
  • penalty
  • 6.4 protected
  • 6.3 protected
  • 6.2 protected
  • 6.1 protected
  • 6.0 protected
  • 6-beta2 protected
  • 6-beta1 protected
  • 5.5 protected
  • 5.4 protected
  • 5.3 protected
  • 5.2 protected
  • 5.1 protected
  • 5.0 protected
  • 5.0-rc1 protected
  • 4.7-beta3 protected
  • 4.7-beta2 protected
  • 4.7-beta1 protected
  • 4.6.4 protected
  • 4.6.3 protected
  • 4.6.2 protected
41 results

ConfigFile.hh

Blame
  • ExprNode.cc 56.04 KiB
    /*
     * Copyright (C) 2007-2009 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 <iostream>
    #include <iterator>
    #include <algorithm>
    
    #include <cassert>
    #include <cmath>
    
    #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 deriv_id)
    {
      // Return zero if derivative is necessarily null (using symbolic a priori)
      set<int>::const_iterator it = non_null_derivatives.find(deriv_id);
      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(deriv_id);
      if (it2 != derivatives.end())
        return it2->second;
      else
        {
          NodeID d = computeDerivative(deriv_id);
          derivatives[deriv_id] = d;
          return d;
        }
    }
    
    int
    ExprNode::precedence(ExprNodeOutputType output_type, 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(const temporary_terms_type &temporary_terms, bool is_matlab) const
    {
      // For a terminal node, the cost is null
      return 0;
    }
    
    void
    ExprNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                    temporary_terms_type &temporary_terms,
                                    bool is_matlab) const
    {
      // Nothing to do for a terminal node
    }
    
    void
    ExprNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                    temporary_terms_type &temporary_terms,
                                    map<NodeID, pair<int, int> > &first_occurence,
                                    int Curr_block,
                                    Model_Block *ModelBlock,
                                    int equation,
                                    map_idx_type &map_idx) const
    {
      // Nothing to do for a terminal node
    }
    
    void
    ExprNode::writeOutput(ostream &output)
    {
      writeOutput(output, oMatlabOutsideModel, temporary_terms_type());
    }
    
    
    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 deriv_id)
    {
      return datatree.Zero;
    }
    
    void
    NumConstNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<NumConstNode *>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
    }
    
    void
    NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                              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())
        if (output_type == oMatlabDynamicModelSparse)
          output << "T" << idx << "(it_)";
        else
          output << "T" << idx;
      else
        output << datatree.num_constants.get(id);
    }
    
    double
    NumConstNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      return(datatree.num_constants.getDouble(id));
    }
    
    void
    NumConstNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      CompileCode.write(&FLDC, sizeof(FLDC));
      double vard = datatree.num_constants.getDouble(id);
    #ifdef DEBUGC
      cout << "FLDC " << vard << "\n";
    #endif
      CompileCode.write(reinterpret_cast<char *>(&vard),sizeof(vard));
    }
    
    void
    NumConstNode::collectEndogenous(set<pair<int, int> > &result) const
    {
    }
    
    void
    NumConstNode::collectExogenous(set<pair<int, int> > &result) const
    {
    }
    
    NodeID
    NumConstNode::toStatic(DataTree &static_datatree) const
    {
      return static_datatree.AddNumConstant(datatree.num_constants.get(id));
    }
    
    
    VariableNode::VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg, int deriv_id_arg) :
      ExprNode(datatree_arg),
      symb_id(symb_id_arg),
      type(datatree.symbol_table.getType(symb_id_arg)),
      lag(lag_arg),
      deriv_id(deriv_id_arg)
    {
      // Add myself to the variable map
      datatree.variable_node_map[make_pair(symb_id, lag)] = this;
    
      // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
      assert(lag == 0 || (type != eModelLocalVariable && type != eModFileLocalVariable && type != eUnknownFunction));
    
      // Fill in non_null_derivatives
      switch(type)
        {
        case eEndogenous:
        case eExogenous:
        case eExogenousDet:
        case eParameter:
          // For a variable or a parameter, the only non-null derivative is with respect to itself
          non_null_derivatives.insert(deriv_id);
          break;
        case eModelLocalVariable:
          // Non null derivatives are those of the value of the local parameter
          non_null_derivatives = datatree.local_variables_table[symb_id]->non_null_derivatives;
          break;
        case eModFileLocalVariable:
          // Such a variable is never derived
          break;
        case eUnknownFunction:
          cerr << "Attempt to construct a VariableNode with an unknown function name" << endl;
          exit(EXIT_FAILURE);
        }
    }
    
    NodeID
    VariableNode::computeDerivative(int deriv_id_arg)
    {
      switch(type)
        {
        case eEndogenous:
        case eExogenous:
        case eExogenousDet:
        case eParameter:
          if (deriv_id == deriv_id_arg)
            return datatree.One;
          else
            return datatree.Zero;
        case eModelLocalVariable:
          return datatree.local_variables_table[symb_id]->getDerivative(deriv_id_arg);
        case eModFileLocalVariable:
          cerr << "ModFileLocalVariable is not derivable" << endl;
          exit(EXIT_FAILURE);
        case eUnknownFunction:
          cerr << "Impossible case!" << endl;
          exit(EXIT_FAILURE);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    void
    VariableNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<VariableNode *>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
      if(type== eModelLocalVariable)
        datatree.local_variables_table[symb_id]->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
    }
    
    void
    VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                              const temporary_terms_type &temporary_terms) const
    {
      // If node is a temporary term
    #ifdef DEBUGC
      cout << "write_ouput output_type=" << output_type << "\n";
    #endif
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<VariableNode *>(this));
      if (it != temporary_terms.end())
        {
          if (output_type == oMatlabDynamicModelSparse)
            output << "T" << idx << "(it_)";
          else
            output << "T" << idx;
          return;
        }
    
      if (IS_LATEX(output_type))
        {
          output << datatree.symbol_table.getTeXName(symb_id);
          if (output_type == oLatexDynamicModel)
            {
              output << "_{t";
              if (lag != 0)
                {
                  if (lag > 0)
                    output << "+";
                  output << lag;
                }
              output << "}";
            }
          return;
        }
    
      int i;
      int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
      switch(type)
        {
        case eParameter:
          if (output_type == oMatlabOutsideModel)
            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 << "(";
              datatree.local_variables_table[symb_id]->writeOutput(output, output_type,temporary_terms);
              output << ")";
            }
          else
            output << datatree.symbol_table.getName(symb_id);
          break;
    
        case eEndogenous:
          switch(output_type)
            {
            case oMatlabDynamicModel:
            case oCDynamicModel:
              i = datatree.getDynJacobianCol(deriv_id) + ARRAY_SUBSCRIPT_OFFSET(output_type);
              output <<  "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              break;
            case oMatlabStaticModel:
            case oMatlabStaticModelSparse:
            case oCStaticModel:
              i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
              output <<  "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              break;
            case oMatlabDynamicModelSparse:
              i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
              if (lag > 0)
                output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              else if (lag < 0)
                output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              else
                output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              break;
            case oMatlabOutsideModel:
              output << "oo_.steady_state" << "(" << tsid + 1 << ")";
              break;
            default:
              assert(false);
            }
          break;
    
        case eExogenous:
          i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
          switch(output_type)
            {
            case oMatlabDynamicModel:
            case oMatlabDynamicModelSparse:
              if (lag > 0)
                output <<  "x(it_+" << lag << ", " << i << ")";
              else if (lag < 0)
                output <<  "x(it_" << lag << ", " << i << ")";
              else
                output <<  "x(it_, " << i << ")";
              break;
            case oCDynamicModel:
              if (lag == 0)
                output <<  "x[it_+" << i << "*nb_row_x]";
              else if (lag > 0)
                output <<  "x[it_+" << lag << "+" << i << "*nb_row_x]";
              else
                output <<  "x[it_" << lag << "+" << i << "*nb_row_x]";
              break;
            case oMatlabStaticModel:
            case oMatlabStaticModelSparse:
            case oCStaticModel:
              output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              break;
            case oMatlabOutsideModel:
              assert(lag == 0);
              output <<  "oo_.exo_steady_state" << "(" << i << ")";
              break;
            default:
              assert(false);
            }
          break;
    
        case eExogenousDet:
          i = tsid + datatree.symbol_table.exo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
          switch(output_type)
            {
            case oMatlabDynamicModel:
            case oMatlabDynamicModelSparse:
              if (lag > 0)
                output <<  "x(it_+" << lag << ", " << i << ")";
              else if (lag < 0)
                output <<  "x(it_" << lag << ", " << i << ")";
              else
                output <<  "x(it_, " << i << ")";
              break;
            case oCDynamicModel:
              if (lag == 0)
                output <<  "x[it_+" << i << "*nb_row_xd]";
              else if (lag > 0)
                output <<  "x[it_+" << lag << "+" << i << "*nb_row_xd]";
              else
                output <<  "x[it_" << lag << "+" << i << "*nb_row_xd]";
              break;
            case oMatlabStaticModel:
            case oMatlabStaticModelSparse:
            case oCStaticModel:
              output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
              break;
            case oMatlabOutsideModel:
              assert(lag == 0);
              output <<  "oo_.exo_det_steady_state" << "(" << tsid + 1 << ")";
              break;
            default:
              assert(false);
            }
          break;
    
        case eUnknownFunction:
          cerr << "Impossible case" << endl;
          exit(EXIT_FAILURE);
        }
    }
    
    double
    VariableNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      eval_context_type::const_iterator it = eval_context.find(symb_id);
      if (it == eval_context.end())
        throw EvalException();
    
      return it->second;
    }
    
    void
    VariableNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      int i, lagl;
    #ifdef DEBUGC
      cout << "output_type=" << output_type << "\n";
    #endif
      if(!lhs_rhs)
        CompileCode.write(&FLDV, sizeof(FLDV));
      else
        CompileCode.write(&FSTPV, sizeof(FSTPV));
      char typel=(char)type;
      CompileCode.write(&typel, sizeof(typel));
      int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
      switch(type)
        {
        case eParameter:
          i = tsid;
          CompileCode.write(reinterpret_cast<char *>(&i), sizeof(i));
    #ifdef DEBUGC
          cout << "FLD Param[ " << i << ", symb_id=" << symb_id << "]\n";
    #endif
          break;
        case eEndogenous :
          i = symb_id;
          CompileCode.write(reinterpret_cast<char *>(&i), sizeof(i));
          lagl=lag;
          CompileCode.write(reinterpret_cast<char *>(&lagl), sizeof(lagl));
          break;
        case eExogenous :
          i = tsid;
          CompileCode.write(reinterpret_cast<char *>(&i), sizeof(i));
          lagl=lag;
          CompileCode.write(reinterpret_cast<char *>(&lagl), sizeof(lagl));
          break;
        case eExogenousDet:
          i = tsid + datatree.symbol_table.exo_nbr();
          CompileCode.write(reinterpret_cast<char *>(&i), sizeof(i));
          lagl=lag;
          CompileCode.write(reinterpret_cast<char *>(&lagl), sizeof(lagl));
          break;
        case eModelLocalVariable:
        case eModFileLocalVariable:
          datatree.local_variables_table[symb_id]->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
          break;
        case eUnknownFunction:
          cerr << "Impossible case: eUnknownFuncion" << endl;
          exit(EXIT_FAILURE);
        }
    }
    
    void
    VariableNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                        temporary_terms_type &temporary_terms,
                                        map<NodeID, pair<int, int> > &first_occurence,
                                        int Curr_block,
                                        Model_Block *ModelBlock,
                                        int equation,
                                        map_idx_type &map_idx) const
    {
      if(type== eModelLocalVariable)
        datatree.local_variables_table[symb_id]->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
    }
    
    void
    VariableNode::collectEndogenous(set<pair<int, int> > &result) const
    {
      if (type == eEndogenous)
        result.insert(make_pair(symb_id, lag));
      else if (type == eModelLocalVariable)
        datatree.local_variables_table[symb_id]->collectEndogenous(result);
    }
    
    void
    VariableNode::collectExogenous(set<pair<int, int> > &result) const
    {
      if (type == eExogenous)
        result.insert(make_pair(symb_id, lag));
      else if (type == eModelLocalVariable)
        datatree.local_variables_table[symb_id]->collectExogenous(result);
    }
    
    NodeID
    VariableNode::toStatic(DataTree &static_datatree) const
    {
      return static_datatree.AddVariable(datatree.symbol_table.getName(symb_id));
    }
    
    
    UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, UnaryOpcode op_code_arg, const NodeID arg_arg) :
      ExprNode(datatree_arg),
      arg(arg_arg),
      op_code(op_code_arg)
    {
      // Add myself to the unary op map
      datatree.unary_op_node_map[make_pair(arg, op_code)] = this;
    
      // Non-null derivatives are those of the argument
      non_null_derivatives = arg->non_null_derivatives;
    }
    
    NodeID
    UnaryOpNode::computeDerivative(int deriv_id)
    {
      NodeID darg = arg->getDerivative(deriv_id);
    
      NodeID t11, t12, t13;
    
      switch(op_code)
        {
        case oUminus:
          return datatree.AddUMinus(darg);
        case oExp:
          return datatree.AddTimes(darg, this);
        case oLog:
          return datatree.AddDivide(darg, arg);
        case oLog10:
          t11 = datatree.AddExp(datatree.One);
          t12 = datatree.AddLog10(t11);
          t13 = datatree.AddDivide(darg, arg);
          return datatree.AddTimes(t12, t13);
        case oCos:
          t11 = datatree.AddSin(arg);
          t12 = datatree.AddUMinus(t11);
          return datatree.AddTimes(darg, t12);
        case oSin:
          t11 = datatree.AddCos(arg);
          return datatree.AddTimes(darg, t11);
        case oTan:
          t11 = datatree.AddTimes(this, this);
          t12 = datatree.AddPlus(t11, datatree.One);
          return datatree.AddTimes(darg, t12);
        case oAcos:
          t11 = datatree.AddSin(this);
          t12 = datatree.AddDivide(darg, t11);
          return datatree.AddUMinus(t12);
        case oAsin:
          t11 = datatree.AddCos(this);
          return datatree.AddDivide(darg, t11);
        case oAtan:
          t11 = datatree.AddTimes(arg, arg);
          t12 = datatree.AddPlus(datatree.One, t11);
          return datatree.AddDivide(darg, t12);
        case oCosh:
          t11 = datatree.AddSinh(arg);
          return datatree.AddTimes(darg, t11);
        case oSinh:
          t11 = datatree.AddCosh(arg);
          return datatree.AddTimes(darg, t11);
        case oTanh:
          t11 = datatree.AddTimes(this, this);
          t12 = datatree.AddMinus(datatree.One, t11);
          return datatree.AddTimes(darg, t12);
        case oAcosh:
          t11 = datatree.AddSinh(this);
          return datatree.AddDivide(darg, t11);
        case oAsinh:
          t11 = datatree.AddCosh(this);
          return datatree.AddDivide(darg, t11);
        case oAtanh:
          t11 = datatree.AddTimes(arg, arg);
          t12 = datatree.AddMinus(datatree.One, t11);
          return datatree.AddTimes(darg, t12);
        case oSqrt:
          t11 = datatree.AddPlus(this, this);
          return datatree.AddDivide(darg, t11);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    int
    UnaryOpNode::cost(const temporary_terms_type &temporary_terms, bool is_matlab) const
    {
      // For a temporary term, the cost is null
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode *>(this));
      if (it != temporary_terms.end())
        return 0;
    
      int cost = arg->cost(temporary_terms, is_matlab);
    
      if (is_matlab)
        // Cost for Matlab files
        switch(op_code)
          {
          case oUminus:
            return cost + 70;
          case oExp:
            return cost + 160;
          case oLog:
            return cost + 300;
          case oLog10:
            return cost + 16000;
          case oCos:
          case oSin:
          case oCosh:
            return cost + 210;
          case oTan:
            return cost + 230;
          case oAcos:
            return cost + 300;
          case oAsin:
            return cost + 310;
          case oAtan:
            return cost + 140;
          case oSinh:
            return cost + 240;
          case oTanh:
            return cost + 190;
          case oAcosh:
            return cost + 770;
          case oAsinh:
            return cost + 460;
          case oAtanh:
            return cost + 350;
          case oSqrt:
            return cost + 570;
          }
      else
        // Cost for C files
        switch(op_code)
          {
          case oUminus:
            return cost + 3;
          case oExp:
          case oAcosh:
            return cost + 210;
          case oLog:
            return cost + 137;
          case oLog10:
            return cost + 139;
          case oCos:
          case oSin:
            return cost + 160;
          case oTan:
            return cost + 170;
          case oAcos:
          case oAtan:
            return cost + 190;
          case oAsin:
            return cost + 180;
          case oCosh:
          case oSinh:
          case oTanh:
            return cost + 240;
          case oAsinh:
            return cost + 220;
          case oAtanh:
            return cost + 150;
          case oSqrt:
            return cost + 90;
          }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    void
    UnaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                       temporary_terms_type &temporary_terms,
                                       bool is_matlab) const
    {
      NodeID this2 = const_cast<UnaryOpNode *>(this);
    
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          reference_count[this2] = 1;
          arg->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
        }
      else
        {
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, is_matlab) > MIN_COST(is_matlab))
            temporary_terms.insert(this2);
        }
    }
    
    void
    UnaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                       temporary_terms_type &temporary_terms,
                                       map<NodeID, pair<int, int> > &first_occurence,
                                       int Curr_block,
                                       Model_Block *ModelBlock,
                                       int equation,
                                       map_idx_type &map_idx) const
    {
      NodeID this2 = const_cast<UnaryOpNode *>(this);
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          reference_count[this2] = 1;
          first_occurence[this2] = make_pair(Curr_block,equation);
          arg->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
        }
      else
        {
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, false) > MIN_COST_C)
            {
              temporary_terms.insert(this2);
              ModelBlock->Block_List[first_occurence[this2].first].Temporary_Terms_in_Equation[first_occurence[this2].second]->insert(this2);
            }
        }
    }
    
    void
    UnaryOpNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode*>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
      else
        arg->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
    }
    
    void
    UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                             const temporary_terms_type &temporary_terms) const
    {
      // If node is a temporary term
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          if (output_type == oMatlabDynamicModelSparse)
            output << "T" << idx << "(it_)";
          else
            output << "T" << idx;
          return;
        }
    
      // Always put parenthesis around uminus nodes
      if (op_code == oUminus)
        output << LEFT_PAR(output_type);
    
      switch(op_code)
        {
        case oUminus:
          output << "-";
          break;
        case oExp:
          output << "exp";
          break;
        case oLog:
          output << "log";
          break;
        case oLog10:
          if (IS_LATEX(output_type))
            output << "log_{10}";
          else
            output << "log10";
          break;
        case oCos:
          output << "cos";
          break;
        case oSin:
          output << "sin";
          break;
        case oTan:
          output << "tan";
          break;
        case oAcos:
          output << "acos";
          break;
        case oAsin:
          output << "asin";
          break;
        case oAtan:
          output << "atan";
          break;
        case oCosh:
          output << "cosh";
          break;
        case oSinh:
          output << "sinh";
          break;
        case oTanh:
          output << "tanh";
          break;
        case oAcosh:
          output << "acosh";
          break;
        case oAsinh:
          output << "asinh";
          break;
        case oAtanh:
          output << "atanh";
          break;
        case oSqrt:
          output << "sqrt";
          break;
        }
    
      bool close_parenthesis = false;
    
      /* Enclose argument with parentheses if:
         - current opcode is not uminus, or
         - current opcode is uminus and argument has lowest precedence
      */
      if (op_code != oUminus
          || (op_code == oUminus
              && arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms)))
        {
          output << LEFT_PAR(output_type);
          close_parenthesis = true;
        }
    
      // Write argument
      arg->writeOutput(output, output_type, temporary_terms);
    
      if (close_parenthesis)
        output << RIGHT_PAR(output_type);
    
      // Close parenthesis for uminus
      if (op_code == oUminus)
        output << RIGHT_PAR(output_type);
    }
    
    double
    UnaryOpNode::eval_opcode(UnaryOpcode op_code, double v) throw (EvalException)
    {
      switch(op_code)
        {
        case oUminus:
          return(-v);
        case oExp:
          return(exp(v));
        case oLog:
          return(log(v));
        case oLog10:
          return(log10(v));
        case oCos:
          return(cos(v));
        case oSin:
          return(sin(v));
        case oTan:
          return(tan(v));
        case oAcos:
          return(acos(v));
        case oAsin:
          return(asin(v));
        case oAtan:
          return(atan(v));
        case oCosh:
          return(cosh(v));
        case oSinh:
          return(sinh(v));
        case oTanh:
          return(tanh(v));
        case oAcosh:
          return(acosh(v));
        case oAsinh:
          return(asinh(v));
        case oAtanh:
          return(atanh(v));
        case oSqrt:
          return(sqrt(v));
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    double
    UnaryOpNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      double v = arg->eval(eval_context);
    
      return eval_opcode(op_code, v);
    }
    
    void
    UnaryOpNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          CompileCode.write(&FLDT, sizeof(FLDT));
          int var=map_idx[idx];
          CompileCode.write(reinterpret_cast<char *>(&var), sizeof(var));
          return;
        }
      arg->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      CompileCode.write(&FUNARY, sizeof(FUNARY));
      UnaryOpcode op_codel=op_code;
      CompileCode.write(reinterpret_cast<char *>(&op_codel), sizeof(op_codel));
    }
    
    void
    UnaryOpNode::collectEndogenous(set<pair<int, int> > &result) const
    {
      arg->collectEndogenous(result);
    }
    
    void
    UnaryOpNode::collectExogenous(set<pair<int, int> > &result) const
    {
      arg->collectExogenous(result);
    }
    
    NodeID
    UnaryOpNode::toStatic(DataTree &static_datatree) const
    {
      NodeID sarg = arg->toStatic(static_datatree);
      switch(op_code)
        {
        case oUminus:
          return static_datatree.AddUMinus(sarg);
        case oExp:
          return static_datatree.AddExp(sarg);
        case oLog:
          return static_datatree.AddLog(sarg);
        case oLog10:
          return static_datatree.AddLog10(sarg);
        case oCos:
          return static_datatree.AddCos(sarg);
        case oSin:
          return static_datatree.AddSin(sarg);
        case oTan:
          return static_datatree.AddTan(sarg);
        case oAcos:
          return static_datatree.AddAcos(sarg);
        case oAsin:
          return static_datatree.AddAsin(sarg);
        case oAtan:
          return static_datatree.AddAtan(sarg);
        case oCosh:
          return static_datatree.AddCosh(sarg);
        case oSinh:
          return static_datatree.AddSinh(sarg);
        case oTanh:
          return static_datatree.AddTanh(sarg);
        case oAcosh:
          return static_datatree.AddAcosh(sarg);
        case oAsinh:
          return static_datatree.AddAsinh(sarg);
        case oAtanh:
          return static_datatree.AddAtanh(sarg);
        case oSqrt:
          return static_datatree.AddSqrt(sarg);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    
    BinaryOpNode::BinaryOpNode(DataTree &datatree_arg, const NodeID arg1_arg,
                               BinaryOpcode op_code_arg, const NodeID arg2_arg) :
      ExprNode(datatree_arg),
      arg1(arg1_arg),
      arg2(arg2_arg),
      op_code(op_code_arg)
    {
      datatree.binary_op_node_map[make_pair(make_pair(arg1, arg2), op_code)] = this;
    
      // Non-null derivatives are the union of those of the arguments
      // Compute set union of arg1->non_null_derivatives and arg2->non_null_derivatives
      set_union(arg1->non_null_derivatives.begin(),
                arg1->non_null_derivatives.end(),
                arg2->non_null_derivatives.begin(),
                arg2->non_null_derivatives.end(),
                inserter(non_null_derivatives, non_null_derivatives.begin()));
    }
    
    NodeID
    BinaryOpNode::computeDerivative(int deriv_id)
    {
      NodeID darg1 = arg1->getDerivative(deriv_id);
      NodeID darg2 = arg2->getDerivative(deriv_id);
    
      NodeID t11, t12, t13, t14, t15;
    
      switch(op_code)
        {
        case oPlus:
          return datatree.AddPlus(darg1, darg2);
        case oMinus:
          return datatree.AddMinus(darg1, darg2);
        case oTimes:
          t11 = datatree.AddTimes(darg1, arg2);
          t12 = datatree.AddTimes(darg2, arg1);
          return datatree.AddPlus(t11, t12);
        case oDivide:
          t11 = datatree.AddTimes(darg1, arg2);
          t12 = datatree.AddTimes(darg2, arg1);
          t13 = datatree.AddMinus(t11, t12);
          t14 = datatree.AddTimes(arg2, arg2);
          return datatree.AddDivide(t13, t14);
        case oLess:
        case oGreater:
        case oLessEqual:
        case oGreaterEqual:
        case oEqualEqual:
        case oDifferent:
          return datatree.Zero;
        case oPower:
          if (darg2 == datatree.Zero)
            {
              if (darg1 == datatree.Zero)
                return datatree.Zero;
              else
                {
                  t11 = datatree.AddMinus(arg2, datatree.One);
                  t12 = datatree.AddPower(arg1, t11);
                  t13 = datatree.AddTimes(arg2, t12);
                  return datatree.AddTimes(darg1, t13);
                }
            }
          else
            {
              t11 = datatree.AddLog(arg1);
              t12 = datatree.AddTimes(darg2, t11);
              t13 = datatree.AddTimes(darg1, arg2);
              t14 = datatree.AddDivide(t13, arg1);
              t15 = datatree.AddPlus(t12, t14);
              return datatree.AddTimes(t15, this);
            }
        case oMax:
          t11 = datatree.AddGreater(arg1,arg2);
          t12 = datatree.AddTimes(t11,darg1);
          t13 = datatree.AddMinus(datatree.One,t11);
          t14 = datatree.AddTimes(t13,darg2);
          return datatree.AddPlus(t14,t12);
        case oMin:
          t11 = datatree.AddGreater(arg2,arg1);
          t12 = datatree.AddTimes(t11,darg1);
          t13 = datatree.AddMinus(datatree.One,t11);
          t14 = datatree.AddTimes(t13,darg2);
          return datatree.AddPlus(t14,t12);
        case oEqual:
          return datatree.AddMinus(darg1, darg2);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    int
    BinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
      // A temporary term behaves as a variable
      if (it != temporary_terms.end())
        return 100;
    
      switch(op_code)
        {
        case oEqual:
          return 0;
        case oEqualEqual:
        case oDifferent:
          return 1;
        case oLessEqual:
        case oGreaterEqual:
        case oLess:
        case oGreater:
          return 2;
        case oPlus:
        case oMinus:
          return 3;
        case oTimes:
        case oDivide:
          return 4;
        case oPower:
          if (IS_C(output_type))
            // In C, power operator is of the form pow(a, b)
            return 100;
          else
            return 5;
        case oMin:
        case oMax:
          return 100;
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    int
    BinaryOpNode::cost(const temporary_terms_type &temporary_terms, bool is_matlab) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
      // For a temporary term, the cost is null
      if (it != temporary_terms.end())
        return 0;
    
      int cost = arg1->cost(temporary_terms, is_matlab);
      cost += arg2->cost(temporary_terms, is_matlab);
    
      if (is_matlab)
        // Cost for Matlab files
        switch(op_code)
          {
          case oLess:
          case oGreater:
          case oLessEqual:
          case oGreaterEqual:
          case oEqualEqual:
          case oDifferent:
            return cost + 60;
          case oPlus:
          case oMinus:
          case oTimes:
            return cost + 90;
          case oMax:
          case oMin:
            return cost + 110;
          case oDivide:
            return cost + 990;
          case oPower:
            return cost + 1160;
          case oEqual:
            return cost;
          }
      else
        // Cost for C files
        switch(op_code)
          {
          case oLess:
          case oGreater:
          case oLessEqual:
          case oGreaterEqual:
          case oEqualEqual:
          case oDifferent:
            return cost + 2;
          case oPlus:
          case oMinus:
          case oTimes:
            return cost + 4;
          case oMax:
          case oMin:
    	return cost + 5;
          case oDivide:
            return cost + 15;
          case oPower:
            return cost + 520;
          case oEqual:
            return cost;
          }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    void
    BinaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                        temporary_terms_type &temporary_terms,
                                        bool is_matlab) const
    {
      NodeID this2 = const_cast<BinaryOpNode *>(this);
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          // If this node has never been encountered, set its ref count to one,
          //  and travel through its children
          reference_count[this2] = 1;
          arg1->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
          arg2->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
        }
      else
        {
          // If the node has already been encountered, increment its ref count
          //  and declare it as a temporary term if it is too costly
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, is_matlab) > MIN_COST(is_matlab))
            temporary_terms.insert(this2);
        }
    }
    
    void
    BinaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                        temporary_terms_type &temporary_terms,
                                        map<NodeID, pair<int, int> > &first_occurence,
                                        int Curr_block,
                                        Model_Block *ModelBlock,
                                        int equation,
                                        map_idx_type &map_idx) const
    {
      NodeID this2 = const_cast<BinaryOpNode *>(this);
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          reference_count[this2] = 1;
          first_occurence[this2] = make_pair(Curr_block, equation);
          arg1->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
          arg2->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
        }
      else
        {
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, false) > MIN_COST_C)
            {
              temporary_terms.insert(this2);
              ModelBlock->Block_List[first_occurence[this2].first].Temporary_Terms_in_Equation[first_occurence[this2].second]->insert(this2);
            }
        }
    }
    
    double
    BinaryOpNode::eval_opcode(double v1, BinaryOpcode op_code, double v2) throw (EvalException)
    {
      switch(op_code)
        {
        case oPlus:
          return(v1 + v2);
        case oMinus:
          return(v1 - v2);
        case oTimes:
          return(v1 * v2);
        case oDivide:
          return(v1 / v2);
        case oPower:
          return(pow(v1, v2));
        case oMax:
          if (v1 < v2)
            return v2;
          else
            return v1;
        case oMin:
          if (v1 > v2)
            return v2;
          else
            return v1;
        case oLess:
          return (v1 < v2);
        case oGreater:
          return (v1 > v2);
        case oLessEqual:
          return (v1 <= v2);
        case oGreaterEqual:
          return (v1 >= v2);
        case oEqualEqual:
          return (v1 == v2);
        case oDifferent:
          return (v1 != v2);
        case oEqual:
          throw EvalException();
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    double
    BinaryOpNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      double v1 = arg1->eval(eval_context);
      double v2 = arg2->eval(eval_context);
    
      return eval_opcode(v1, op_code, v2);
    }
    
    void
    BinaryOpNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      // If current node is a temporary term
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          CompileCode.write(&FLDT, sizeof(FLDT));
          int var=map_idx[idx];
          CompileCode.write(reinterpret_cast<char *>(&var), sizeof(var));
          return;
        }
      arg1->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      arg2->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      CompileCode.write(&FBINARY, sizeof(FBINARY));
      BinaryOpcode op_codel=op_code;
      CompileCode.write(reinterpret_cast<char *>(&op_codel),sizeof(op_codel));
    }
    
    void
    BinaryOpNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
      else
        {
          arg1->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
          arg2->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
        }
    }
    
    
    void
    BinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                              const temporary_terms_type &temporary_terms) const
    {
      // If current node is a temporary term
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<BinaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          if (output_type == oMatlabDynamicModelSparse)
            output << "T" << idx << "(it_)";
          else
            output << "T" << idx;
          return;
        }
    
      // Treat special case of power operator in C, and case of max and min operators
      if ((op_code == oPower && IS_C(output_type)) || op_code == oMax || op_code == oMin )
        {
          switch (op_code)
            {
            case oPower:
              output << "pow(";
              break;
            case oMax:
              output << "max(";
              break;
            case oMin:
              output << "min(";
              break;
            default:
              ;
            }
          arg1->writeOutput(output, output_type, temporary_terms);
          output << ",";
          arg2->writeOutput(output, output_type, temporary_terms);
          output << ")";
          return;
        }
    
      int prec = precedence(output_type, temporary_terms);
    
      bool close_parenthesis = false;
    
      if (IS_LATEX(output_type) && op_code == oDivide)
        output << "\\frac{";
      else
        {
          // If left argument has a lower precedence, or if current and left argument are both power operators, add parenthesis around left argument
          BinaryOpNode *barg1 = dynamic_cast<BinaryOpNode *>(arg1);
          if (arg1->precedence(output_type, temporary_terms) < prec
              || (op_code == oPower && barg1 != NULL && barg1->op_code == oPower))
            {
              output << LEFT_PAR(output_type);
              close_parenthesis = true;
            }
        }
    
      // Write left argument
      arg1->writeOutput(output, output_type, temporary_terms);
    
      if (close_parenthesis)
        output << RIGHT_PAR(output_type);
    
      if (IS_LATEX(output_type) && op_code == oDivide)
        output << "}";
    
    
      // Write current operator symbol
      switch(op_code)
        {
        case oPlus:
          output << "+";
          break;
        case oMinus:
          output << "-";
          break;
        case oTimes:
          if (IS_LATEX(output_type))
            output << "\\cdot ";
          else
            output << "*";
          break;
        case oDivide:
          if (!IS_LATEX(output_type))
            output << "/";
          break;
        case oPower:
          output << "^";
          break;
        case oLess:
          output << "<";
          break;
        case oGreater:
          output << ">";
          break;
        case oLessEqual:
          if (IS_LATEX(output_type))
            output << "\\leq ";
          else
            output << "<=";
          break;
        case oGreaterEqual:
          if (IS_LATEX(output_type))
            output << "\\geq ";
          else
            output << ">=";
          break;
        case oEqualEqual:
          output << "==";
          break;
        case oDifferent:
          if (IS_MATLAB(output_type))
            output << "~=";
          else
            {
              if (IS_C(output_type))
                output << "!=";
              else
                output << "\\neq ";
            }
          break;
        case oEqual:
          output << "=";
          break;
        default:
          ;
        }
    
      close_parenthesis = false;
    
      if (IS_LATEX(output_type) && (op_code == oPower || op_code == oDivide))
        output << "{";
      else
        {
          /* Add parenthesis around right argument if:
             - its precedence is lower than those of the current node
             - it is a power operator and current operator is also a power operator
             - it is a minus operator with same precedence than current operator
             - it is a divide operator with same precedence than current operator */
          BinaryOpNode *barg2 = dynamic_cast<BinaryOpNode *>(arg2);
          int arg2_prec = arg2->precedence(output_type, temporary_terms);
          if (arg2_prec < prec
              || (op_code == oPower && barg2 != NULL && barg2->op_code == oPower && !IS_LATEX(output_type))
              || (op_code == oMinus && arg2_prec == prec)
              || (op_code == oDivide && arg2_prec == prec && !IS_LATEX(output_type)))
            {
              output << LEFT_PAR(output_type);
              close_parenthesis = true;
            }
        }
    
      // Write right argument
      arg2->writeOutput(output, output_type, temporary_terms);
    
      if (IS_LATEX(output_type) && (op_code == oPower || op_code == oDivide))
        output << "}";
    
      if (close_parenthesis)
        output << RIGHT_PAR(output_type);
    }
    
    void
    BinaryOpNode::collectEndogenous(set<pair<int, int> > &result) const
    {
      arg1->collectEndogenous(result);
      arg2->collectEndogenous(result);
    }
    
    void
    BinaryOpNode::collectExogenous(set<pair<int, int> > &result) const
    {
      arg1->collectExogenous(result);
      arg2->collectExogenous(result);
    }
    
    NodeID
    BinaryOpNode::toStatic(DataTree &static_datatree) const
    {
      NodeID sarg1 = arg1->toStatic(static_datatree);
      NodeID sarg2 = arg2->toStatic(static_datatree);
      switch(op_code)
        {
        case oPlus:
          return static_datatree.AddPlus(sarg1, sarg2);
        case oMinus:
          return static_datatree.AddMinus(sarg1, sarg2);
        case oTimes:
          return static_datatree.AddTimes(sarg1, sarg2);
        case oDivide:
          return static_datatree.AddDivide(sarg1, sarg2);
        case oPower:
          return static_datatree.AddPower(sarg1, sarg2);
        case oEqual:
          return static_datatree.AddEqual(sarg1, sarg2);
        case oMax:
          return static_datatree.AddMax(sarg1, sarg2);
        case oMin:
          return static_datatree.AddMin(sarg1, sarg2);
        case oLess:
          return static_datatree.AddLess(sarg1, sarg2);
        case oGreater:
          return static_datatree.AddGreater(sarg1, sarg2);
        case oLessEqual:
          return static_datatree.AddLessEqual(sarg1, sarg2);
        case oGreaterEqual:
          return static_datatree.AddGreaterEqual(sarg1, sarg2);
        case oEqualEqual:
          return static_datatree.AddEqualEqual(sarg1, sarg2);
        case oDifferent:
          return static_datatree.AddDifferent(sarg1, sarg2);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    
    TrinaryOpNode::TrinaryOpNode(DataTree &datatree_arg, const NodeID arg1_arg,
                                 TrinaryOpcode op_code_arg, const NodeID arg2_arg, const NodeID arg3_arg) :
      ExprNode(datatree_arg),
      arg1(arg1_arg),
      arg2(arg2_arg),
      arg3(arg3_arg),
      op_code(op_code_arg)
    {
      datatree.trinary_op_node_map[make_pair(make_pair(make_pair(arg1, arg2), arg3), op_code)] = this;
    
      // Non-null derivatives are the union of those of the arguments
      // Compute set union of arg{1,2,3}->non_null_derivatives
      set<int> non_null_derivatives_tmp;
      set_union(arg1->non_null_derivatives.begin(),
                arg1->non_null_derivatives.end(),
                arg2->non_null_derivatives.begin(),
                arg2->non_null_derivatives.end(),
                inserter(non_null_derivatives_tmp, non_null_derivatives_tmp.begin()));
      set_union(non_null_derivatives_tmp.begin(),
                non_null_derivatives_tmp.end(),
                arg3->non_null_derivatives.begin(),
                arg3->non_null_derivatives.end(),
                inserter(non_null_derivatives, non_null_derivatives.begin()));
    }
    
    NodeID
    TrinaryOpNode::computeDerivative(int deriv_id)
    {
      NodeID darg1 = arg1->getDerivative(deriv_id);
      NodeID darg2 = arg2->getDerivative(deriv_id);
      NodeID darg3 = arg3->getDerivative(deriv_id);
    
      NodeID t11, t12, t13, t14, t15;
    
      switch(op_code)
        {
        case oNormcdf:
          // normal pdf is inlined in the tree
          NodeID y;
          // sqrt(2*pi)
          t14 = datatree.AddSqrt(datatree.AddTimes(datatree.Two, datatree.Pi));
          // x - mu
          t12 = datatree.AddMinus(arg1,arg2);
          // y = (x-mu)/sigma
          y = datatree.AddDivide(t12,arg3);
          // (x-mu)^2/sigma^2
          t12 = datatree.AddTimes(y,y);
          // -(x-mu)^2/sigma^2
          t13 = datatree.AddUMinus(t12);
          // -((x-mu)^2/sigma^2)/2
          t12 = datatree.AddDivide(t13, datatree.Two);
          // exp(-((x-mu)^2/sigma^2)/2)
          t13 = datatree.AddExp(t12);
          // derivative of a standardized normal
          // t15 = (1/sqrt(2*pi))*exp(-y^2/2)
          t15 = datatree.AddDivide(t13,t14);
          // derivatives thru x
          t11 = datatree.AddDivide(darg1,arg3);
          // derivatives thru mu
          t12 = datatree.AddDivide(darg2,arg3);
          // intermediary sum
          t14 = datatree.AddMinus(t11,t12);
          // derivatives thru sigma
          t11 = datatree.AddDivide(y,arg3);
          t12 = datatree.AddTimes(t11,darg3);
          //intermediary sum
          t11 = datatree.AddMinus(t14,t12);
          // total derivative:
          // (darg1/sigma - darg2/sigma - darg3*(x-mu)/sigma^2) * t15
          // where t15 is the derivative of a standardized normal
          return datatree.AddTimes(t11, t15);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    int
    TrinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_type &temporary_terms) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
      // A temporary term behaves as a variable
      if (it != temporary_terms.end())
        return 100;
    
      switch(op_code)
        {
        case oNormcdf:
          return 100;
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    int
    TrinaryOpNode::cost(const temporary_terms_type &temporary_terms, bool is_matlab) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
      // For a temporary term, the cost is null
      if (it != temporary_terms.end())
        return 0;
    
      int cost = arg1->cost(temporary_terms, is_matlab);
      cost += arg2->cost(temporary_terms, is_matlab);
    
      if (is_matlab)
        // Cost for Matlab files
        switch(op_code)
          {
          case oNormcdf:
            return cost+1000;
          }
      else
        // Cost for C files
        switch(op_code)
          {
          case oNormcdf:
            return cost+1000;
          }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    void
    TrinaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                         temporary_terms_type &temporary_terms,
                                         bool is_matlab) const
    {
      NodeID this2 = const_cast<TrinaryOpNode *>(this);
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          // If this node has never been encountered, set its ref count to one,
          //  and travel through its children
          reference_count[this2] = 1;
          arg1->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
          arg2->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
          arg3->computeTemporaryTerms(reference_count, temporary_terms, is_matlab);
        }
      else
        {
          // If the node has already been encountered, increment its ref count
          //  and declare it as a temporary term if it is too costly
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, is_matlab) > MIN_COST(is_matlab))
            temporary_terms.insert(this2);
        }
    }
    
    void
    TrinaryOpNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                         temporary_terms_type &temporary_terms,
                                         map<NodeID, pair<int, int> > &first_occurence,
                                         int Curr_block,
                                         Model_Block *ModelBlock,
                                         int equation,
                                         map_idx_type &map_idx) const
    {
      NodeID this2 = const_cast<TrinaryOpNode *>(this);
      map<NodeID, int>::iterator it = reference_count.find(this2);
      if (it == reference_count.end())
        {
          reference_count[this2] = 1;
          first_occurence[this2] = make_pair(Curr_block,equation);
          arg1->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
          arg2->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
          arg3->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, ModelBlock, equation, map_idx);
        }
      else
        {
          reference_count[this2]++;
          if (reference_count[this2] * cost(temporary_terms, false) > MIN_COST_C)
            {
              temporary_terms.insert(this2);
              ModelBlock->Block_List[first_occurence[this2].first].Temporary_Terms_in_Equation[first_occurence[this2].second]->insert(this2);
            }
        }
    }
    
    double
    TrinaryOpNode::eval_opcode(double v1, TrinaryOpcode op_code, double v2, double v3) throw (EvalException)
    {
      switch(op_code)
        {
        case oNormcdf:
          cerr << "NORMCDF: eval not implemented" << endl;
          exit(EXIT_FAILURE);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    double
    TrinaryOpNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      double v1 = arg1->eval(eval_context);
      double v2 = arg2->eval(eval_context);
      double v3 = arg3->eval(eval_context);
    
      return eval_opcode(v1, op_code, v2, v3);
    }
    
    void
    TrinaryOpNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      // If current node is a temporary term
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          CompileCode.write(&FLDT, sizeof(FLDT));
          int var=map_idx[idx];
          CompileCode.write(reinterpret_cast<char *>(&var), sizeof(var));
          return;
        }
      arg1->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      arg2->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      arg3->compile(CompileCode, lhs_rhs, temporary_terms, map_idx);
      CompileCode.write(&FBINARY, sizeof(FBINARY));
      TrinaryOpcode op_codel=op_code;
      CompileCode.write(reinterpret_cast<char *>(&op_codel),sizeof(op_codel));
    }
    
    void
    TrinaryOpNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
      else
        {
          arg1->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
          arg2->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
          arg3->collectTemporary_terms(temporary_terms, ModelBlock, Curr_Block);
        }
    }
    
    
    void
    TrinaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                               const temporary_terms_type &temporary_terms) const
    {
      // TrinaryOpNode not implemented for C output
      assert(!IS_C(output_type));
    
      // If current node is a temporary term
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<TrinaryOpNode *>(this));
      if (it != temporary_terms.end())
        {
          output << "T" << idx;
          return;
        }
    
      switch (op_code)
        {
        case oNormcdf:
          output << "normcdf(";
          break;
        }
      arg1->writeOutput(output, output_type, temporary_terms);
      output << ",";
      arg2->writeOutput(output, output_type, temporary_terms);
      output << ",";
      arg3->writeOutput(output, output_type, temporary_terms);
      output << ")";
    }
    
    void
    TrinaryOpNode::collectEndogenous(set<pair<int, int> > &result) const
    {
      arg1->collectEndogenous(result);
      arg2->collectEndogenous(result);
      arg3->collectEndogenous(result);
    }
    
    void
    TrinaryOpNode::collectExogenous(set<pair<int, int> > &result) const
    {
      arg1->collectExogenous(result);
      arg2->collectExogenous(result);
      arg3->collectExogenous(result);
    }
    
    NodeID
    TrinaryOpNode::toStatic(DataTree &static_datatree) const
    {
      NodeID sarg1 = arg1->toStatic(static_datatree);
      NodeID sarg2 = arg2->toStatic(static_datatree);
      NodeID sarg3 = arg3->toStatic(static_datatree);
      switch(op_code)
        {
        case oNormcdf:
          return static_datatree.AddNormcdf(sarg1, sarg2, sarg3);
        }
      // Suppress GCC warning
      exit(EXIT_FAILURE);
    }
    
    
    UnknownFunctionNode::UnknownFunctionNode(DataTree &datatree_arg,
                                             int symb_id_arg,
                                             const vector<NodeID> &arguments_arg) :
      ExprNode(datatree_arg),
      symb_id(symb_id_arg),
      arguments(arguments_arg)
    {
    }
    
    NodeID
    UnknownFunctionNode::computeDerivative(int deriv_id)
    {
      cerr << "UnknownFunctionNode::computeDerivative: operation impossible!" << endl;
      exit(EXIT_FAILURE);
    }
    
    void
    UnknownFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                               temporary_terms_type &temporary_terms,
                                               bool is_matlab) const
    {
      cerr << "UnknownFunctionNode::computeTemporaryTerms: operation impossible!" << endl;
      exit(EXIT_FAILURE);
    }
    
    void UnknownFunctionNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
                                          const temporary_terms_type &temporary_terms) const
    {
      output << datatree.symbol_table.getName(symb_id) << "(";
      for(vector<NodeID>::const_iterator it = arguments.begin();
          it != arguments.end(); it++)
        {
          if (it != arguments.begin())
            output << ",";
    
          (*it)->writeOutput(output, output_type, temporary_terms);
        }
      output << ")";
    }
    
    void
    UnknownFunctionNode::computeTemporaryTerms(map<NodeID, int> &reference_count,
                                               temporary_terms_type &temporary_terms,
                                               map<NodeID, pair<int, int> > &first_occurence,
                                               int Curr_block,
                                               Model_Block *ModelBlock,
                                               int equation,
                                               map_idx_type &map_idx) const
    {
      cerr << "UnknownFunctionNode::computeTemporaryTerms: not implemented" << endl;
      exit(EXIT_FAILURE);
    }
    
    void
    UnknownFunctionNode::collectEndogenous(set<pair<int, int> > &result) const
    {
      for(vector<NodeID>::const_iterator it = arguments.begin();
          it != arguments.end(); it++)
        (*it)->collectEndogenous(result);
    }
    
    void
    UnknownFunctionNode::collectExogenous(set<pair<int, int> > &result) const
    {
      for(vector<NodeID>::const_iterator it = arguments.begin();
          it != arguments.end(); it++)
        (*it)->collectExogenous(result);
    }
    
    void
    UnknownFunctionNode::collectTemporary_terms(const temporary_terms_type &temporary_terms, Model_Block *ModelBlock, int Curr_Block) const
    {
      temporary_terms_type::const_iterator it = temporary_terms.find(const_cast<UnknownFunctionNode *>(this));
      if (it != temporary_terms.end())
        ModelBlock->Block_List[Curr_Block].Temporary_InUse->insert(idx);
      else
        {
          //arg->collectTemporary_terms(temporary_terms, result);
        }
    }
    
    
    double
    UnknownFunctionNode::eval(const eval_context_type &eval_context) const throw (EvalException)
    {
      throw EvalException();
    }
    
    void
    UnknownFunctionNode::compile(ofstream &CompileCode, bool lhs_rhs, const temporary_terms_type &temporary_terms, map_idx_type &map_idx) const
    {
      cerr << "UnknownFunctionNode::compile: operation impossible!" << endl;
      exit(EXIT_FAILURE);
    }
    
    NodeID
    UnknownFunctionNode::toStatic(DataTree &static_datatree) const
    {
      vector<NodeID> static_arguments;
      for(vector<NodeID>::const_iterator it = arguments.begin();
          it != arguments.end(); it++)
        static_arguments.push_back((*it)->toStatic(static_datatree));
      return static_datatree.AddUnknownFunction(datatree.symbol_table.getName(symb_id), static_arguments);
    }