ExprNode.hh 99.8 KB
Newer Older
1
/*
2
 * Copyright © 2007-2019 Dynare Team
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * 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/>.
 */

#ifndef _EXPR_NODE_HH
#define _EXPR_NODE_HH

#include <set>
#include <map>
#include <vector>
26
#include <ostream>
27
#include <functional>
28

29 30
using namespace std;

31 32
#include "SymbolTable.hh"
#include "CodeInterpreter.hh"
33
#include "ExternalFunctionsTable.hh"
34
#include "SymbolList.hh"
35 36

class DataTree;
37
class NumConstNode;
sebastien's avatar
sebastien committed
38
class VariableNode;
39
class UnaryOpNode;
sebastien's avatar
sebastien committed
40
class BinaryOpNode;
41
class PacExpectationNode;
42

43
using expr_t = class ExprNode *;
44 45 46 47

struct ExprNodeLess;

//! Type for set of temporary terms
48 49
/*! The ExprNodeLess ordering is important for the temporary terms algorithm,
    see the definition of ExprNodeLess */
50
using temporary_terms_t = set<expr_t, ExprNodeLess>;
Houtan Bastani's avatar
Houtan Bastani committed
51
/*! Keeps track of array indices of temporary_terms for writing */
52
using temporary_terms_idxs_t = map<expr_t, int>;
53

54
//! set of temporary terms used in a block
55
using temporary_terms_inuse_t = set<int>;
56

57
using map_idx_t = map<int, int>;
58

59 60
//! Type for evaluation contexts
/*! The key is a symbol id. Lags are assumed to be null */
61
using eval_context_t = map<int, double>;
62

63
//! Type for tracking first/second derivative functions that have already been written as temporary terms
64
using deriv_node_temp_terms_t = map<pair<int, vector<expr_t>>, int>;
65

66
//! Type for the substitution map used in the process of substitutitng diff expressions
67
//! diff_table[static_expr_t][lag] -> [dynamic_expr_t]
68
using diff_table_t = map<expr_t, map<int, expr_t>>;
69

70
//! Possible types of output when writing ExprNode(s)
71
enum class ExprNodeOutputType
72
  {
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    matlabStaticModel,                           //!< Matlab code, static model
    matlabDynamicModel,                          //!< Matlab code, dynamic model
    matlabStaticModelSparse,                     //!< Matlab code, static block decomposed model
    matlabDynamicModelSparse,                    //!< Matlab code, dynamic block decomposed model
    CDynamicModel,                               //!< C code, dynamic model
    CStaticModel,                                //!< C code, static model
    juliaStaticModel,                            //!< Julia code, static model
    juliaDynamicModel,                           //!< Julia code, dynamic model
    matlabOutsideModel,                          //!< Matlab code, outside model block (for example in initval)
    latexStaticModel,                            //!< LaTeX code, static model
    latexDynamicModel,                           //!< LaTeX code, dynamic model
    latexDynamicSteadyStateOperator,             //!< LaTeX code, dynamic model, inside a steady state operator
    matlabDynamicSteadyStateOperator,            //!< Matlab code, dynamic model, inside a steady state operator
    matlabDynamicSparseSteadyStateOperator,      //!< Matlab code, dynamic block decomposed model, inside a steady state operator
    CDynamicSteadyStateOperator,                 //!< C code, dynamic model, inside a steady state operator
    juliaDynamicSteadyStateOperator,             //!< Julia code, dynamic model, inside a steady state operator
    steadyStateFile,                             //!< Matlab code, in the generated steady state file
    juliaSteadyStateFile,                        //!< Julia code, in the generated steady state file
    matlabDseries,                               //!< Matlab code for dseries
    epilogueFile                                 //!< Matlab code, in the generated epilogue file
93 94
  };

95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
inline bool
isMatlabOutput(ExprNodeOutputType output_type)
{
  return output_type == ExprNodeOutputType::matlabStaticModel
    || output_type == ExprNodeOutputType::matlabDynamicModel
    || output_type == ExprNodeOutputType::matlabOutsideModel
    || output_type == ExprNodeOutputType::matlabStaticModelSparse
    || output_type == ExprNodeOutputType::matlabDynamicModelSparse
    || output_type == ExprNodeOutputType::matlabDynamicSteadyStateOperator
    || output_type == ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator
    || output_type == ExprNodeOutputType::steadyStateFile
    || output_type == ExprNodeOutputType::matlabDseries
    || output_type == ExprNodeOutputType::epilogueFile;
}

inline bool
isJuliaOutput(ExprNodeOutputType output_type)
{
  return output_type == ExprNodeOutputType::juliaStaticModel
    || output_type == ExprNodeOutputType::juliaDynamicModel
    || output_type == ExprNodeOutputType::juliaDynamicSteadyStateOperator
    || output_type == ExprNodeOutputType::juliaSteadyStateFile;
}

inline bool
isCOutput(ExprNodeOutputType output_type)
{
  return output_type == ExprNodeOutputType::CDynamicModel
    || output_type == ExprNodeOutputType::CStaticModel
    || output_type == ExprNodeOutputType::CDynamicSteadyStateOperator;
}

inline bool
isLatexOutput(ExprNodeOutputType output_type)
{
  return output_type == ExprNodeOutputType::latexStaticModel
    || output_type == ExprNodeOutputType::latexDynamicModel
    || output_type == ExprNodeOutputType::latexDynamicSteadyStateOperator;
}
134

Houtan Bastani's avatar
Houtan Bastani committed
135 136
/* Equal to 1 for Matlab langage or Julia, or to 0 for C language. Not defined for LaTeX.
   In Matlab and Julia, array indexes begin at 1, while they begin at 0 in C */
137
#define ARRAY_SUBSCRIPT_OFFSET(output_type) (static_cast<int>(isMatlabOutput(output_type) || isJuliaOutput(output_type)))
138

139
// Left and right array subscript delimiters: '(' and ')' for Matlab, '[' and ']' for C
140 141
#define LEFT_ARRAY_SUBSCRIPT(output_type) (isMatlabOutput(output_type) ? '(' : '[')
#define RIGHT_ARRAY_SUBSCRIPT(output_type) (isMatlabOutput(output_type) ? ')' : ']')
142

143
// Left and right parentheses
144 145
#define LEFT_PAR(output_type) (isLatexOutput(output_type) ? "\\left(" : "(")
#define RIGHT_PAR(output_type) (isLatexOutput(output_type) ? "\\right)" : ")")
146 147

//! Base class for expression nodes
148
class ExprNode
149 150 151 152 153 154 155 156 157 158 159 160 161
    {
      friend class DataTree;
      friend class DynamicModel;
      friend class StaticModel;
      friend class ModelTree;
      friend struct ExprNodeLess;
      friend class NumConstNode;
      friend class VariableNode;
      friend class UnaryOpNode;
      friend class BinaryOpNode;
      friend class TrinaryOpNode;
      friend class AbstractExternalFunctionNode;
      friend class VarExpectationNode;
162
      friend class PacExpectationNode;
163 164 165 166 167 168 169 170 171 172
    private:
      //! Computes derivative w.r. to a derivation ID (but doesn't store it in derivatives map)
      /*! You shoud use getDerivative() to get the benefit of symbolic a priori and of caching */
      virtual expr_t computeDerivative(int deriv_id) = 0;

    protected:
      //! Reference to the enclosing DataTree
      DataTree &datatree;

      //! Index number
173
      const int idx;
174 175

      //! Is the data member non_null_derivatives initialized ?
176
      bool preparedForDerivation{false};
177 178 179 180 181 182 183

      //! Set of derivation 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, expr_t> derivatives;

184 185
      constexpr static int min_cost_matlab{40*90};
      constexpr static int min_cost_c{40*4};
186 187
      inline static int min_cost(bool is_matlab) { return(is_matlab ? min_cost_matlab : min_cost_c); };

188 189 190 191
      //! Cost of computing current node
      /*! Nodes included in temporary_terms are considered having a null cost */
      virtual int cost(int cost, bool is_matlab) const;
      virtual int cost(const temporary_terms_t &temporary_terms, bool is_matlab) const;
192
      virtual int cost(const map<pair<int, int>, temporary_terms_t> &temp_terms_map, bool is_matlab) const;
193 194 195 196

      //! For creating equation cross references
      struct EquationInfo
      {
197 198 199 200
        set<pair<int, int>> param;
        set<pair<int, int>> endo;
        set<pair<int, int>> exo;
        set<pair<int, int>> exo_det;
201 202
      };

203 204 205 206 207 208
      //! If this node is a temporary term, writes its temporary term representation
      /*! Returns true if node is a temporary term and has therefore been
          written to output*/
      bool checkIfTemporaryTermThenWrite(ostream &output, ExprNodeOutputType output_type,
                                         const temporary_terms_t &temporary_terms,
                                         const temporary_terms_idxs_t &temporary_terms_idxs) const;
209 210 211 212

      // Internal helper for matchVariableTimesConstantTimesParam()
      virtual void matchVTCTPHelper(int &var_id, int &lag, int &param_id, double &constant, bool at_denominator) const;

213
    public:
214
      ExprNode(DataTree &datatree_arg, int idx_arg);
215
      virtual ~ExprNode() = default;
216

217 218 219 220 221
      ExprNode(const ExprNode &) = delete;
      ExprNode(ExprNode &&) = delete;
      ExprNode & operator=(const ExprNode &) = delete;
      ExprNode & operator=(ExprNode &&) = delete;

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
      //! Initializes data member non_null_derivatives
      virtual void prepareForDerivation() = 0;

      //! Returns derivative w.r. to derivation ID
      /*! Uses a symbolic a priori to pre-detect null derivatives, and caches the result for other derivatives (to avoid computing it several times)
        For an equal node, returns the derivative of lhs minus rhs */
      expr_t getDerivative(int deriv_id);

      //! Computes derivatives by applying the chain rule for some variables
      /*!
        \param deriv_id The derivation ID with respect to which we are derivating
        \param recursive_variables Contains the derivation ID for which chain rules must be applied. Keys are derivation IDs, values are equations of the form x=f(y) where x is the key variable and x doesn't appear in y
      */
      virtual expr_t getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables) = 0;

      //! Returns precedence of node
      /*! Equals 100 for constants, variables, unary ops, and temporary terms */
      virtual int precedence(ExprNodeOutputType output_t, const temporary_terms_t &temporary_terms) const;

241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260
      //! Compute temporary terms in this expression
      /*!
        \param[in] derivOrder the derivation order (first w.r.t. endo/exo,
                   second w.r.t. params)
        \param[out] temp_terms_map the computed temporary terms, associated
                    with their derivation order
        \param[out] reference_count a temporary structure, used to count
                    references to each node (integer in outer pair is the
                    reference count, the inner pair is the derivation order)
        \param[in] is_matlab whether we are in a MATLAB context, since that
                    affects the cost of each operator

        A node will be marked as a temporary term if it is referenced at least
        two times (i.e. has at least two parents), and has a computing cost
        (multiplied by reference count) greater to datatree.min_cost
      */
      virtual void computeTemporaryTerms(const pair<int, int> &derivOrder,
                                         map<pair<int, int>, temporary_terms_t> &temp_terms_map,
                                         map<expr_t, pair<int, pair<int, int>>> &reference_count,
                                         bool is_matlab) const;
261 262 263 264 265 266

      //! Writes output of node, using a Txxx notation for nodes in temporary_terms, and specifiying the set of already written external functions
      /*!
        \param[in] output the output stream
        \param[in] output_type the type of output (MATLAB, C, LaTeX...)
        \param[in] temporary_terms the nodes that are marked as temporary terms
267
        \param[in] a map from temporary_terms to integers indexes (in the
268 269
                   MATLAB, C or Julia vector of temporary terms); can be empty
                   when writing MATLAB with block decomposition)
270
        \param[in] tef_terms the set of already written external function nodes
271
      */
272
      virtual void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const = 0;
273 274 275 276 277 278 279 280 281 282 283

      //! returns true if the expr node contains an external function
      virtual bool containsExternalFunction() const = 0;

      //! Writes output of node (with no temporary terms and with "outside model" output type)
      void writeOutput(ostream &output) const;

      //! Writes output of node (with no temporary terms)
      void writeOutput(ostream &output, ExprNodeOutputType output_type) const;

      //! Writes output of node, using a Txxx notation for nodes in temporary_terms
Houtan Bastani's avatar
Houtan Bastani committed
284
      void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs) const;
285

Stéphane Adjemian's avatar
Stéphane Adjemian committed
286
      //! Writes output of node in JSON syntax
287
      virtual void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, const bool isdynamic = true) const = 0;
Stéphane Adjemian's avatar
Stéphane Adjemian committed
288

Houtan Bastani's avatar
Houtan Bastani committed
289 290 291
      //! Writes the Abstract Syntax Tree in JSON
      virtual void writeJsonAST(ostream &output) const = 0;

Stéphane Adjemian's avatar
Stéphane Adjemian committed
292 293
      virtual int precedenceJson(const temporary_terms_t &temporary_terms) const;

294 295 296
      //! Writes the output for an external function, ensuring that the external function is called as few times as possible using temporary terms
      virtual void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
                                               const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
297
                                               const temporary_terms_idxs_t &temporary_terms_idxs,
298 299
                                               deriv_node_temp_terms_t &tef_terms) const;

Stéphane Adjemian's avatar
Stéphane Adjemian committed
300 301 302 303
      //! Write the JSON output of an external function in a string vector
      //! Allows the insertion of commas if necessary
      virtual void writeJsonExternalFunctionOutput(vector<string> &efout,
                                                   const temporary_terms_t &temporary_terms,
304 305
                                                   deriv_node_temp_terms_t &tef_terms,
                                                   const bool isdynamic = true) const;
Stéphane Adjemian's avatar
Stéphane Adjemian committed
306

307 308 309 310 311 312 313 314 315 316 317 318
      virtual void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
                                                 bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                                 const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
                                                 deriv_node_temp_terms_t &tef_terms) const;

      //! Computes the set of all variables of a given symbol type in the expression (with information on lags)
      /*!
        Variables are stored as integer pairs of the form (symb_id, lag).
        They are added to the set given in argument.
        Note that model local variables are substituted by their expression in the computation
        (and added if type_arg = ModelLocalVariable).
      */
319
      virtual void collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const = 0;
320

321 322 323
      //! Find lowest lag for VAR
      virtual int VarMinLag() const = 0;

324
      //! Find the maximum lag in a VAR: handles case where LHS is diff
Houtan Bastani's avatar
Houtan Bastani committed
325
      virtual int VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const = 0;
326 327 328 329

      //! Finds LHS variable in a VAR equation
      virtual void collectVARLHSVariable(set<expr_t> &result) const = 0;

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
      //! Computes the set of all variables of a given symbol type in the expression (without information on lags)
      /*!
        Variables are stored as symb_id.
        They are added to the set given in argument.
        Note that model local variables are substituted by their expression in the computation
        (and added if type_arg = ModelLocalVariable).
      */
      void collectVariables(SymbolType type_arg, set<int> &result) const;

      //! Computes the set of endogenous variables in the expression
      /*!
        Endogenous are stored as integer pairs of the form (type_specific_id, lag).
        They are added to the set given in argument.
        Note that model local variables are substituted by their expression in the computation.
      */
345
      virtual void collectEndogenous(set<pair<int, int>> &result) const;
346 347 348 349 350 351 352

      //! Computes the set of exogenous variables in the expression
      /*!
        Exogenous are stored as integer pairs of the form (type_specific_id, lag).
        They are added to the set given in argument.
        Note that model local variables are substituted by their expression in the computation.
      */
353
      virtual void collectExogenous(set<pair<int, int>> &result) const;
354 355 356 357 358

      virtual void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const = 0;

      virtual void computeTemporaryTerms(map<expr_t, int> &reference_count,
                                         temporary_terms_t &temporary_terms,
359
                                         map<expr_t, pair<int, int>> &first_occurence,
360
                                         int Curr_block,
361
                                         vector< vector<temporary_terms_t>> &v_temporary_terms,
362 363 364 365 366 367 368 369 370 371 372 373
                                         int equation) const;

      class EvalException

      {
      };

      class EvalExternalFunctionException : public EvalException

      {
      };

374
      virtual double eval(const eval_context_t &eval_context) const noexcept(false) = 0;
375
      virtual void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, const deriv_node_temp_terms_t &tef_terms) const = 0;
376 377 378 379 380 381 382 383 384 385 386 387 388 389
      void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const;
      //! Creates a static version of this node
      /*!
        This method duplicates the current node by creating a similar node from which all leads/lags have been stripped,
        adds the result in the static_datatree argument (and not in the original datatree), and returns it.
      */
      virtual expr_t toStatic(DataTree &static_datatree) const = 0;

      /*!
        Compute cross references for equations
      */
      //  virtual void computeXrefs(set<int> &param, set<int> &endo, set<int> &exo, set<int> &exo_det) const = 0;
      virtual void computeXrefs(EquationInfo &ei) const = 0;
      //! Try to normalize an equation linear in its endogenous variable
390
      virtual pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<tuple<int, expr_t, expr_t>> &List_of_Op_RHS) const = 0;
391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407

      //! Returns the maximum lead of endogenous in this expression
      /*! Always returns a non-negative value */
      virtual int maxEndoLead() const = 0;

      //! Returns the maximum lead of exogenous in this expression
      /*! Always returns a non-negative value */
      virtual int maxExoLead() const = 0;

      //! Returns the maximum lag of endogenous in this expression
      /*! Always returns a non-negative value */
      virtual int maxEndoLag() const = 0;

      //! Returns the maximum lag of exogenous in this expression
      /*! Always returns a non-negative value */
      virtual int maxExoLag() const = 0;

408 409 410
      //! Returns the maximum lead of endo/exo/exodet in this expression
      /*! A negative value means that the expression contains only lagged
          variables. */
411 412
      virtual int maxLead() const = 0;

413 414 415
      //! Returns the maximum lag of endo/exo/exodet in this expression
      /*! A negative value means that the expression contains only leaded
          variables. */
416 417
      virtual int maxLag() const = 0;

418 419 420 421 422 423
      //! Returns the maximum lag of endo/exo/exodet, as if diffs were expanded
      /*! This function behaves as maxLag(), except that it treats diff()
          differently. For e.g., on diff(diff(x(-1))), maxLag() returns 1 while
          maxLagWithDiffsExpanded() returns 3. */
      virtual int maxLagWithDiffsExpanded() const = 0;

Houtan Bastani's avatar
Houtan Bastani committed
424 425
      //! Get Max lag of var associated with Pac model
      //! Takes account of undiffed LHS variables in calculating the max lag
426
      virtual int PacMaxLag(int lhs_symb_id) const = 0;
Houtan Bastani's avatar
Houtan Bastani committed
427

428 429 430
      //! Get the target variable of the PAC model
      virtual int getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const = 0;

Houtan Bastani's avatar
Houtan Bastani committed
431 432
      virtual expr_t undiff() const = 0;

433 434 435 436 437 438 439 440
      //! Returns a new expression where all the leads/lags have been shifted backwards by the same amount
      /*!
        Only acts on endogenous, exogenous, exogenous det
        \param[in] n The number of lags by which to shift
        \return The same expression except that leads/lags have been shifted backwards
      */
      virtual expr_t decreaseLeadsLags(int n) const = 0;

441
      //! Type for the substitution map used in the process of creating auxiliary vars
442
      using subst_table_t = map<const ExprNode *, const VariableNode *>;
443

444
      //! Type for the substitution map used in the process of substituting adl expressions
445
      using subst_table_adl_t = map<const ExprNode *, const expr_t>;
446

447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527
      //! Creates auxiliary endo lead variables corresponding to this expression
      /*!
        If maximum endogenous lead >= 3, this method will also create intermediary auxiliary var, and will add the equations of the form aux1 = aux2(+1) to the substitution table.
        \pre This expression is assumed to have maximum endogenous lead >= 2
        \param[in,out] subst_table The table to which new auxiliary variables and their correspondance will be added
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
        \return The new variable node corresponding to the current expression
      */
      VariableNode *createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;

      //! Creates auxiliary exo lead variables corresponding to this expression
      /*!
        If maximum exogenous lead >= 2, this method will also create intermediary auxiliary var, and will add the equations of the form aux1 = aux2(+1) to the substitution table.
        \pre This expression is assumed to have maximum exogenous lead >= 1
        \param[in,out] subst_table The table to which new auxiliary variables and their correspondance will be added
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
        \return The new variable node corresponding to the current expression
      */
      VariableNode *createExoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const;

      //! Constructs a new expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
      /*!
        \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.

        If the method detects a sub-expr which needs to be substituted, two cases are possible:
        - if this expr is in the table, then it will use the corresponding variable and return the substituted expression
        - if this expr is not in the table, then it will create an auxiliary endogenous variable, add the substitution in the table and return the substituted expression

        \return A new equivalent expression where sub-expressions with max endo lead >= 2 have been replaced by auxiliary variables
      */
      virtual expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const = 0;

      //! Constructs a new expression where endo variables with max endo lag >= 2 have been replaced by auxiliary variables
      /*!
        \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
      */
      virtual expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;

      //! Constructs a new expression where exogenous variables with a lead have been replaced by auxiliary variables
      /*!
        \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
      */
      virtual expr_t substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const = 0;
      //! Constructs a new expression where exogenous variables with a lag have been replaced by auxiliary variables
      /*!
        \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
      */
      virtual expr_t substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;

      //! Constructs a new expression where the expectation operator has been replaced by auxiliary variables
      /*!
        \param[in,out] subst_table Map used to store expressions that have already be substituted and their corresponding variable, in order to avoid creating two auxiliary variables for the same sub-expr.
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
        \param[in] partial_information_model Are we substituting in a partial information model?
      */
      virtual expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const = 0;

      virtual expr_t decreaseLeadsLagsPredeterminedVariables() const = 0;

      //! Constructs a new expression where forward variables (supposed to be at most in t+1) have been replaced by themselves at t, plus a new aux var representing their (time) differentiate
      /*!
        \param[in] subset variables to which to limit the transformation; transform
        all fwrd vars if empty
        \param[in,out] subst_table Map used to store mapping between a given
        forward variable and the aux var that contains its differentiate
        \param[out] neweqs Equations to be added to the model to match the creation of auxiliary variables.
      */
      virtual expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;

      //! Return true if the nodeID is a numerical constant equal to value and false otherwise
      /*!
        \param[in] value of the numerical constante
        \param[out] the boolean equal to true if NodeId is a constant equal to value
      */
      virtual bool isNumConstNodeEqualTo(double value) const = 0;

      //! Returns true if the expression contains one or several endogenous variable
528
      virtual bool containsEndogenous() const = 0;
529 530 531 532

      //! Returns true if the expression contains one or several exogenous variable
      virtual bool containsExogenous() const = 0;

533
      //! Returns the maximum number of nested diffs in the expression
534
      virtual int countDiffs() const = 0;
535

536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554
      //! Return true if the nodeID is a variable withe a type equal to type_arg, a specific variable id aqual to varfiable_id and a lag equal to lag_arg and false otherwise
      /*!
        \param[in] the type (type_arg), specifique variable id (variable_id and the lag (lag_arg)
        \param[out] the boolean equal to true if NodeId is the variable
      */
      virtual bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const = 0;

      //! Replaces the Trend var with datatree.One
      virtual expr_t replaceTrendVar() const = 0;

      //! Constructs a new expression where the variable indicated by symb_id has been detrended
      /*!
        \param[in] symb_id indicating the variable to be detrended
        \param[in] log_trend indicates if the trend is in log
        \param[in] trend indicating the trend
        \return the new binary op pointing to a detrended variable
      */
      virtual expr_t detrend(int symb_id, bool log_trend, expr_t trend) const = 0;

555 556 557
      //! Substitute adl operator
      virtual expr_t substituteAdl() const = 0;

558 559 560
      //! Substitute VarExpectation nodes
      virtual expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const = 0;

561
      //! Substitute diff operator
562
      virtual void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const = 0;
563
      virtual void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const = 0;
564
      virtual int findTargetVariable(int lhs_symb_id) const = 0;
Houtan Bastani's avatar
Houtan Bastani committed
565
      virtual expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
566
      virtual expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const = 0;
567

568
      //! Substitute pac_expectation operator
569
      virtual expr_t substitutePacExpectation(const string & name, expr_t subexpr) = 0;
570

571
      //! Add ExprNodes to the provided datatree
572
      virtual expr_t clone(DataTree &datatree) const = 0;
573 574 575 576 577 578 579 580 581 582 583 584 585

      //! Move a trend variable with lag/lead to time t by dividing/multiplying by its growth factor
      virtual expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const = 0;

      //! Returns true if the expression is in static form (no lead, no lag, no expectation, no STEADY_STATE)
      virtual bool isInStaticForm() const = 0;

      //! Substitute auxiliary variables by their expression in static model
      virtual expr_t substituteStaticAuxiliaryVariable() const = 0;

      //! Returns true if model_info_name is referenced by a VarExpectationNode
      virtual bool isVarModelReferenced(const string &model_info_name) const = 0;

586
      //! Matches a linear combination of variables, where scalars can be constant*parameter
587 588
      /*! Returns a list of (variable_id, lag, param_id, constant)
          corresponding to the terms in the expression. When there is no
589 590 591
          parameter in a term, param_id == -1.
          Can throw a MatchFailureException. */
      vector<tuple<int, int, int, double>> matchLinearCombinationOfVariables() const;
592 593 594

      pair<int, vector<tuple<int, int, int, double>>> matchParamTimesLinearCombinationOfVariables() const;

595 596 597 598
      //! Returns true if expression is of the form:
      //! param * (endog op endog op ...) + param * (endog op endog op ...) + ...
      virtual bool isParamTimesEndogExpr() const = 0;

599
      //! Fills the EC matrix structure
600 601 602
      void fillErrorCorrectionRow(int eqn, const vector<int> &nontarget_lhs, const vector<int> &target_lhs,
                                  map<tuple<int, int, int>, expr_t> &A0,
                                  map<tuple<int, int, int>, expr_t> &A0star) const;
603

604
      //! Finds equations where a variable is equal to a constant
605
      virtual void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const = 0;
606 607

      //! Replaces variables found in findConstantEquations() with their constant values
608
      virtual expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const = 0;
609

610
      //! Returns true if PacExpectationNode encountered
611
      virtual bool containsPacExpectation(const string &pac_model_name = "") const = 0;
612

613 614
      //! Fills map
      virtual void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const = 0;
615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641

      //! Decompose an expression into its additive terms
      /*! Returns a list of terms, with their sign (either 1 or -1, depending
        on whether the terms appears with a plus or a minus).
        The current_sign argument should normally be left to 1.
        If current_sign == -1, then all signs are inverted */
      virtual void decomposeAdditiveTerms(vector<pair<expr_t, int>> &terms, int current_sign = 1) const;

      // Matches an expression of the form variable*constant*parameter
      /* Returns a tuple (variable_id, lag, param_id, constant).
         The variable must be an exogenous or an endogenous.
         The constant is optional (in which case 1 is returned); there can be
         several multiplicative constants; constants can also appear at the
         denominator (i.e. after a divide sign).
         The parameter is optional (in which case param_id == -1).
         If the expression is not of the expected form, throws a
         MatchFailureException */
      tuple<int, int, int, double> matchVariableTimesConstantTimesParam() const;

      //! Exception thrown by matchVariableTimesConstantTimesParam when matching fails
      class MatchFailureException
      {
      public:
        const string message;
        MatchFailureException(string message_arg) : message{move(message_arg)} {};
      };
};
642 643

//! Object used to compare two nodes (using their indexes)
644 645 646
/*! Note that in this ordering, a subexpression is always less than the
    expression from which it is extracted. This property is used extensively in
    the temporary terms computations. */
647 648
struct ExprNodeLess
{
649
  bool
650
  operator()(expr_t arg1, expr_t arg2) const
651 652 653 654 655 656 657 658 659
  {
    return arg1->idx < arg2->idx;
  }
};

//! Numerical constant node
/*! The constant is necessarily non-negative (this is enforced at the NumericalConstants class level) */
class NumConstNode : public ExprNode
{
660
public:
661 662
  //! Id from numerical constants table
  const int id;
663
private:
664
  expr_t computeDerivative(int deriv_id) override;
665 666
protected:
  void matchVTCTPHelper(int &var_id, int &lag, int &param_id, double &constant, bool at_denominator) const override;
667
public:
668
  NumConstNode(DataTree &datatree_arg, int idx_arg, int id_arg);
669 670
  void prepareForDerivation() override;
  void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const override;
Houtan Bastani's avatar
Houtan Bastani committed
671
  void writeJsonAST(ostream &output) const override;
672 673 674
  void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, const bool isdynamic) const override;
  bool containsExternalFunction() const override;
  void collectVARLHSVariable(set<expr_t> &result) const override;
675
  void collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const override;
676 677 678 679 680
  void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const override;
  double eval(const eval_context_t &eval_context) const noexcept(false) override;
  void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, const deriv_node_temp_terms_t &tef_terms) const override;
  expr_t toStatic(DataTree &static_datatree) const override;
  void computeXrefs(EquationInfo &ei) const override;
681
  pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<tuple<int, expr_t, expr_t>>  &List_of_Op_RHS) const override;
682 683 684 685 686 687 688
  expr_t getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables) override;
  int maxEndoLead() const override;
  int maxExoLead() const override;
  int maxEndoLag() const override;
  int maxExoLag() const override;
  int maxLead() const override;
  int maxLag() const override;
689
  int maxLagWithDiffsExpanded() const override;
690
  int VarMinLag() const override;
Houtan Bastani's avatar
Houtan Bastani committed
691
  int VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const override;
692
  int PacMaxLag(int lhs_symb_id) const override;
693
  int getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const override;
694 695 696 697 698 699 700 701
  expr_t undiff() const override;
  expr_t decreaseLeadsLags(int n) const override;
  expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const override;
  expr_t substituteAdl() const override;
702
  expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
703 704
  void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const override;
  void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const override;
705
  int findTargetVariable(int lhs_symb_id) const override;
706 707
  expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
708
  expr_t substitutePacExpectation(const string & name, expr_t subexpr) override;
709 710 711 712 713 714 715 716 717
  expr_t decreaseLeadsLagsPredeterminedVariables() const override;
  expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  bool isNumConstNodeEqualTo(double value) const override;
  bool containsEndogenous() const override;
  bool containsExogenous() const override;
  int countDiffs() const override;
  bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const override;
  expr_t replaceTrendVar() const override;
  expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override;
718
  expr_t clone(DataTree &datatree) const override;
719 720
  expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const override;
  bool isInStaticForm() const override;
721 722
  void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const override;
  expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
723 724
  bool containsPacExpectation(const string &pac_model_name = "") const override;
  bool isParamTimesEndogExpr() const override;
725 726 727
  bool isVarModelReferenced(const string &model_info_name) const override;
  void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override;
  expr_t substituteStaticAuxiliaryVariable() const override;
728 729 730 731 732
};

//! Symbol or variable node
class VariableNode : public ExprNode
{
733
  friend class UnaryOpNode;
734
public:
735 736
  //! Id from the symbol table
  const int symb_id;
737
  //! A positive value is a lead, a negative is a lag
738
  const int lag;
739
private:
740
  expr_t computeDerivative(int deriv_id) override;
741 742
protected:
  void matchVTCTPHelper(int &var_id, int &lag, int &param_id, double &constant, bool at_denominator) const override;
743
public:
744
  VariableNode(DataTree &datatree_arg, int idx_arg, int symb_id_arg, int lag_arg);
745 746
  void prepareForDerivation() override;
  void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const override;
Houtan Bastani's avatar
Houtan Bastani committed
747
  void writeJsonAST(ostream &output) const override;
748 749 750
  void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, const bool isdynamic) const override;
  bool containsExternalFunction() const override;
  void collectVARLHSVariable(set<expr_t> &result) const override;
751
  void collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const override;
752
  void computeTemporaryTerms(map<expr_t, int > &reference_count,
753
                                     temporary_terms_t &temporary_terms,
754
                                     map<expr_t, pair<int, int>> &first_occurence,
755
                                     int Curr_block,
756
                                     vector< vector<temporary_terms_t>> &v_temporary_terms,
757 758 759 760 761 762
                                     int equation) const override;
  void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const override;
  double eval(const eval_context_t &eval_context) const noexcept(false) override;
  void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, const deriv_node_temp_terms_t &tef_terms) const override;
  expr_t toStatic(DataTree &static_datatree) const override;
  void computeXrefs(EquationInfo &ei) const override;
763
  SymbolType get_type() const;
764
  pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<tuple<int, expr_t, expr_t>>  &List_of_Op_RHS) const override;
765 766 767 768 769 770 771
  expr_t getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables) override;
  int maxEndoLead() const override;
  int maxExoLead() const override;
  int maxEndoLag() const override;
  int maxExoLag() const override;
  int maxLead() const override;
  int maxLag() const override;
772
  int maxLagWithDiffsExpanded() const override;
773
  int VarMinLag() const override;
Houtan Bastani's avatar
Houtan Bastani committed
774
  int VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const override;
775
  int PacMaxLag(int lhs_symb_id) const override;
776
  int getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const override;
777 778 779 780 781 782 783 784
  expr_t undiff() const override;
  expr_t decreaseLeadsLags(int n) const override;
  expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const override;
  expr_t substituteAdl() const override;
785
  expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
786 787
  void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const override;
  void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const override;
788
  int findTargetVariable(int lhs_symb_id) const override;
789 790
  expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
791
  expr_t substitutePacExpectation(const string & name, expr_t subexpr) override;
792 793 794 795 796 797 798 799 800
  expr_t decreaseLeadsLagsPredeterminedVariables() const override;
  expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  bool isNumConstNodeEqualTo(double value) const override;
  bool containsEndogenous() const override;
  bool containsExogenous() const override;
  int countDiffs() const override;
  bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const override;
  expr_t replaceTrendVar() const override;
  expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override;
801
  expr_t clone(DataTree &datatree) const override;
802 803
  expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const override;
  bool isInStaticForm() const override;
804 805
  void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const override;
  expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
806
  bool containsPacExpectation(const string &pac_model_name = "") const override;
807
  bool isParamTimesEndogExpr() const override;
808 809
  bool isVarModelReferenced(const string &model_info_name) const override;
  void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override;
810
  //! Substitute auxiliary variables by their expression in static model
811
  expr_t substituteStaticAuxiliaryVariable() const override;
812 813 814 815 816
};

//! Unary operator node
class UnaryOpNode : public ExprNode
{
817 818
protected:
  void matchVTCTPHelper(int &var_id, int &lag, int &param_id, double &constant, bool at_denominator) const override;
819
public:
820
  const expr_t arg;
sebastien's avatar
sebastien committed
821 822
  //! Stores the information set. Only used for expectation operator
  const int expectation_information_set;
823
  //! Only used for UnaryOpcode::steadyStateParamDeriv and UnaryOpcode::steadyStateParam2ndDeriv
824
  const int param1_symb_id, param2_symb_id;
825
  const UnaryOpcode op_code;
826
  const string adl_param_name;
827
  const vector<int> adl_lags;
828
private:
829 830 831
  expr_t computeDerivative(int deriv_id) override;
  int cost(int cost, bool is_matlab) const override;
  int cost(const temporary_terms_t &temporary_terms, bool is_matlab) const override;
832
  int cost(const map<pair<int, int>, temporary_terms_t> &temp_terms_map, bool is_matlab) const override;
833
  //! Returns the derivative of this node if darg is the derivative of the argument
834
  expr_t composeDerivatives(expr_t darg, int deriv_id);
835
public:
836
  UnaryOpNode(DataTree &datatree_arg, int idx_arg, UnaryOpcode op_code_arg, const expr_t arg_arg, int expectation_information_set_arg, int param1_symb_id_arg, int param2_symb_id_arg, string adl_param_name_arg, vector<int> adl_lags_arg);
837
  void prepareForDerivation() override;
838 839 840 841
  void computeTemporaryTerms(const pair<int, int> &derivOrder,
                             map<pair<int, int>, temporary_terms_t> &temp_terms_map,
                             map<expr_t, pair<int, pair<int, int>>> &reference_count,
                             bool is_matlab) const override;
842
  void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const override;
Houtan Bastani's avatar
Houtan Bastani committed
843
  void writeJsonAST(ostream &output) const override;
844 845 846
  void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, const bool isdynamic) const override;
  bool containsExternalFunction() const override;
  void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
847
                                           const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
848
                                           const temporary_terms_idxs_t &temporary_terms_idxs,
849 850
                                           deriv_node_temp_terms_t &tef_terms) const override;
  void writeJsonExternalFunctionOutput(vector<string> &efout,
851
                                               const temporary_terms_t &temporary_terms,
852
                                               deriv_node_temp_terms_t &tef_terms,
853 854
                                               const bool isdynamic) const override;
  void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
855 856
                                             bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                             const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
857 858
                                             deriv_node_temp_terms_t &tef_terms) const override;
  void computeTemporaryTerms(map<expr_t, int> &reference_count,
859
                                     temporary_terms_t &temporary_terms,
860
                                     map<expr_t, pair<int, int>> &first_occurence,
861
                                     int Curr_block,
862
                                     vector< vector<temporary_terms_t>> &v_temporary_terms,
863 864
                                     int equation) const override;
  void collectVARLHSVariable(set<expr_t> &result) const override;
865
  void collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const override;
866
  void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const override;
867
  static double eval_opcode(UnaryOpcode op_code, double v) noexcept(false);
868 869 870 871
  double eval(const eval_context_t &eval_context) const noexcept(false) override;
  void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, const deriv_node_temp_terms_t &tef_terms) const override;
  expr_t toStatic(DataTree &static_datatree) const override;
  void computeXrefs(EquationInfo &ei) const override;
872
  pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<tuple<int, expr_t, expr_t>>  &List_of_Op_RHS) const override;
873 874 875 876 877 878 879
  expr_t getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables) override;
  int maxEndoLead() const override;
  int maxExoLead() const override;
  int maxEndoLag() const override;
  int maxExoLag() const override;
  int maxLead() const override;
  int maxLag() const override;
880
  int maxLagWithDiffsExpanded() const override;
881
  int VarMinLag() const override;
Houtan Bastani's avatar
Houtan Bastani committed
882
  int VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const override;
883
  int PacMaxLag(int lhs_symb_id) const override;
884
  int getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const override;
885 886 887
  expr_t undiff() const override;
  expr_t decreaseLeadsLags(int n) const override;
  expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
sebastien's avatar
sebastien committed
888
  //! Creates another UnaryOpNode with the same opcode, but with a possibly different datatree and argument
889
  expr_t buildSimilarUnaryOpNode(expr_t alt_arg, DataTree &alt_datatree) const;
890 891 892 893 894
  expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const override;
  expr_t substituteAdl() const override;
895
  expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
896
  void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const override;
897
  bool createAuxVarForUnaryOpNode() const;
898
  void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const override;
899
  int findTargetVariable(int lhs_symb_id) const override;
900 901
  expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
902
  expr_t substitutePacExpectation(const string & name, expr_t subexpr) override;
903 904 905 906 907 908 909 910 911
  expr_t decreaseLeadsLagsPredeterminedVariables() const override;
  expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  bool isNumConstNodeEqualTo(double value) const override;
  bool containsEndogenous() const override;
  bool containsExogenous() const override;
  int countDiffs() const override;
  bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const override;
  expr_t replaceTrendVar() const override;
  expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override;
912
  expr_t clone(DataTree &datatree) const override;
913 914
  expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const override;
  bool isInStaticForm() const override;
915 916
  void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const override;
  expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
917
  bool containsPacExpectation(const string &pac_model_name = "") const override;
918
  bool isParamTimesEndogExpr() const override;
919 920
  bool isVarModelReferenced(const string &model_info_name) const override;
  void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override;
921
  //! Substitute auxiliary variables by their expression in static model
922
  expr_t substituteStaticAuxiliaryVariable() const override;
923
  void decomposeAdditiveTerms(vector<pair<expr_t, int>> &terms, int current_sign) const override;
924 925 926 927 928
};

//! Binary operator node
class BinaryOpNode : public ExprNode
{
929 930
protected:
  void matchVTCTPHelper(int &var_id, int &lag, int &param_id, double &constant, bool at_denominator) const override;
931
public:
932
  const expr_t arg1, arg2;
933
  const BinaryOpcode op_code;
934 935 936
  const int powerDerivOrder;
  const string adlparam;
private:
937 938 939
  expr_t computeDerivative(int deriv_id) override;
  int cost(int cost, bool is_matlab) const override;
  int cost(const temporary_terms_t &temporary_terms, bool is_matlab) const override;
940
  int cost(const map<pair<int, int>, temporary_terms_t> &temp_terms_map, bool is_matlab) const override;
941
  //! Returns the derivative of this node if darg1 and darg2 are the derivatives of the arguments
942
  expr_t composeDerivatives(expr_t darg1, expr_t darg2);
943
public:
944
  BinaryOpNode(DataTree &datatree_arg, int idx_arg, const expr_t arg1_arg,
945
               BinaryOpcode op_code_arg, const expr_t arg2_arg, int powerDerivOrder);
946 947 948
  void prepareForDerivation() override;
  int precedenceJson(const temporary_terms_t &temporary_terms) const override;
  int precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const override;
949 950 951 952
  void computeTemporaryTerms(const pair<int, int> &derivOrder,
                             map<pair<int, int>, temporary_terms_t> &temp_terms_map,
                             map<expr_t, pair<int, pair<int, int>>> &reference_count,
                             bool is_matlab) const override;
953
  void writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs, const deriv_node_temp_terms_t &tef_terms) const override;
Houtan Bastani's avatar
Houtan Bastani committed
954
  void writeJsonAST(ostream &output) const override;
955 956 957
  void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, const bool isdynamic) const override;
  bool containsExternalFunction() const override;
  void writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
958
                                           const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
959
                                           const temporary_terms_idxs_t &temporary_terms_idxs,
960 961
                                           deriv_node_temp_terms_t &tef_terms) const override;
  void writeJsonExternalFunctionOutput(vector<string> &efout,
962
                                               const temporary_terms_t &temporary_terms,
963
                                               deriv_node_temp_terms_t &tef_terms,
964 965
                                               const bool isdynamic) const override;
  void compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
966 967
                                             bool lhs_rhs, const temporary_terms_t &temporary_terms,
                                             const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
968 969
                                             deriv_node_temp_terms_t &tef_terms) const override;
  void computeTemporaryTerms(map<expr_t, int> &reference_count,
970
                                     temporary_terms_t &temporary_terms,
971
                                     map<expr_t, pair<int, int>> &first_occurence,
972
                                     int Curr_block,
973
                                     vector< vector<temporary_terms_t>> &v_temporary_terms,
974 975
                                     int equation) const override;
  void collectVARLHSVariable(set<expr_t> &result) const override;
976
  void collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const override;
977
  void collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const override;
978
  static double eval_opcode(double v1, BinaryOpcode op_code, double v2, int derivOrder) noexcept(false);
979 980
  double eval(const eval_context_t &eval_context) const noexcept(false) override;
  void compile(ostream &CompileCode, unsigned int &instruction_number, bool lhs_rhs, const temporary_terms_t &temporary_terms, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic, const deriv_node_temp_terms_t &tef_terms) const override;
981
  expr_t Compute_RHS(expr_t arg1, expr_t arg2, int op, int op_type) const;
982 983
  expr_t toStatic(DataTree &static_datatree) const override;
  void computeXrefs(EquationInfo &ei) const override;
984
  pair<int, expr_t> normalizeEquation(int symb_id_endo, vector<tuple<int, expr_t, expr_t>>  &List_of_Op_RHS) const override;
985 986 987 988 989 990 991
  expr_t getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables) override;
  int maxEndoLead() const override;
  int maxExoLead() const override;
  int maxEndoLag() const override;
  int maxExoLag() const override;
  int maxLead() const override;
  int maxLag() const override;
992
  int maxLagWithDiffsExpanded() const override;
993
  int VarMinLag() const override;
Houtan Bastani's avatar
Houtan Bastani committed
994
  int VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const override;
995
  int PacMaxLag(int lhs_symb_id) const override;
996
  int getPacTargetSymbIdHelper(int lhs_symb_id, int undiff_lhs_symb_id, const set<pair<int, int>> & endogs) const;
997
  int getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const override;
998 999 1000
  expr_t undiff() const override;
  expr_t decreaseLeadsLags(int n) const override;
  expr_t substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
sebastien's avatar
sebastien committed
1001
  //! Creates another BinaryOpNode with the same opcode, but with a possibly different datatree and arguments
1002
  expr_t buildSimilarBinaryOpNode(expr_t alt_arg1, expr_t alt_arg2, DataTree &alt_datatree) const;
1003 1004 1005 1006 1007
  expr_t substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const override;
  expr_t substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const override;
  expr_t substituteAdl() const override;
1008
  expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
1009 1010
  void findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const override;
  void findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const override;
1011 1012 1013
  bool findTargetVariableHelper1(int lhs_symb_id, int rhs_symb_id) const;
  int findTargetVariableHelper(const expr_t arg1, const expr_t arg2, int lhs_symb_id) const;
  int findTargetVariable(int lhs_symb_id) const override;
1014 1015
  expr_t substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  expr_t substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
1016
  expr_t substitutePacExpectation(const string & name, expr_t subexpr) override;
1017 1018 1019 1020 1021 1022 1023 1024 1025
  expr_t decreaseLeadsLagsPredeterminedVariables() const override;
  expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
  bool isNumConstNodeEqualTo(double value) const override;
  bool containsEndogenous() const override;
  bool containsExogenous() const override;
  int countDiffs() const override;
  bool isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const override;
  expr_t replaceTrendVar() const override;
  expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override;
1026
  expr_t clone(DataTree &datatree) const override;
1027
  expr_t removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const override;
1028 1029
  //! Function to write out the oPowerNode in expr_t terms as opposed to writing out the function itself
  expr_t unpackPowerDeriv() const;
Houtan Bastani's avatar
Houtan Bastani committed
1030
  //! Returns MULT_i*(lhs-rhs) = 0, creating multiplier MULT_i
1031 1032 1033
  expr_t addMultipliersToConstraints(int i);
  //! Returns the non-zero hand-side of an equation (that must have a hand side equal to zero)
  expr_t getNonZeroPartofEquation() const;
1034
  bool isInStaticForm() const override;
1035
  void fillAutoregressiveRow(int eqn, const vector<int> &lhs, map<tuple<int, int, int>, expr_t> &AR) const;
1036 1037
  void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const override;
  expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
1038
  bool containsPacExpectation(const string &pac_model_name = "") const override;
1039
  pair<int, vector<tuple<int, bool, int>>> getPacEC(BinaryOpNode *bopn, int lhs_symb_id, int lhs_orig_symb_id) const;
1040
  void getPacAREC(int lhs_symb_id, int lhs_orig_symb_id,
1041
                  pair<int, vector<tuple<int, bool, int>>> &ec_params_and_vars,
1042 1043
                  set<pair<int, pair<int, int>>> &ar_params_and_vars,
                  vector<tuple<int, int, int, double>> &additive_vars_params_and_constants) const;
1044 1045 1046 1047 1048 1049 1050 1051

  //! Finds the share of optimizing agents in the PAC equation,
  //! the expr node associated with it,
  //! and the expr node associated with the non-optimizing part
  tuple<int, expr_t, expr_t, expr_t> getPacOptimizingShareAndExprNodes(int lhs_symb_id, int lhs_orig_symb_id) const;
  pair<int, expr_t> getPacOptimizingShareAndExprNodesHelper(BinaryOpNode *bopn, int lhs_symb_id, int lhs_orig_symb_id) const;
  expr_t getPacNonOptimizingPart(BinaryOpNode *bopn, int optim_share) const;
  bool getPacNonOptimizingPartHelper(BinaryOpNode *bopn, int optim_share) const;
1052
  bool isParamTimesEndogExpr() const override;
1053 1054
  bool isVarModelReferenced(const string &model_info_name) const override;
  void getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const override;
1055
  //! Substitute auxiliary variables by their expression in static model
1056
  expr_t substituteStaticAuxiliaryVariable() const override;
1057
  //! Substitute auxiliary variables by their expression in static model auxiliary variable definition
1058
  expr_t substituteStaticAuxiliaryDefinition() const;
1059
  void decomposeAdditiveTerms(vector<pair<expr_t, int>> &terms, int current_sign) const override;
1060 1061 1062 1063 1064 1065
};

//! Trinary operator node
class TrinaryOpNode : public ExprNode
{
  friend class ModelTree;
1066
public: