ExprNode.cc 323 KB
Newer Older
1
/*
2
 * Copyright (C) 2007-2018 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
{
}

ExprNode::~ExprNode()
38
= default;
39

40
expr_t
41
ExprNode::getDerivative(int deriv_id)
42
{
sebastien's avatar
sebastien committed
43
44
  if (!preparedForDerivation)
    prepareForDerivation();
45

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

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

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

70
71
72
73
74
75
76
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;
}

77
int
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
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
ExprNode::cost(const map<NodeTreeReference, temporary_terms_t> &temp_terms_map, bool is_matlab) const
93
94
95
96
{
  // For a terminal node, the cost is null
  return 0;
}
97

98
99
100
101
102
103
104
105
106
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;

107
  if (output_type == ExprNodeOutputType::matlabDynamicModelSparse)
108
109
    output << "T" << idx << "(it_)";
  else
110
    if (output_type == ExprNodeOutputType::matlabStaticModelSparse)
111
112
113
114
115
116
117
      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)
118
               << it2->second + ARRAY_SUBSCRIPT_OFFSET(output_type)
119
120
121
122
123
               << RIGHT_ARRAY_SUBSCRIPT(output_type);
      }
  return true;
}

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

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

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

151
void
152
ExprNode::computeTemporaryTerms(map<expr_t, pair<int, NodeTreeReference>> &reference_count,
153
                                map<NodeTreeReference, temporary_terms_t> &temp_terms_map,
Houtan Bastani's avatar
temp    
Houtan Bastani committed
154
                                bool is_matlab, NodeTreeReference tr) const
155
156
157
{
  // Nothing to do for a terminal node
}
158
159

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

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

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

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

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

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

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

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

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

sebastien's avatar
sebastien committed
230
VariableNode *
231
ExprNode::createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
sebastien's avatar
sebastien committed
232
233
234
235
236
237
238
239
{
  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);

240
  expr_t substexpr = decreaseLeadsLags(n-1);
sebastien's avatar
sebastien committed
241
242
243
244
  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))
245
  while (lag >= 0)
sebastien's avatar
sebastien committed
246
    {
247
      expr_t orig_expr = decreaseLeadsLags(lag);
sebastien's avatar
sebastien committed
248
249
250
      it = subst_table.find(orig_expr);
      if (it == subst_table.end())
        {
251
          int symb_id = datatree.symbol_table.addEndoLeadAuxiliaryVar(orig_expr->idx, substexpr);
sebastien's avatar
sebastien committed
252
253
          neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
          substexpr = datatree.AddVariable(symb_id, +1);
254
          assert(dynamic_cast<VariableNode *>(substexpr) != nullptr);
sebastien's avatar
sebastien committed
255
256
257
258
259
260
261
262
263
264
265
          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
266
267
268
269
270
271
272
273
274
275
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);

276
  expr_t substexpr = decreaseLeadsLags(n);
sebastien's avatar
sebastien committed
277
278
279
280
  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))
281
  while (lag >= 0)
sebastien's avatar
sebastien committed
282
    {
283
      expr_t orig_expr = decreaseLeadsLags(lag);
sebastien's avatar
sebastien committed
284
285
286
      it = subst_table.find(orig_expr);
      if (it == subst_table.end())
        {
287
          int symb_id = datatree.symbol_table.addExoLeadAuxiliaryVar(orig_expr->idx, substexpr);
sebastien's avatar
sebastien committed
288
289
          neweqs.push_back(dynamic_cast<BinaryOpNode *>(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
          substexpr = datatree.AddVariable(symb_id, +1);
290
          assert(dynamic_cast<VariableNode *>(substexpr) != nullptr);
sebastien's avatar
sebastien committed
291
292
293
294
295
296
297
298
299
300
301
          subst_table[orig_expr] = dynamic_cast<VariableNode *>(substexpr);
        }
      else
        substexpr = const_cast<VariableNode *>(it->second);

      lag--;
    }

  return dynamic_cast<VariableNode *>(substexpr);
}

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

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

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

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

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

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

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

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

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

Houtan Bastani's avatar
Houtan Bastani committed
362
363
364
365
366
367
void
NumConstNode::writeJsonAST(ostream &output) const
{
  output << "{\"node_type\" : \"NumConstNode\", \"value\" : " << datatree.num_constants.get(id) << "}";
}

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

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

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

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

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

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

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

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

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

430
431
432
433
434
void
NumConstNode::computeXrefs(EquationInfo &ei) const
{
}

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

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

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

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

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

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

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

Houtan Bastani's avatar
Houtan Bastani committed
477
478
479
480
481
482
expr_t
NumConstNode::undiff() const
{
  return const_cast<NumConstNode *>(this);
}

483
484
485
486
487
488
int
NumConstNode::VarMinLag() const
{
  return 1;
}

Houtan Bastani's avatar
Houtan Bastani committed
489
490
int
NumConstNode::VarMaxLag(DataTree &static_datatree, set<expr_t> &static_lhs) const
491
{
Houtan Bastani's avatar
Houtan Bastani committed
492
  return 0;
493
494
}

Houtan Bastani's avatar
Houtan Bastani committed
495
int
496
NumConstNode::PacMaxLag(int lhs_symb_id) const
Houtan Bastani's avatar
Houtan Bastani committed
497
498
499
500
{
  return 0;
}

501
expr_t
sebastien's avatar
sebastien committed
502
503
504
505
506
NumConstNode::decreaseLeadsLags(int n) const
{
  return const_cast<NumConstNode *>(this);
}

507
expr_t
sebastien's avatar
sebastien committed
508
NumConstNode::decreaseLeadsLagsPredeterminedVariables() const
509
{
sebastien's avatar
sebastien committed
510
  return const_cast<NumConstNode *>(this);
511
512
}

513
expr_t
514
NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool deterministic_model) const
sebastien's avatar
sebastien committed
515
516
517
518
{
  return const_cast<NumConstNode *>(this);
}

519
expr_t
520
521
522
523
524
NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
  return const_cast<NumConstNode *>(this);
}

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

531
expr_t
sebastien's avatar
sebastien committed
532
NumConstNode::substituteExoLag(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
sebastien's avatar
sebastien committed
533
534
535
536
{
  return const_cast<NumConstNode *>(this);
}

537
expr_t
538
539
540
541
542
NumConstNode::substituteExpectation(subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs, bool partial_information_model) const
{
  return const_cast<NumConstNode *>(this);
}

543
expr_t
544
545
546
547
548
NumConstNode::substituteAdl() const
{
  return const_cast<NumConstNode *>(this);
}

549
550
551
552
553
554
expr_t
NumConstNode::substituteVarExpectation(const map<string, expr_t> &subst_table) const
{
  return const_cast<NumConstNode *>(this);
}

555
556
557
558
559
void
NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}

560
561
562
563
564
void
NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}

565
int
566
NumConstNode::findTargetVariable(int lhs_symb_id) const
567
568
569
570
{
  return -1;
}

571
expr_t
Houtan Bastani's avatar
Houtan Bastani committed
572
NumConstNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
573
574
575
576
{
  return const_cast<NumConstNode *>(this);
}

577
578
579
580
581
582
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);
}

583
expr_t
584
NumConstNode::substitutePacExpectation(map<const PacExpectationNode *, const BinaryOpNode *> &subst_table)
585
586
587
588
{
  return const_cast<NumConstNode *>(this);
}

589
expr_t
590
NumConstNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
591
592
593
594
{
  return const_cast<NumConstNode *>(this);
}

595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
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;
}

610
611
612
613
614
void
NumConstNode::getEndosAndMaxLags(map<string, int> &model_endos_and_lags) const
{
}

615
bool
616
NumConstNode::containsPacExpectation(const string &pac_model_name) const
617
618
619
620
{
  return false;
}

621
bool
622
NumConstNode::containsEndogenous() const
623
624
625
626
{
  return false;
}

627
628
629
630
631
632
bool
NumConstNode::containsExogenous() const
{
  return false;
}

633
634
635
636
637
638
639
expr_t
NumConstNode::replaceTrendVar() const
{
  return const_cast<NumConstNode *>(this);
}

expr_t
640
NumConstNode::detrend(int symb_id, bool log_trend, expr_t trend) const
641
642
643
644
645
646
647
648
649
650
{
  return const_cast<NumConstNode *>(this);
}

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

651
652
653
654
655
656
bool
NumConstNode::isInStaticForm() const
{
  return true;
}

657
658
659
660
661
662
663
bool
NumConstNode::isParamTimesEndogExpr() const
{
  return false;
}

void
664
NumConstNode::getPacOptimizingPart(int lhs_orig_symb_id, pair<int, pair<vector<int>, vector<bool>>> &ec_params_and_vars,
665
666
667
668
                                   set<pair<int, pair<int, int>>> &ar_params_and_vars) const
{
}

669
void
670
671
672
NumConstNode::getPacOptimizingShareAndExprNodes(set<int> &optim_share,
                                                expr_t &optim_part,
                                                expr_t &non_optim_part) const
673
674
675
676
{
}

void
677
678
679
680
681
682
NumConstNode::getPacNonOptimizingPart(set<pair<int, pair<pair<int, int>, double>>>
                                      &params_vars_and_scaling_factor) const
{
}

void
683
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, set<pair<int, pair<pair<int, int>, double>>> &params_vars_and_scaling_factor_arg)
684
685
686
{
}

687
void
688
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 equation_number_arg)
689
690
691
{
}

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

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

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

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

714
VariableNode::VariableNode(DataTree &datatree_arg, int idx_arg, int symb_id_arg, int lag_arg) :
715
716
717
  ExprNode{datatree_arg, idx_arg},
  symb_id{symb_id_arg},
  lag{lag_arg}
Houtan Bastani's avatar
Houtan Bastani committed
718
719
{
  // It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
720
721
  assert(get_type() != SymbolType::externalFunction
         && (lag == 0 || (get_type() != SymbolType::modelLocalVariable && get_type() != SymbolType::modFileLocalVariable)));
Houtan Bastani's avatar
Houtan Bastani committed
722
723
}

sebastien's avatar
sebastien committed
724
725
726
727
728
void
VariableNode::prepareForDerivation()
{
  if (preparedForDerivation)
    return;
729

sebastien's avatar
sebastien committed
730
  preparedForDerivation = true;
sebastien's avatar
sebastien committed
731

732
  // Fill in non_null_derivatives
733
  switch (get_type())
734
    {
735
736
737
738
739
740
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
741
      // For a variable or a parameter, the only non-null derivative is with respect to itself
742
      non_null_derivatives.insert(datatree.getDerivID(symb_id, lag));
743
      break;
744
    case SymbolType::modelLocalVariable:
745
      datatree.getLocalVariable(symb_id)->prepareForDerivation();
746
      // Non null derivatives are those of the value of the local parameter
747
      non_null_derivatives = datatree.getLocalVariable(symb_id)->non_null_derivatives;
748
      break;
749
750
751
    case SymbolType::modFileLocalVariable:
    case SymbolType::statementDeclaredVariable:
    case SymbolType::unusedEndogenous:
752
753
      // Such a variable is never derived
      break;
754
755
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
Houtan Bastani's avatar
Houtan Bastani committed
756
757
758
    case SymbolType::endogenousEpilogue:
    case SymbolType::exogenousEpilogue:
    case SymbolType::parameterEpilogue:
sebastien's avatar
sebastien committed
759
      cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
760
      exit(EXIT_FAILURE);
761
762
763
    }
}

764
expr_t
sebastien's avatar
sebastien committed
765
VariableNode::computeDerivative(int deriv_id)
766
{
767
  switch (get_type())
768
    {
769
770
771
772
773
774
    case SymbolType::endogenous:
    case SymbolType::exogenous:
    case SymbolType::exogenousDet:
    case SymbolType::parameter:
    case SymbolType::trend:
    case SymbolType::logTrend:
sebastien's avatar
sebastien committed
775
      if (deriv_id == datatree.getDerivID(symb_id, lag))
776
777
778
        return datatree.One;
      else
        return datatree.Zero;
779
    case SymbolType::modelLocalVariable:
780
      return datatree.getLocalVariable(symb_id)->getDerivative(deriv_id);
781
    case SymbolType::modFileLocalVariable:
782
      cerr << "ModFileLocalVariable is not derivable" << endl;
783
      exit(EXIT_FAILURE);
784
    case SymbolType::statementDeclaredVariable:
785
786
      cerr << "eStatementDeclaredVariable is not derivable" << endl;
      exit(EXIT_FAILURE);
787
    case SymbolType::unusedEndogenous:
788
789
      cerr << "eUnusedEndogenous is not derivable" << endl;
      exit(EXIT_FAILURE);
790
791
    case SymbolType::externalFunction:
    case SymbolType::endogenousVAR:
Houtan Bastani's avatar
Houtan Bastani committed
792
793
794
795
    case SymbolType::endogenousEpilogue:
    case SymbolType::exogenousEpilogue:
    case SymbolType::parameterEpilogue:
      cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
796
      exit(EXIT_FAILURE);
797
    }
sebastien's avatar
sebastien committed
798
  // Suppress GCC warning
799
  exit(EXIT_FAILURE);
800
801
}

802
void
803
VariableNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
804
{
805
  auto it = temporary_terms.find(const_cast<VariableNode *>(this));
806
807
  if (it != temporary_terms.end())
    temporary_terms_inuse.insert(idx);
808
  if (get_type() == SymbolType::modelLocalVariable)
809
    datatree.getLocalVariable(symb_id)->collectTemporary_terms(temporary_terms, temporary_terms_inuse, Curr_Block);
810
}
811

812
813
814
815
816
817
bool
VariableNode::containsExternalFunction() const
{
  return false;
}

Houtan Bastani's avatar
Houtan Bastani committed
818
819
820
821
822
void
VariableNode::writeJsonAST(ostream &output) const
{
  output << "{\"node_type\" : \"VariableNode\", "
         << "\"name\" : \"" << datatree.symbol_table.getName(symb_id) << "\", \"type\" : \"";
823
  switch (get_type())
Houtan Bastani's avatar
Houtan Bastani committed
824
825
826
827
828
829
830
831
832
833
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
871
872
873
    {
    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;
    case SymbolType::endogenousEpilogue:
      output << "endogenousEpilogue";
      break;
    case SymbolType::exogenousEpilogue:
      output << "exogenousEpilogue";
      break;
    case SymbolType::parameterEpilogue:
      output << "parameterEpilogue";
      break;
    }
  output << "\", \"lag\" : " << lag << "}";
}

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

887
  output << datatree.symbol_table.getName(symb_id);
888
  if (isdynamic && lag != 0)
889
890
891
    output << "(" << lag << ")";
}

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

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

923
924
925
926
  int i;
  int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
  switch (type)
    {
927
    case SymbolType::parameter:
Houtan Bastani's avatar
Houtan Bastani committed
928
    case SymbolType::parameterEpilogue:
929
      if (output_type == ExprNodeOutputType::matlabOutsideModel)
930
931
932
933
        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
934

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

950
    case SymbolType::modFileLocalVariable:
951
952
953
      output << datatree.symbol_table.getName(symb_id);
      break;

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