ExprNode.cc 328 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
expr_t
sebastien's avatar
sebastien committed
510
511
512
513
514
NumConstNode::decreaseLeadsLags(int n) const
{
  return const_cast<NumConstNode *>(this);
}

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

521
expr_t
522
NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
sebastien's avatar
sebastien committed
523
524
525
526
{
  return const_cast<NumConstNode *>(this);
}

527
expr_t
528
529
530
531
532
NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
  return const_cast<NumConstNode *>(this);
}

533
expr_t
534
NumConstNode::substituteExoLead(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
sebastien's avatar
sebastien committed
535
536
537
538
{
  return const_cast<NumConstNode *>(this);
}

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

545
expr_t
546
547
548
549
550
NumConstNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const
{
  return const_cast<NumConstNode *>(this);
}

551
expr_t
552
553
554
555
556
NumConstNode::substituteAdl() const
{
  return const_cast<NumConstNode *>(this);
}

557
558
559
560
561
562
expr_t
NumConstNode::substituteVarExpectation(const map<string, expr_t> &subst_table) const
{
  return const_cast<NumConstNode *>(this);
}

563
564
565
566
567
void
NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}

568
569
570
571
572
void
NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}

573
int
574
NumConstNode::findTargetVariable(int lhs_symb_id) const
575
576
577
578
{
  return -1;
}

579
expr_t
Houtan Bastani's avatar
Houtan Bastani committed
580
NumConstNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
581
582
583
584
{
  return const_cast<NumConstNode *>(this);
}

585
586
587
588
589
590
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);
}

591
expr_t
592
NumConstNode::substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table)
593
594
595
596
{
  return const_cast<NumConstNode *>(this);
}

597
expr_t
598
NumConstNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
599
600
601
602
{
  return const_cast<NumConstNode *>(this);
}

603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
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;
}

618
619
620
621
622
void
NumConstNode::getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const
{
}

623
bool
624
NumConstNode::containsPacExpectation(const string &pac_model_name) const
625
626
627
628
{
  return false;
}

629
bool
630
NumConstNode::containsEndogenous() const
631
632
633
634
{
  return false;
}

635
636
637
638
639
640
bool
NumConstNode::containsExogenous() const
{
  return false;
}

641
642
643
644
645
646
647
expr_t
NumConstNode::replaceTrendVar() const
{
  return const_cast<NumConstNode *>(this);
}

expr_t
648
NumConstNode::detrend(int symb_id, bool log_trend, expr_t trend) const
649
650
651
652
653
654
655
656
657
658
{
  return const_cast<NumConstNode *>(this);
}

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

659
660
661
662
663
664
bool
NumConstNode::isInStaticForm() const
{
  return true;
}

665
666
667
668
669
670
671
bool
NumConstNode::isParamTimesEndogExpr() const
{
  return false;
}

void
672
NumConstNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars,
673
674
675
676
                                   set<pair<int, pair<int, int>>> &ar_params_and_vars) const
{
}

677
void
678
679
680
NumConstNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share,
                                                expr_t &optim_part,
                                                expr_t &non_optim_part) const
681
682
683
684
{
}

void
685
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)
686
687
688
{
}

689
void
690
NumConstNode::fillPacExpectationVarInfo(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)
691
692
693
{
}

694
695
696
697
698
699
bool
NumConstNode::isVarModelReferenced(const string &model_info_name) const
{
  return false;
}

700
701
702
703
704
705
expr_t
NumConstNode::substituteStaticAuxiliaryVariable() const
{
  return const_cast<NumConstNode *>(this);
}

Houtan Bastani's avatar
Houtan Bastani committed
706
void
707
NumConstNode::fillAutoregressiveRow(int eqn, const vector<int> &lhs, map<tuple<int, int, int>, expr_t> &AR) const
Houtan Bastani's avatar
Houtan Bastani committed
708
709
710
{
}

711
void
712
NumConstNode::fillErrorCorrectionRow(int eqn, const vector<int> &nontrend_lhs, const vector<int> &trend_lhs, map<tuple<int, int, int>, expr_t> &EC) const
713
714
715
{
}

716
void
717
NumConstNode::findConstantEquations(map<VariableNode *, NumConstNode *> &table) const
718
719
720
721
722
{
  return;
}

expr_t
723
NumConstNode::replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const
724
725
726
727
{
  return const_cast<NumConstNode *>(this);
}

728
VariableNode::VariableNode(DataTree &datatree_arg, int idx_arg, int symb_id_arg, int lag_arg) :
729
730
731
  ExprNode{datatree_arg, idx_arg},
  symb_id{symb_id_arg},
  lag{lag_arg}
Houtan Bastani's avatar
Houtan Bastani committed
732
733
{
  // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
734
735
  assert(get_type() != SymbolType::externalFunction
         && (lag == 0 || (get_type() != SymbolType::modelLocalVariable && get_type() != SymbolType::modFileLocalVariable)));
Houtan Bastani's avatar
Houtan Bastani committed
736
737
}

sebastien's avatar
sebastien committed
738
739
740
741
742
void
VariableNode::prepareForDerivation()
{
  if (preparedForDerivation)
    return;
743

sebastien's avatar
sebastien committed
744
  preparedForDerivation = true;
sebastien's avatar
sebastien committed
745

746
  // Fill in non_null_derivatives
747
  switch (get_type())
748
    {
749
750
751
752
753
754
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
755
      // For a variable or a parameter, the only non-null derivative is with respect to itself
756
      non_null_derivatives.insert(datatree.getDerivID(symb_id, lag));
757
      break;
758
    case SymbolType::modelLocalVariable:
759
      datatree.getLocalVariable(symb_id)->prepareForDerivation();
760
      // Non null derivatives are those of the value of the local parameter
761
      non_null_derivatives = datatree.getLocalVariable(symb_id)->non_null_derivatives;
762
      break;
763
764
765
    case SymbolType::modFileLocalVariable:
    case SymbolType::statementDeclaredVariable:
    case SymbolType::unusedEndogenous:
766
767
      // Such a variable is never derived
      break;
768
769
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
770
    case SymbolType::epilogue:
sebastien's avatar
sebastien committed
771
      cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
772
      exit(EXIT_FAILURE);
773
774
775
    }
}

776
expr_t
sebastien's avatar
sebastien committed
777
VariableNode::computeDerivative(int deriv_id)
778
{
779
  switch (get_type())
780
    {
781
782
783
784
785
786
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
787
      if (deriv_id == datatree.getDerivID(symb_id, lag))
788
789
790
        return datatree.One;
      else
        return datatree.Zero;
791
    case SymbolType::modelLocalVariable:
792
      return datatree.getLocalVariable(symb_id)->getDerivative(deriv_id);
793
    case SymbolType::modFileLocalVariable:
794
      cerr << "ModFileLocalVariable is not derivable" << endl;
795
      exit(EXIT_FAILURE);
796
    case SymbolType::statementDeclaredVariable:
797
798
      cerr << "eStatementDeclaredVariable is not derivable" << endl;
      exit(EXIT_FAILURE);
799
    case SymbolType::unusedEndogenous:
800
801
      cerr << "eUnusedEndogenous is not derivable" << endl;
      exit(EXIT_FAILURE);
802
803
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
804
    case SymbolType::epilogue:
Houtan Bastani's avatar
Houtan Bastani committed
805
      cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
806
      exit(EXIT_FAILURE);
807
    }
sebastien's avatar
sebastien committed
808
  // Suppress GCC warning
809
  exit(EXIT_FAILURE);
810
811
}

812
void
813
VariableNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
814
{
815
  auto it = temporary_terms.find(const_cast<VariableNode *>(this));
816
817
  if (it != temporary_terms.end())
    temporary_terms_inuse.insert(idx);
818
  if (get_type() == SymbolType::modelLocalVariable)
819
    datatree.getLocalVariable(symb_id)->collectTemporary_terms(temporary_terms, temporary_terms_inuse, Curr_Block);
820
}
821

822
823
824
825
826
827
bool
VariableNode::containsExternalFunction() const
{
  return false;
}

Houtan Bastani's avatar
Houtan Bastani committed
828
829
830
831
832
void
VariableNode::writeJsonAST(ostream &output) const
{
  output << "{\"node_type\" : \"VariableNode\", "
         << "\"name\" : \"" << datatree.symbol_table.getName(symb_id) << "\", \"type\" : \"";
833
  switch (get_type())
Houtan Bastani's avatar
Houtan Bastani committed
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
    {
    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;
871
872
873
    case SymbolType::epilogue:
      output << "epilogue";
      break;
Houtan Bastani's avatar
Houtan Bastani committed
874
875
876
877
    }
  output << "\", \"lag\" : " << lag << "}";
}

878
void
879
VariableNode::writeJsonOutput(ostream &output,
880
                              const temporary_terms_t &temporary_terms,
881
                              const deriv_node_temp_terms_t &tef_terms,
882
                              const bool isdynamic) const
883
{
884
  auto it = temporary_terms.find(const_cast<VariableNode *>(this));
885
886
887
888
889
890
  if (it != temporary_terms.end())
    {
      output << "T" << idx;
      return;
    }

891
  output << datatree.symbol_table.getName(symb_id);
892
  if (isdynamic && lag != 0)
893
894
895
    output << "(" << lag << ")";
}

896
897
void
VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
898
                          const temporary_terms_t &temporary_terms,
Houtan Bastani's avatar
Houtan Bastani committed
899
                          const temporary_terms_idxs_t &temporary_terms_idxs,
900
                          const deriv_node_temp_terms_t &tef_terms) const
901
{
902
  auto type = get_type();
903
904
  if (checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
    return;
905

906
  if (isLatexOutput(output_type))
907
    {
908
      if (output_type == ExprNodeOutputType::latexDynamicSteadyStateOperator)
909
910
        output << "\\bar";
      output << "{" << datatree.symbol_table.getTeXName(symb_id);
911
      if (output_type == ExprNodeOutputType::latexDynamicModel
912
          && (type == SymbolType::endogenous || type == SymbolType::exogenous || type == SymbolType::exogenousDet || type == SymbolType::modelLocalVariable || type == SymbolType::trend || type == SymbolType::logTrend))
913
914
915
916
917
918
919
920
        {
          output << "_{t";
          if (lag != 0)
            {
              if (lag > 0)
                output << "+";
              output << lag;
            }
921
          output << "}";
922
        }
923
      output << "}";
924
925
      return;
    }
926

927
928
929
930
  int i;
  int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
  switch (type)
    {
931
    case SymbolType::parameter:
932
      if (output_type == ExprNodeOutputType::matlabOutsideModel)
933
934
935
936
        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
937

938
    case SymbolType::modelLocalVariable:
939
940
941
      if (output_type == ExprNodeOutputType::matlabDynamicModelSparse || output_type == ExprNodeOutputType::matlabStaticModelSparse
          || output_type == ExprNodeOutputType::matlabDynamicSteadyStateOperator || output_type == ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator
          || output_type == ExprNodeOutputType::CDynamicSteadyStateOperator)
942
943
        {
          output << "(";
944
          datatree.getLocalVariable(symb_id)->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
945
946
947
          output << ")";
        }
      else
Sébastien Villemot's avatar
Sébastien Villemot committed
948
949
        /* We append underscores to avoid name clashes with "g1" or "oo_".
           But we probably never arrive here because MLV are temporary terms… */
950
        output << datatree.symbol_table.getName(symb_id) << "__";
951
      break;
ferhat's avatar
ferhat committed
952

953
    case SymbolType::modFileLocalVariable:
954
955
956
      output << datatree.symbol_table.getName(symb_id);
      break;

957
    case SymbolType::endogenous:
958
959
      switch (output_type)
        {
960
961
962
        case ExprNodeOutputType::juliaDynamicModel:
        case ExprNodeOutputType::matlabDynamicModel:
        case ExprNodeOutputType::CDynamicModel:
963
964
965
          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;
966
967
968
969
        case ExprNodeOutputType::CStaticModel:
        case ExprNodeOutputType::juliaStaticModel:
        case ExprNodeOutputType::matlabStaticModel:
        case ExprNodeOutputType::matlabStaticModelSparse:
970
971
972
          i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
          output <<  "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
          break;
973
        case ExprNodeOutputType::matlabDynamicModelSparse:
974
975
976
977
978
979
980
981
          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;
982
        case ExprNodeOutputType::matlabOutsideModel:
983
984
          output << "oo_.steady_state(" << tsid + 1 << ")";
          break;
985
986
987
        case ExprNodeOutputType::juliaDynamicSteadyStateOperator:
        case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
        case ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator:
Houtan Bastani's avatar
Houtan Bastani committed
988
          output << "steady_state" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
989
          break;
990
        case ExprNodeOutputType::CDynamicSteadyStateOperator:
991
992
          output << "steady_state[" << tsid << "]";
          break;
993
994
        case ExprNodeOutputType::juliaSteadyStateFile:
        case ExprNodeOutputType::steadyStateFile:
Houtan Bastani's avatar
Houtan Bastani committed
995
          output << "ys_" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
996
          break;
997
        case ExprNodeOutputType::matlabDseries:
998
999
1000
          output << "ds." << datatree.symbol_table.getName(symb_id);
          if (lag != 0)
            output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);