ExprNode.cc 337 KB
Newer Older
1
/*
2
 * Copyright (C) 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
 *
 * 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>

24
#include <cassert>
25
#include <cmath>
26

27
#include <utility>
28

29
30
#include "ExprNode.hh"
#include "DataTree.hh"
31
#include "ModFile.hh"
32

33
ExprNode::ExprNode(DataTree &datatree_arg, int idx_arg) : datatree{datatree_arg}, idx{idx_arg}
34
35
36
{
}

37
expr_t
38
ExprNode::getDerivative(int deriv_id)
39
{
sebastien's avatar
sebastien committed
40
41
  if (!preparedForDerivation)
    prepareForDerivation();
42

43
  // Return zero if derivative is necessarily null (using symbolic a priori)
44
  auto it = non_null_derivatives.find(deriv_id);
45
46
  if (it == non_null_derivatives.end())
    return datatree.Zero;
47

48
  // If derivative is stored in cache, use the cached value, otherwise compute it (and cache it)
49
  map<int, expr_t>::const_iterator it2 = derivatives.find(deriv_id);
50
51
52
53
  if (it2 != derivatives.end())
    return it2->second;
  else
    {
54
      expr_t d = computeDerivative(deriv_id);
55
      derivatives[deriv_id] = d;
56
57
58
59
      return d;
    }
}

ferhat's avatar
ferhat committed
60
int
61
ExprNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const
62
63
64
65
{
  // For a constant, a variable, or a unary op, the precedence is maximal
  return 100;
}
ferhat's avatar
ferhat committed
66

67
68
69
70
71
72
73
int
ExprNode::precedenceJson(const temporary_terms_t &temporary_terms) const
{
  // For a constant, a variable, or a unary op, the precedence is maximal
  return 100;
}

74
int
75
76
77
78
79
80
81
82
83
84
85
86
87
88
ExprNode::cost(int cost, bool is_matlab) const
{
  // For a terminal node, the cost is null
  return 0;
}

int
ExprNode::cost(const temporary_terms_t &temp_terms_map, bool is_matlab) const
{
  // For a terminal node, the cost is null
  return 0;
}

int
89
ExprNode::cost(const map<pair<int, int>, temporary_terms_t> &temp_terms_map, bool is_matlab) const
90
91
92
93
{
  // For a terminal node, the cost is null
  return 0;
}
94

95
96
97
98
99
100
101
102
103
bool
ExprNode::checkIfTemporaryTermThenWrite(ostream &output, ExprNodeOutputType output_type,
                                        const temporary_terms_t &temporary_terms,
                                        const temporary_terms_idxs_t &temporary_terms_idxs) const
{
  auto it = temporary_terms.find(const_cast<ExprNode *>(this));
  if (it == temporary_terms.end())
    return false;

104
  if (output_type == ExprNodeOutputType::matlabDynamicModelSparse)
105
106
    output << "T" << idx << "(it_)";
  else
107
    if (output_type == ExprNodeOutputType::matlabStaticModelSparse)
108
109
110
111
112
113
114
      output << "T" << idx;
    else
      {
        auto it2 = temporary_terms_idxs.find(const_cast<ExprNode *>(this));
        // It is the responsibility of the caller to ensure that all temporary terms have their index
        assert(it2 != temporary_terms_idxs.end());
        output << "T" << LEFT_ARRAY_SUBSCRIPT(output_type)
115
               << it2->second + ARRAY_SUBSCRIPT_OFFSET(output_type)
116
117
118
119
120
               << RIGHT_ARRAY_SUBSCRIPT(output_type);
      }
  return true;
}

121
122
123
void
ExprNode::collectVariables(SymbolType type, set<int> &result) const
{
124
  set<pair<int, int>> symbs_lags;
125
126
  collectDynamicVariables(type, symbs_lags);
  transform(symbs_lags.begin(), symbs_lags.end(), inserter(result, result.begin()),
127
            [](auto x) { return x.first; });
128
129
}

sebastien's avatar
sebastien committed
130
void
131
ExprNode::collectEndogenous(set<pair<int, int>> &result) const
sebastien's avatar
sebastien committed
132
{
133
  set<pair<int, int>> symb_ids;
134
  collectDynamicVariables(SymbolType::endogenous, symb_ids);
135
  for (const auto & symb_id : symb_ids)
136
    result.emplace(datatree.symbol_table.getTypeSpecificID(symb_id.first), symb_id.second);
sebastien's avatar
sebastien committed
137
138
139
}

void
140
ExprNode::collectExogenous(set<pair<int, int>> &result) const
sebastien's avatar
sebastien committed
141
{
142
  set<pair<int, int>> symb_ids;
143
  collectDynamicVariables(SymbolType::exogenous, symb_ids);
144
  for (const auto & symb_id : symb_ids)
145
    result.emplace(datatree.symbol_table.getTypeSpecificID(symb_id.first), symb_id.second);
sebastien's avatar
sebastien committed
146
147
}

148
void
149
150
151
152
ExprNode::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
153
154
155
{
  // Nothing to do for a terminal node
}
156
157

void
158
ExprNode::computeTemporaryTerms(map<expr_t, int> &reference_count,
159
                                temporary_terms_t &temporary_terms,
160
                                map<expr_t, pair<int, int>> &first_occurence,
161
                                int Curr_block,
162
                                vector<vector<temporary_terms_t>> &v_temporary_terms,
163
                                int equation) const
164
165
166
{
  // Nothing to do for a terminal node
}
167

168
169
pair<int, expr_t>
ExprNode::normalizeEquation(int var_endo, vector<tuple<int, expr_t, expr_t>> &List_of_Op_RHS) const
170
{
171
  /* nothing to do */
172
  return { 0, nullptr };
173
}
174

175
void
176
ExprNode::writeOutput(ostream &output) const
177
{
178
  writeOutput(output, ExprNodeOutputType::matlabOutsideModel, {}, {});
179
180
}

181
182
183
void
ExprNode::writeOutput(ostream &output, ExprNodeOutputType output_type) const
{
184
  writeOutput(output, output_type, {}, {});
185
186
}

187
void
Houtan Bastani's avatar
Houtan Bastani committed
188
ExprNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs) const
189
{
190
  writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, {});
191
192
}

193
194
void
ExprNode::compile(ostream &CompileCode, unsigned int &instruction_number,
195
196
                  bool lhs_rhs, const temporary_terms_t &temporary_terms,
                  const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const
197
{
198
  compile(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx, dynamic, steady_dynamic, {});
199
200
}

201
202
void
ExprNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
203
                                      const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
204
                                      const temporary_terms_idxs_t &temporary_terms_idxs,
205
                                      deriv_node_temp_terms_t &tef_terms) const
206
207
208
209
{
  // Nothing to do
}

210
211
212
void
ExprNode::writeJsonExternalFunctionOutput(vector<string> &efout,
                                          const temporary_terms_t &temporary_terms,
213
214
                                          deriv_node_temp_terms_t &tef_terms,
                                          const bool isdynamic) const
215
216
217
218
{
  // Nothing to do
}

219
220
void
ExprNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
221
222
223
                                        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
224
225
226
227
{
  // Nothing to do
}

sebastien's avatar
sebastien committed
228
VariableNode *
229
ExprNode::createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
sebastien's avatar
sebastien committed
230
231
232
233
234
235
236
237
{
  int n = maxEndoLead();
  assert(n >= 2);

  subst_table_t::const_iterator it = subst_table.find(this);
  if (it != subst_table.end())
    return const_cast<VariableNode *>(it->second);

238
  expr_t substexpr = decreaseLeadsLags(n-1);
sebastien's avatar
sebastien committed
239
240
241
242
  int lag = n-2;

  // Each iteration tries to create an auxvar such that auxvar(+1)=expr(-lag)
  // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to expr(-lag-1) (resp. expr(-lag))
243
  while (lag >= 0)
sebastien's avatar
sebastien committed
244
    {
245
      expr_t orig_expr = decreaseLeadsLags(lag);
sebastien's avatar
sebastien committed
246
247
248
      it = subst_table.find(orig_expr);
      if (it == subst_table.end())
        {
249
          int symb_id = datatree.symbol_table.addEndoLeadAuxiliaryVar(orig_expr->idx, substexpr);
sebastien's avatar
sebastien committed
250
251
          neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
          substexpr = datatree.AddVariable(symb_id, +1);
252
          assert(dynamic_cast<VariableNode *>(substexpr) != nullptr);
sebastien's avatar
sebastien committed
253
254
255
256
257
258
259
260
261
262
263
          subst_table[orig_expr] = dynamic_cast<VariableNode *>(substexpr);
        }
      else
        substexpr = const_cast<VariableNode *>(it->second);

      lag--;
    }

  return dynamic_cast<VariableNode *>(substexpr);
}

sebastien's avatar
sebastien committed
264
265
266
267
268
269
270
271
272
273
VariableNode *
ExprNode::createExoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
  int n = maxExoLead();
  assert(n >= 1);

  subst_table_t::const_iterator it = subst_table.find(this);
  if (it != subst_table.end())
    return const_cast<VariableNode *>(it->second);

274
  expr_t substexpr = decreaseLeadsLags(n);
sebastien's avatar
sebastien committed
275
276
277
278
  int lag = n-1;

  // Each iteration tries to create an auxvar such that auxvar(+1)=expr(-lag)
  // At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to expr(-lag-1) (resp. expr(-lag))
279
  while (lag >= 0)
sebastien's avatar
sebastien committed
280
    {
281
      expr_t orig_expr = decreaseLeadsLags(lag);
sebastien's avatar
sebastien committed
282
283
284
      it = subst_table.find(orig_expr);
      if (it == subst_table.end())
        {
285
          int symb_id = datatree.symbol_table.addExoLeadAuxiliaryVar(orig_expr->idx, substexpr);
sebastien's avatar
sebastien committed
286
287
          neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
          substexpr = datatree.AddVariable(symb_id, +1);
288
          assert(dynamic_cast<VariableNode *>(substexpr) != nullptr);
sebastien's avatar
sebastien committed
289
290
291
292
293
294
295
296
297
298
299
          subst_table[orig_expr] = dynamic_cast<VariableNode *>(substexpr);
        }
      else
        substexpr = const_cast<VariableNode *>(it->second);

      lag--;
    }

  return dynamic_cast<VariableNode *>(substexpr);
}

300
301
302
303
304
305
306
307
308
309
310
311
bool
ExprNode::isNumConstNodeEqualTo(double value) const
{
  return false;
}

bool
ExprNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
  return false;
}

312
313
314
315
316
void
ExprNode::getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const
{
}

317
NumConstNode::NumConstNode(DataTree &datatree_arg, int idx_arg, int id_arg) :
318
319
  ExprNode{datatree_arg, idx_arg},
  id{id_arg}
320
{
sebastien's avatar
sebastien committed
321
}
322

323
324
int
NumConstNode::countDiffs() const
325
{
326
  return 0;
327
328
}

sebastien's avatar
sebastien committed
329
330
331
332
void
NumConstNode::prepareForDerivation()
{
  preparedForDerivation = true;
333
334
335
  // All derivatives are null, so non_null_derivatives is left empty
}

336
expr_t
337
NumConstNode::computeDerivative(int deriv_id)
338
339
340
341
{
  return datatree.Zero;
}

342
void
343
NumConstNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
344
{
345
  auto it = temporary_terms.find(const_cast<NumConstNode *>(this));
346
347
348
  if (it != temporary_terms.end())
    temporary_terms_inuse.insert(idx);
}
349

350
351
void
NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
352
                          const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
353
                          const temporary_terms_idxs_t &temporary_terms_idxs,
354
                          const deriv_node_temp_terms_t &tef_terms) const
355
{
356
  if (!checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
357
358
    output << datatree.num_constants.get(id);
}
359

Houtan Bastani's avatar
Houtan Bastani committed
360
361
362
void
NumConstNode::writeJsonAST(ostream &output) const
{
363
364
365
366
367
  output << "{\"node_type\" : \"NumConstNode\", \"value\" : ";
  double testval = datatree.num_constants.getDouble(id);
  if (testval < 1.0 && testval > -1.0 && testval != 0.0)
    output << "0";
  output << datatree.num_constants.get(id) << "}";
Houtan Bastani's avatar
Houtan Bastani committed
368
369
}

370
void
371
NumConstNode::writeJsonOutput(ostream &output,
372
                              const temporary_terms_t &temporary_terms,
373
                              const deriv_node_temp_terms_t &tef_terms,
374
                              const bool isdynamic) const
375
376
377
378
{
  output << datatree.num_constants.get(id);
}

379
380
381
382
383
384
bool
NumConstNode::containsExternalFunction() const
{
  return false;
}

385
double
386
NumConstNode::eval(const eval_context_t &eval_context) const noexcept(false)
387
{
388
  return (datatree.num_constants.getDouble(id));
389
390
391
}

void
392
393
394
NumConstNode::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,
395
                      const deriv_node_temp_terms_t &tef_terms) const
396
397
{
  FLDC_ fldc(datatree.num_constants.getDouble(id));
398
  fldc.write(CompileCode, instruction_number);
399
}
400

401
402
403
void
NumConstNode::collectVARLHSVariable(set<expr_t> &result) const
{
404
405
  cerr << "ERROR: you can only have variables or unary ops on LHS of VAR" << endl;
  exit(EXIT_FAILURE);
406
407
}

408
void
409
NumConstNode::collectDynamicVariables(SymbolType type_arg, set<pair<int, int>> &result) const
410
411
412
{
}

413
414
pair<int, expr_t>
NumConstNode::normalizeEquation(int var_endo, vector<tuple<int, expr_t, expr_t>> &List_of_Op_RHS) const
415
{
416
  /* return the numercial constant */
417
  return { 0, datatree.AddNonNegativeConstant(datatree.num_constants.get(id)) };
418
}
ferhat's avatar
ferhat committed
419

420
421
expr_t
NumConstNode::getChainRuleDerivative(int deriv_id, const map<int, expr_t> &recursive_variables)
ferhat's avatar
ferhat committed
422
{
ferhat's avatar
ferhat committed
423
  return datatree.Zero;
ferhat's avatar
ferhat committed
424
425
}

426
expr_t
sebastien's avatar
sebastien committed
427
NumConstNode::toStatic(DataTree &static_datatree) const
428
{
429
  return static_datatree.AddNonNegativeConstant(datatree.num_constants.get(id));
430
}
sebastien's avatar
sebastien committed
431

432
433
434
435
436
void
NumConstNode::computeXrefs(EquationInfo &ei) const
{
}

437
expr_t
438
NumConstNode::clone(DataTree &datatree) const
439
{
440
  return datatree.AddNonNegativeConstant(datatree.num_constants.get(id));
441
442
}

sebastien's avatar
sebastien committed
443
444
445
446
447
int
NumConstNode::maxEndoLead() const
{
  return 0;
}
ferhat's avatar
ferhat committed
448

sebastien's avatar
sebastien committed
449
450
451
452
453
454
int
NumConstNode::maxExoLead() const
{
  return 0;
}

455
456
457
458
459
460
461
462
463
464
465
466
int
NumConstNode::maxEndoLag() const
{
  return 0;
}

int
NumConstNode::maxExoLag() const
{
  return 0;
}

467
468
469
470
471
472
int
NumConstNode::maxLead() const
{
  return 0;
}

473
474
475
476
477
478
int
NumConstNode::maxLag() const
{
  return 0;
}

479
480
481
482
483
484
int
NumConstNode::maxLagWithDiffsExpanded() const
{
  return 0;
}

Houtan Bastani's avatar
Houtan Bastani committed
485
486
487
488
489
490
expr_t
NumConstNode::undiff() const
{
  return const_cast<NumConstNode *>(this);
}

491
492
493
494
495
496
int
NumConstNode::VarMinLag() const
{
  return 1;
}

Houtan Bastani's avatar
Houtan Bastani committed
497
498
int
NumConstNode::VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const
499
{
Houtan Bastani's avatar
Houtan Bastani committed
500
  return 0;
501
502
}

Houtan Bastani's avatar
Houtan Bastani committed
503
int
504
NumConstNode::PacMaxLag(int lhs_symb_id) const
Houtan Bastani's avatar
Houtan Bastani committed
505
506
507
508
{
  return 0;
}

509
510
511
512
513
514
int
NumConstNode::getPacTargetSymbId(int lhs_symb_id, int undiff_lhs_symb_id) const
{
  return -1;
}

515
expr_t
sebastien's avatar
sebastien committed
516
517
518
519
520
NumConstNode::decreaseLeadsLags(int n) const
{
  return const_cast<NumConstNode *>(this);
}

521
expr_t
sebastien's avatar
sebastien committed
522
NumConstNode::decreaseLeadsLagsPredeterminedVariables() const
523
{
sebastien's avatar
sebastien committed
524
  return const_cast<NumConstNode *>(this);
525
526
}

527
expr_t
528
NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
sebastien's avatar
sebastien committed
529
530
531
532
{
  return const_cast<NumConstNode *>(this);
}

533
expr_t
534
535
536
537
538
NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
  return const_cast<NumConstNode *>(this);
}

539
expr_t
540
NumConstNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
sebastien's avatar
sebastien committed
541
542
543
544
{
  return const_cast<NumConstNode *>(this);
}

545
expr_t
sebastien's avatar
sebastien committed
546
NumConstNode::substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
sebastien's avatar
sebastien committed
547
548
549
550
{
  return const_cast<NumConstNode *>(this);
}

551
expr_t
552
553
554
555
556
NumConstNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const
{
  return const_cast<NumConstNode *>(this);
}

557
expr_t
558
559
560
561
562
NumConstNode::substituteAdl() const
{
  return const_cast<NumConstNode *>(this);
}

563
564
565
566
567
568
expr_t
NumConstNode::substituteVarExpectation(const map<string, expr_t> &subst_table) const
{
  return const_cast<NumConstNode *>(this);
}

569
570
571
572
573
void
NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}

574
575
576
577
578
void
NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}

579
int
580
NumConstNode::findTargetVariable(int lhs_symb_id) const
581
582
583
584
{
  return -1;
}

585
expr_t
Houtan Bastani's avatar
Houtan Bastani committed
586
NumConstNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
587
588
589
590
{
  return const_cast<NumConstNode *>(this);
}

591
592
593
594
595
596
expr_t
NumConstNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
  return const_cast<NumConstNode *>(this);
}

597
expr_t
598
599
600
601
602
603
604
605
NumConstNode::substitutePacExpectation(const string & name, map<const PacExpectationNode *, const BinaryOpNode *> &subst_table)
{
  return const_cast<NumConstNode *>(this);
}

expr_t
NumConstNode::substitutePacExpectation(const string & name, int mce_symb_id,
                                       map<const PacExpectationNode *, const BinaryOpNode *> &subst_table)
606
607
608
609
{
  return const_cast<NumConstNode *>(this);
}

610
expr_t
611
NumConstNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
612
613
614
615
{
  return const_cast<NumConstNode *>(this);
}

616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
bool
NumConstNode::isNumConstNodeEqualTo(double value) const
{
  if (datatree.num_constants.getDouble(id) == value)
    return true;
  else
    return false;
}

bool
NumConstNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
  return false;
}

631
632
633
634
635
void
NumConstNode::getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const
{
}

636
bool
637
NumConstNode::containsPacExpectation(const string &pac_model_name) const
638
639
640
641
{
  return false;
}

642
bool
643
NumConstNode::containsEndogenous() const
644
645
646
647
{
  return false;
}

648
649
650
651
652
653
bool
NumConstNode::containsExogenous() const
{
  return false;
}

654
655
656
657
658
659
660
expr_t
NumConstNode::replaceTrendVar() const
{
  return const_cast<NumConstNode *>(this);
}

expr_t
661
NumConstNode::detrend(int symb_id, bool log_trend, expr_t trend) const
662
663
664
665
666
667
668
669
670
671
{
  return const_cast<NumConstNode *>(this);
}

expr_t
NumConstNode::removeTrendLeadLag(map<int, expr_t> trend_symbols_map) const
{
  return const_cast<NumConstNode *>(this);
}

672
673
674
675
676
677
bool
NumConstNode::isInStaticForm() const
{
  return true;
}

678
679
680
681
682
683
684
bool
NumConstNode::isParamTimesEndogExpr() const
{
  return false;
}

void
685
NumConstNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars,
686
687
688
689
                                   set<pair<int, pair<int, int>>> &ar_params_and_vars) const
{
}

690
void
691
692
693
NumConstNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share,
                                                expr_t &optim_part,
                                                expr_t &non_optim_part) const
694
695
696
697
{
}

void
698
NumConstNode::addParamInfoToPac(pair<int, int> &lhs_arg, int optim_share_arg, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars_arg, set<pair<int, pair<int, int>>> &ar_params_and_vars_arg, const vector<tuple<int, int, int, double>> &non_optim_vars_params_and_constants)
699
700
701
{
}

702
void
703
NumConstNode::fillPacExpectationVarInfo(const string &model_name_arg, vector<int> &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector<bool> &nonstationary_arg, int growth_symb_id_arg, int growth_lag_arg, int equation_number_arg)
704
705
706
{
}

707
708
709
710
711
712
bool
NumConstNode::isVarModelReferenced(const string &model_info_name) const
{
  return false;
}

713
714
715
716
717
718
expr_t
NumConstNode::substituteStaticAuxiliaryVariable() const
{
  return const_cast<NumConstNode *>(this);
}

Houtan Bastani's avatar
Houtan Bastani committed
719
void
720
NumConstNode::fillAutoregressiveRow(int eqn, const vector<int> &lhs, map<tuple<int, int, int>, expr_t> &AR) const
Houtan Bastani's avatar
Houtan Bastani committed
721
722
723
{
}

724
void
725
NumConstNode::fillErrorCorrectionRow(int eqn, const vector<int> &nontrend_lhs, const vector<int> &trend_lhs, map<tuple<int, int, int>, expr_t> &A0, map<tuple<int, int, int>, expr_t> &A0star) const
726
727
728
{
}

729
void
730
NumConstNode::findConstantEquations(map<VariableNode *, NumConstNode *> &table) const
731
732
733
734
735
{
  return;
}

expr_t
736
NumConstNode::replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const
737
738
739
740
{
  return const_cast<NumConstNode *>(this);
}

741
VariableNode::VariableNode(DataTree &datatree_arg, int idx_arg, int symb_id_arg, int lag_arg) :
742
743
744
  ExprNode{datatree_arg, idx_arg},
  symb_id{symb_id_arg},
  lag{lag_arg}
Houtan Bastani's avatar
Houtan Bastani committed
745
746
{
  // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
747
748
  assert(get_type() != SymbolType::externalFunction
         && (lag == 0 || (get_type() != SymbolType::modelLocalVariable && get_type() != SymbolType::modFileLocalVariable)));
Houtan Bastani's avatar
Houtan Bastani committed
749
750
}

sebastien's avatar
sebastien committed
751
752
753
754
755
void
VariableNode::prepareForDerivation()
{
  if (preparedForDerivation)
    return;
756

sebastien's avatar
sebastien committed
757
  preparedForDerivation = true;
sebastien's avatar
sebastien committed
758

759
  // Fill in non_null_derivatives
760
  switch (get_type())
761
    {
762
763
764
765
766
767
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
768
      // For a variable or a parameter, the only non-null derivative is with respect to itself
769
      non_null_derivatives.insert(datatree.getDerivID(symb_id, lag));
770
      break;
771
    case SymbolType::modelLocalVariable:
772
      datatree.getLocalVariable(symb_id)->prepareForDerivation();
773
      // Non null derivatives are those of the value of the local parameter
774
      non_null_derivatives = datatree.getLocalVariable(symb_id)->non_null_derivatives;
775
      break;
776
777
778
    case SymbolType::modFileLocalVariable:
    case SymbolType::statementDeclaredVariable:
    case SymbolType::unusedEndogenous:
779
780
      // Such a variable is never derived
      break;
781
782
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
783
    case SymbolType::epilogue:
sebastien's avatar
sebastien committed
784
      cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
785
      exit(EXIT_FAILURE);
786
787
788
    }
}

789
expr_t
sebastien's avatar
sebastien committed
790
VariableNode::computeDerivative(int deriv_id)
791
{
792
  switch (get_type())
793
    {
794
795
796
797
798
799
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
800
      if (deriv_id == datatree.getDerivID(symb_id, lag))
801
802
803
        return datatree.One;
      else
        return datatree.Zero;
804
    case SymbolType::modelLocalVariable:
805
      return datatree.getLocalVariable(symb_id)->getDerivative(deriv_id);
806
    case SymbolType::modFileLocalVariable:
807
      cerr << "ModFileLocalVariable is not derivable" << endl;
808
      exit(EXIT_FAILURE);
809
    case SymbolType::statementDeclaredVariable:
810
811
      cerr << "eStatementDeclaredVariable is not derivable" << endl;
      exit(EXIT_FAILURE);
812
    case SymbolType::unusedEndogenous:
813
814
      cerr << "eUnusedEndogenous is not derivable" << endl;
      exit(EXIT_FAILURE);
815
816
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
817
    case SymbolType::epilogue:
Houtan Bastani's avatar
Houtan Bastani committed
818
      cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
819
      exit(EXIT_FAILURE);
820
    }
sebastien's avatar
sebastien committed
821
  // Suppress GCC warning
822
  exit(EXIT_FAILURE);
823
824
}

825
void
826
VariableNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
827
{
828
  auto it = temporary_terms.find(const_cast<VariableNode *>(this));
829
830
  if (it != temporary_terms.end())
    temporary_terms_inuse.insert(idx);
831
  if (get_type() == SymbolType::modelLocalVariable)
832
    datatree.getLocalVariable(symb_id)->collectTemporary_terms(temporary_terms, temporary_terms_inuse, Curr_Block);
833
}
834

835
836
837
838
839
840
bool
VariableNode::containsExternalFunction() const
{
  return false;
}

Houtan Bastani's avatar
Houtan Bastani committed
841
842
843
844
845
void
VariableNode::writeJsonAST(ostream &output) const
{
  output << "{\"node_type\" : \"VariableNode\", "
         << "\"name\" : \"" << datatree.symbol_table.getName(symb_id) << "\", \"type\" : \"";
846
  switch (get_type())
Houtan Bastani's avatar
Houtan Bastani committed
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
    {
    case SymbolType::endogenous:
      output << "endogenous";
      break;
    case SymbolType::exogenous:
      output << "exogenous";
      break;
    case SymbolType::exogenousDet:
      output << "exogenousDet";
      break;
    case SymbolType::parameter:
      output << "parameter";
      break;
    case SymbolType::modelLocalVariable:
      output << "modelLocalVariable";
      break;
    case SymbolType::modFileLocalVariable:
      output << "modFileLocalVariable";
      break;
    case SymbolType::externalFunction:
      output << "externalFunction";
      break;
    case SymbolType::trend:
      output << "trend";
      break;
    case SymbolType::statementDeclaredVariable:
      output << "statementDeclaredVariable";
      break;
    case SymbolType::logTrend:
      output << "logTrend:";
      break;
    case SymbolType::unusedEndogenous:
      output << "unusedEndogenous";
      break;
    case SymbolType::endogenousVAR:
      output << "endogenousVAR";
      break;
884
885
886
    case SymbolType::epilogue:
      output << "epilogue";
      break;
Houtan Bastani's avatar
Houtan Bastani committed
887
888
889
890
    }
  output << "\", \"lag\" : " << lag << "}";
}

891
void
892
VariableNode::writeJsonOutput(ostream &output,
893
                              const temporary_terms_t &temporary_terms,
894
                              const deriv_node_temp_terms_t &tef_terms,
895
                              const bool isdynamic) const
896
{
897
  auto it = temporary_terms.find(const_cast<VariableNode *>(this));
898
899
900
901
902
903
  if (it != temporary_terms.end())
    {
      output << "T" << idx;
      return;
    }

904
  output << datatree.symbol_table.getName(symb_id);
905
  if (isdynamic && lag != 0)
906
907
908
    output << "(" << lag << ")";
}

909
910
void
VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
911
                          const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
912
                          const temporary_terms_idxs_t &temporary_terms_idxs,
913
                          const deriv_node_temp_terms_t &tef_terms) const
914
{
915
  auto type = get_type();
916
917
  if (checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
    return;
918

919
  if (isLatexOutput(output_type))
920
    {
921
      if (output_type == ExprNodeOutputType::latexDynamicSteadyStateOperator)
922
923
        output << "\\bar";
      output << "{" << datatree.symbol_table.getTeXName(symb_id);
924
      if (output_type == ExprNodeOutputType::latexDynamicModel
925
          && (type == SymbolType::endogenous || type == SymbolType::exogenous || type == SymbolType::exogenousDet || type == SymbolType::modelLocalVariable || type == SymbolType::trend || type == SymbolType::logTrend))
926
927
928
929
930
931
932
933
        {
          output << "_{t";
          if (lag != 0)
            {
              if (lag > 0)
                output << "+";
              output << lag;
            }
934
          output << "}";
935
        }
936
      output << "}";
937
938
      return;
    }
939

940
941
942
943
  int i;
  int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
  switch (type)
    {
944
    case SymbolType::parameter:
945
      if (output_type == ExprNodeOutputType::matlabOutsideModel)
946
947
948
949
        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;
ferhat's avatar
ferhat committed
950

951
    case SymbolType::modelLocalVariable:
952
953
954
      if (output_type == ExprNodeOutputType::matlabDynamicModelSparse || output_type == ExprNodeOutputType::matlabStaticModelSparse
          || output_type == ExprNodeOutputType::matlabDynamicSteadyStateOperator || output_type == ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator
          || output_type == ExprNodeOutputType::CDynamicSteadyStateOperator)
955
956
        {
          output << "(";
957
          datatree.getLocalVariable(symb_id)->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
958
959
960
          output << ")";
        }
      else
Sébastien Villemot's avatar
Sébastien Villemot committed
961
962
        /* We append underscores to avoid name clashes with "g1" or "oo_".
           But we probably never arrive here because MLV are temporary terms… */
963
        output << datatree.symbol_table.getName(symb_id) << "__";
964
      break;
ferhat's avatar
ferhat committed
965

966
    case SymbolType::modFileLocalVariable:
967
968
969
      output << datatree.symbol_table.getName(symb_id);
      break;

970
    case SymbolType::endogenous:
971
972
      switch (output_type)
        {
973
974
975
        case ExprNodeOutputType::juliaDynamicModel:
        case ExprNodeOutputType::matlabDynamicModel:
        case ExprNodeOutputType::CDynamicModel:
976
977
978
          i = datatree.getDynJacobianCol(datatree.getDerivID(symb_id, lag)) + ARRAY_SUBSCRIPT_OFFSET(output_type);
          output <<  "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
979
980
981
982
        case ExprNodeOutputType::CStaticModel:
        case ExprNodeOutputType::juliaStaticModel:
        case ExprNodeOutputType::matlabStaticModel:
        case ExprNodeOutputType::matlabStaticModelSparse:
983
984
985
          i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
          output <<  "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
986
        case ExprNodeOutputType::matlabDynamicModelSparse:
987
988
989
990
991
992
993
994
          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;
995
        case ExprNodeOutputType::matlabOutsideModel:
996
997
          output << "oo_.steady_state(" << tsid + 1 << ")";
          break;
998
999
1000
        case ExprNodeOutputType::juliaDynamicSteadyStateOperator:
        case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
        case ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator:
Houtan Bastani's avatar
Houtan Bastani committed
1001
          output << "steady_state" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
1002
          break;
1003
        case ExprNodeOutputType::CDynamicSteadyStateOperator:
1004
1005
          output << "steady_state[" << tsid << "]";
          break;
1006
1007
        case ExprNodeOutputType::juliaSteadyStateFile:
        case ExprNodeOutputType::steadyStateFile:
Houtan Bastani's avatar
Houtan Bastani committed
1008
          output << "ys_" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
1009
          break;
1010
        case ExprNodeOutputType::matlabDseries:
1011
1012
1013
1014
          output << "ds." << datatree.symbol_table.getName(symb_id);
          if (lag != 0)
            output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
1015
        case ExprNodeOutputType::epilogueFile:
Houtan Bastani's avatar
Houtan Bastani committed
1016
          output << "dseries__." << datatree.symbol_table.getName(symb_id);
1017
1018
1019
1020
          output << LEFT_ARRAY_SUBSCRIPT(output_type) << "t";
          if (lag != 0)
            output << lag;
          output << RIGHT_ARRAY_SUBSCRIPT(output_type);
Houtan Bastani's avatar
Houtan Bastani committed
1021
          break;
1022
        default:
1023
1024
          cerr << "VariableNode::writeOutput: should not reach this point" << endl;
          exit(EXIT_FAILURE);
1025
1026
        }
      break;
ferhat's avatar
ferhat committed
1027

1028
    case SymbolType::exogenous:
1029
1030
1031
      i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
      switch (output_type)
        {
1032
1033
1034
        case ExprNodeOutputType::juliaDynamicModel:
        case ExprNodeOutputType::matlabDynamicModel:
        case ExprNodeOutputType::matlabDynamicModelSparse:
1035
          if (lag > 0)
Houtan Bastani's avatar
Houtan Bastani committed
1036
1037
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1038
          else if (lag < 0)
Houtan Bastani's avatar
Houtan Bastani committed
1039
1040
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1041
          else
Houtan Bastani's avatar
Houtan Bastani committed
1042
1043
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1044
          break;
1045
        case ExprNodeOutputType::CDynamicModel:
1046
1047
1048
1049
1050
1051
1052
          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;
1053
1054
1055
1056
        case ExprNodeOutputType::CStaticModel:
        case ExprNodeOutputType::juliaStaticModel:
        case ExprNodeOutputType::matlabStaticModel:
        case ExprNodeOutputType::matlabStaticModelSparse:
1057
1058
          output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
1059
        case ExprNodeOutputType::matlabOutsideModel:
1060
          assert(lag == 0);
1061
          output <<  "oo_.exo_steady_state(" << i << ")";
1062
          break;
1063
        case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
1064
          output <<  "oo_.exo_steady_state(" << i << ")";
1065
          break;
1066
1067
        case ExprNodeOutputType::juliaSteadyStateFile:
        case ExprNodeOutputType::steadyStateFile:
Houtan Bastani's avatar
Houtan Bastani committed
1068
          output << "exo_" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
1069
          break;
1070
        case ExprNodeOutputType::matlabDseries:
1071
1072
1073
1074
          output << "ds." << datatree.symbol_table.getName(symb_id);
          if (lag != 0)
            output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
1075
        case ExprNodeOutputType::epilogueFile:
Houtan Bastani's avatar
Houtan Bastani committed
1076
          output << "dseries__." << datatree.symbol_table.getName(symb_id);
1077
          output << LEFT_ARRAY_SUBSCRIPT(output_type) << "t";
Houtan Bastani's avatar
Houtan Bastani committed
1078
          if (lag != 0)
1079
1080
            output << lag;
          output << RIGHT_ARRAY_SUBSCRIPT(output_type);
Houtan Bastani's avatar
Houtan Bastani committed
1081
          break;
1082
        default:
1083
1084
          cerr << "VariableNode::writeOutput: should not reach this point" << endl;
          exit(EXIT_FAILURE);
1085
1086
        }
      break;
ferhat's avatar
ferhat committed
1087

1088
    case SymbolType::exogenousDet:
1089
1090
1091
      i = tsid + datatree.symbol_table.exo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
      switch (output_type)
        {
1092
1093
1094
        case ExprNodeOutputType::juliaDynamicModel:
        case ExprNodeOutputType::matlabDynamicModel:
        case ExprNodeOutputType::matlabDynamicModelSparse:
1095
          if (lag > 0)
Houtan Bastani's avatar
Houtan Bastani committed
1096
1097
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1098
          else if (lag < 0)
Houtan Bastani's avatar
Houtan Bastani committed
1099
1100
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1101
          else
Houtan Bastani's avatar
Houtan Bastani committed
1102
1103
            output <<  "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i
                   << RIGHT_ARRAY_SUBSCRIPT(output_type);
1104
          break;
1105
        case ExprNodeOutputType::CDynamicModel: