1 /*
2  * Copyright © 2003-2019 Dynare Team
3  *
4  * This file is part of Dynare.
5  *
6  * Dynare is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Dynare is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <algorithm>
21 #include <sstream>
22 #include <iostream>
23 #include <cassert>
24 #pragma GCC diagnostic push
25 #pragma GCC diagnostic ignored "-Wold-style-cast"
26 #include <boost/algorithm/string/replace.hpp>
27 #pragma GCC diagnostic pop
28 #include <utility>
29 
30 #include "SymbolTable.hh"
31 
AuxVarInfo(int symb_id_arg,AuxVarType type_arg,int orig_symb_id_arg,int orig_lead_lag_arg,int equation_number_for_multiplier_arg,int information_set_arg,expr_t expr_node_arg,string unary_op_arg)32 AuxVarInfo::AuxVarInfo(int symb_id_arg, AuxVarType type_arg, int orig_symb_id_arg, int orig_lead_lag_arg,
33                        int equation_number_for_multiplier_arg, int information_set_arg,
34                        expr_t expr_node_arg, string unary_op_arg) :
35   symb_id{symb_id_arg},
36   type{type_arg},
37   orig_symb_id{orig_symb_id_arg},
38   orig_lead_lag{orig_lead_lag_arg},
39   equation_number_for_multiplier{equation_number_for_multiplier_arg},
40   information_set{information_set_arg},
41   expr_node{expr_node_arg},
42   unary_op{move(unary_op_arg)}
43 {
44 }
45 
46 int
addSymbol(const string & name,SymbolType type,const string & tex_name,const vector<pair<string,string>> & partition_value)47 SymbolTable::addSymbol(const string &name, SymbolType type, const string &tex_name, const vector<pair<string, string>> &partition_value) noexcept(false)
48 {
49   if (frozen)
50     throw FrozenException();
51 
52   if (exists(name))
53     {
54       if (type_table[getID(name)] == type)
55         throw AlreadyDeclaredException(name, true);
56       else
57         throw AlreadyDeclaredException(name, false);
58     }
59 
60   string final_tex_name = tex_name;
61   if (final_tex_name.empty())
62     {
63       final_tex_name = name;
64       size_t pos = 0;
65       while ((pos = final_tex_name.find('_', pos)) != string::npos)
66         {
67           final_tex_name.insert(pos, R"(\)");
68           pos += 2;
69         }
70     }
71 
72   string final_long_name = name;
73   bool non_long_name_partition_exists = false;
74   for (const auto &it : partition_value)
75     if (it.first == "long_name")
76       final_long_name = it.second;
77     else
78       non_long_name_partition_exists = true;
79 
80   int id = symbol_table.size();
81 
82   symbol_table[name] = id;
83   type_table.push_back(type);
84   name_table.push_back(name);
85   tex_name_table.push_back(final_tex_name);
86   long_name_table.push_back(final_long_name);
87   if (non_long_name_partition_exists)
88     {
89       map<string, string> pmv;
90       for (const auto &it : partition_value)
91         pmv[it.first] = it.second;
92       partition_value_map[id] = pmv;
93     }
94   return id;
95 }
96 
97 int
addSymbol(const string & name,SymbolType type)98 SymbolTable::addSymbol(const string &name, SymbolType type) noexcept(false)
99 {
100   return addSymbol(name, type, "", {});
101 }
102 
103 void
freeze()104 SymbolTable::freeze() noexcept(false)
105 {
106   if (frozen)
107     throw FrozenException();
108 
109   frozen = true;
110 
111   for (int i = 0; i < static_cast<int>(symbol_table.size()); i++)
112     {
113       int tsi;
114       switch (getType(i))
115         {
116         case SymbolType::endogenous:
117           tsi = endo_ids.size();
118           endo_ids.push_back(i);
119           break;
120         case SymbolType::exogenous:
121           tsi = exo_ids.size();
122           exo_ids.push_back(i);
123           break;
124         case SymbolType::exogenousDet:
125           tsi = exo_det_ids.size();
126           exo_det_ids.push_back(i);
127           break;
128         case SymbolType::parameter:
129           tsi = param_ids.size();
130           param_ids.push_back(i);
131           break;
132         default:
133           tsi = -1;
134           break;
135         }
136       type_specific_ids.push_back(tsi);
137     }
138 }
139 
140 void
unfreeze()141 SymbolTable::unfreeze()
142 {
143   frozen = false;
144   endo_ids.clear();
145   exo_ids.clear();
146   exo_det_ids.clear();
147   param_ids.clear();
148   type_specific_ids.clear();
149 }
150 
151 void
changeType(int id,SymbolType newtype)152 SymbolTable::changeType(int id, SymbolType newtype) noexcept(false)
153 {
154   if (frozen)
155     throw FrozenException();
156 
157   validateSymbID(id);
158 
159   type_table[id] = newtype;
160 }
161 
162 int
getID(SymbolType type,int tsid) const163 SymbolTable::getID(SymbolType type, int tsid) const noexcept(false)
164 {
165   if (!frozen)
166     throw NotYetFrozenException();
167 
168   switch (type)
169     {
170     case SymbolType::endogenous:
171       if (tsid < 0 || tsid >= static_cast<int>(endo_ids.size()))
172         throw UnknownTypeSpecificIDException(tsid, type);
173       else
174         return endo_ids[tsid];
175     case SymbolType::exogenous:
176       if (tsid < 0 || tsid >= static_cast<int>(exo_ids.size()))
177         throw UnknownTypeSpecificIDException(tsid, type);
178       else
179         return exo_ids[tsid];
180     case SymbolType::exogenousDet:
181       if (tsid < 0 || tsid >= static_cast<int>(exo_det_ids.size()))
182         throw UnknownTypeSpecificIDException(tsid, type);
183       else
184         return exo_det_ids[tsid];
185     case SymbolType::parameter:
186       if (tsid < 0 || tsid >= static_cast<int>(param_ids.size()))
187         throw UnknownTypeSpecificIDException(tsid, type);
188       else
189         return param_ids[tsid];
190     default:
191       throw UnknownTypeSpecificIDException(tsid, type);
192     }
193 }
194 
195 map<string, map<int, string>>
getPartitionsForType(SymbolType st) const196 SymbolTable::getPartitionsForType(SymbolType st) const noexcept(false)
197 {
198   map<string, map<int, string>> partitions;
199   for (const auto &it : partition_value_map)
200     if (getType(it.first) == st)
201       for (const auto &it1 : it.second)
202         {
203           if (partitions.find(it1.first) == partitions.end())
204             partitions[it1.first] = {};
205           partitions[it1.first][it.first] = it1.second;
206         }
207   return partitions;
208 }
209 
210 void
writeOutput(ostream & output) const211 SymbolTable::writeOutput(ostream &output) const noexcept(false)
212 {
213   if (!frozen)
214     throw NotYetFrozenException();
215 
216   if (exo_nbr() > 0)
217     {
218       output << "M_.exo_names = cell(" << exo_nbr() << ",1);" << endl;
219       output << "M_.exo_names_tex = cell(" << exo_nbr() << ",1);" << endl;
220       output << "M_.exo_names_long = cell(" << exo_nbr() << ",1);" << endl;
221       for (int id = 0; id < exo_nbr(); id++)
222         output << "M_.exo_names(" << id+1 << ") = {'" << getName(exo_ids[id]) << "'};" << endl
223                << "M_.exo_names_tex(" << id+1 << ") = {'" << getTeXName(exo_ids[id]) << "'};" << endl
224                << "M_.exo_names_long(" << id+1 << ") = {'" << getLongName(exo_ids[id]) << "'};" << endl;
225       map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::exogenous);
226       for (auto &partition : partitions)
227         if (partition.first != "long_name")
228           {
229             output << "M_.exo_partitions." << partition.first << " = { ";
230             for (int id = 0; id < exo_nbr(); id++)
231               {
232                 output << "'";
233                 if (auto it1 = partition.second.find(exo_ids[id]);
234                     it1 != partition.second.end())
235                   output << it1->second;
236                 output << "' ";
237               }
238             output << "};" << endl;
239             if (partition.first == "status")
240               output << "M_ = set_observed_exogenous_variables(M_);" << endl;
241             if (partition.first == "used")
242               output << "M_ = set_exogenous_variables_for_simulation(M_);" << endl;
243           }
244     }
245   else
246     {
247       output << "M_.exo_names = {};" << endl;
248       output << "M_.exo_names_tex = {};" << endl;
249       output << "M_.exo_names_long = {};" << endl;
250     }
251 
252   if (exo_det_nbr() > 0)
253     {
254       output << "M_.exo_det_names = cell(" << exo_det_nbr() << ",1);" << endl;
255       output << "M_.exo_det_names_tex = cell(" << exo_det_nbr() << ",1);" << endl;
256       output << "M_.exo_det_names_long = cell(" << exo_det_nbr() << ",1);" << endl;
257       for (int id = 0; id < exo_det_nbr(); id++)
258         output << "M_.exo_det_names(" << id+1 << ") = {'" << getName(exo_det_ids[id]) << "'};" << endl
259                << "M_.exo_det_names_tex(" << id+1 << ") = {'" << getTeXName(exo_det_ids[id]) << "'};" << endl
260                << "M_.exo_det_names_long(" << id+1 << ") = {'" << getLongName(exo_det_ids[id]) << "'};" << endl;
261       output << "M_.exo_det_partitions = struct();" << endl;
262       map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::exogenousDet);
263       for (auto &partition : partitions)
264         if (partition.first != "long_name")
265           {
266             output << "M_.exo_det_partitions." << partition.first << " = { ";
267             for (int id = 0; id < exo_det_nbr(); id++)
268               {
269                 output << "'";
270                 if (auto it1 = partition.second.find(exo_det_ids[id]);
271                     it1 != partition.second.end())
272                   output << it1->second;
273                 output << "' ";
274               }
275             output << "};" << endl;
276           }
277     }
278 
279   if (endo_nbr() > 0)
280     {
281       output << "M_.endo_names = cell(" << endo_nbr() << ",1);" << endl;
282       output << "M_.endo_names_tex = cell(" << endo_nbr() << ",1);" << endl;
283       output << "M_.endo_names_long = cell(" << endo_nbr() << ",1);" << endl;
284       for (int id = 0; id < endo_nbr(); id++)
285         output << "M_.endo_names(" << id+1 << ") = {'" << getName(endo_ids[id]) << "'};" << endl
286                << "M_.endo_names_tex(" << id+1 << ") = {'" << getTeXName(endo_ids[id]) << "'};" << endl
287                << "M_.endo_names_long(" << id+1 << ") = {'" << getLongName(endo_ids[id]) << "'};" << endl;
288       output << "M_.endo_partitions = struct();" << endl;
289       map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::endogenous);
290       for (auto &partition : partitions)
291         if (partition.first != "long_name")
292           {
293             output << "M_.endo_partitions." << partition.first << " = { ";
294             for (int id = 0; id < endo_nbr(); id++)
295               {
296                 output << "'";
297                 if (auto it1 = partition.second.find(endo_ids[id]);
298                     it1 != partition.second.end())
299                   output << it1->second;
300                 output << "' ";
301               }
302             output << "};" << endl;
303           }
304     }
305 
306   if (param_nbr() > 0)
307     {
308       output << "M_.param_names = cell(" << param_nbr() << ",1);" << endl;
309       output << "M_.param_names_tex = cell(" << param_nbr() << ",1);" << endl;
310       output << "M_.param_names_long = cell(" << param_nbr() << ",1);" << endl;
311       for (int id = 0; id < param_nbr(); id++)
312         {
313           output << "M_.param_names(" << id+1 << ") = {'" << getName(param_ids[id]) << "'};" << endl
314                  << "M_.param_names_tex(" << id+1 << ") = {'" << getTeXName(param_ids[id]) << "'};" << endl
315                  << "M_.param_names_long(" << id+1 << ") = {'" << getLongName(param_ids[id]) << "'};" << endl;
316           if (getName(param_ids[id]) == "dsge_prior_weight")
317             output << "options_.dsge_var = 1;" << endl;
318         }
319       output << "M_.param_partitions = struct();" << endl;
320       map<string, map<int, string>> partitions = getPartitionsForType(SymbolType::parameter);
321       for (auto &partition : partitions)
322         if (partition.first != "long_name")
323           {
324             output << "M_.param_partitions." << partition.first << " = { ";
325             for (int id = 0; id < param_nbr(); id++)
326               {
327                 output << "'";
328                 if (auto it1 = partition.second.find(param_ids[id]);
329                     it1 != partition.second.end())
330                   output << it1->second;
331                 output << "' ";
332               }
333             output << "};" << endl;
334           }
335     }
336   else
337     {
338       output << "M_.param_names = {};" << endl;
339       output << "M_.param_names_tex = {};" << endl;
340       output << "M_.param_names_long = {};" << endl;
341     }
342 
343   output << "M_.exo_det_nbr = " << exo_det_nbr() << ";" << endl
344          << "M_.exo_nbr = " << exo_nbr() << ";" << endl
345          << "M_.endo_nbr = " << endo_nbr() << ";" << endl
346          << "M_.param_nbr = " << param_nbr() << ";" << endl;
347 
348   // Write the auxiliary variable table
349   output << "M_.orig_endo_nbr = " << orig_endo_nbr() << ";" << endl;
350   if (aux_vars.size() == 0)
351     output << "M_.aux_vars = [];" << endl;
352   else
353     for (int i = 0; i < static_cast<int>(aux_vars.size()); i++)
354       {
355         output << "M_.aux_vars(" << i+1 << ").endo_index = " << getTypeSpecificID(aux_vars[i].get_symb_id())+1 << ";" << endl
356                << "M_.aux_vars(" << i+1 << ").type = " << aux_vars[i].get_type_id() << ";" << endl;
357         switch (aux_vars[i].get_type())
358           {
359           case AuxVarType::endoLead:
360           case AuxVarType::exoLead:
361             break;
362           case AuxVarType::endoLag:
363           case AuxVarType::exoLag:
364           case AuxVarType::varModel:
365             output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl
366                    << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl;
367             break;
368           case AuxVarType::unaryOp:
369             if (aux_vars[i].get_orig_symb_id() >= 0)
370               output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl
371                      << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl;
372             output << "M_.aux_vars(" << i+1 << ").unary_op = '" << aux_vars[i].get_unary_op() << "';" << endl;
373             break;
374           case AuxVarType::multiplier:
375             output << "M_.aux_vars(" << i+1 << ").eq_nbr = " << aux_vars[i].get_equation_number_for_multiplier() + 1 << ";" << endl;
376             break;
377           case AuxVarType::diffForward:
378             output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl;
379             break;
380           case AuxVarType::expectation:
381             break;
382           case AuxVarType::diff:
383           case AuxVarType::diffLag:
384           case AuxVarType::diffLead:
385             if (aux_vars[i].get_orig_symb_id() >= 0)
386               output << "M_.aux_vars(" << i+1 << ").orig_index = " << getTypeSpecificID(aux_vars[i].get_orig_symb_id())+1 << ";" << endl
387                      << "M_.aux_vars(" << i+1 << ").orig_lead_lag = " << aux_vars[i].get_orig_lead_lag() << ";" << endl;
388             break;
389           }
390 
391         if (expr_t orig_expr = aux_vars[i].get_expr_node();
392             orig_expr)
393           {
394             output << "M_.aux_vars(" << i+1 << ").orig_expr = '";
395             orig_expr->writeJsonOutput(output, {}, {});
396             output << "';" << endl;
397           }
398       }
399 
400   if (predeterminedNbr() > 0)
401     {
402       output << "M_.predetermined_variables = [ ";
403       for (int predetermined_variable : predetermined_variables)
404         output << getTypeSpecificID(predetermined_variable)+1 << " ";
405       output << "];" << endl;
406     }
407 
408   if (observedVariablesNbr() > 0)
409     {
410       int ic = 1;
411       output << "options_.varobs = cell(" << observedVariablesNbr() << ", 1);" << endl;
412       for (auto it = varobs.begin(); it != varobs.end(); ++it, ic++)
413         output << "options_.varobs(" << ic << ")  = {'" << getName(*it) << "'};" << endl;
414 
415       output << "options_.varobs_id = [ ";
416       for (int varob : varobs)
417         output << getTypeSpecificID(varob)+1 << " ";
418       output << " ];"  << endl;
419     }
420 
421   if (observedExogenousVariablesNbr() > 0)
422     {
423       int ic = 1;
424       output << "options_.varexobs = cell(1);" << endl;
425       for (auto it = varexobs.begin(); it != varexobs.end(); ++it, ic++)
426         output << "options_.varexobs(" << ic << ")  = {'" << getName(*it) << "'};" << endl;
427 
428       output << "options_.varexobs_id = [ ";
429       for (int varexob : varexobs)
430         output << getTypeSpecificID(varexob)+1 << " ";
431       output << " ];"  << endl;
432     }
433 }
434 
435 int
addLeadAuxiliaryVarInternal(bool endo,int index,expr_t expr_arg)436 SymbolTable::addLeadAuxiliaryVarInternal(bool endo, int index, expr_t expr_arg) noexcept(false)
437 {
438   ostringstream varname;
439   if (endo)
440     varname << "AUX_ENDO_LEAD_";
441   else
442     varname << "AUX_EXO_LEAD_";
443   varname << index;
444   int symb_id;
445   try
446     {
447       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
448     }
449   catch (AlreadyDeclaredException &e)
450     {
451       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
452       exit(EXIT_FAILURE);
453     }
454 
455   aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLead : AuxVarType::exoLead), 0, 0, 0, 0, expr_arg, "");
456 
457   return symb_id;
458 }
459 
460 int
addLagAuxiliaryVarInternal(bool endo,int orig_symb_id,int orig_lead_lag,expr_t expr_arg)461 SymbolTable::addLagAuxiliaryVarInternal(bool endo, int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
462 {
463   ostringstream varname;
464   if (endo)
465     varname << "AUX_ENDO_LAG_";
466   else
467     varname << "AUX_EXO_LAG_";
468   varname << orig_symb_id << "_" << -orig_lead_lag;
469 
470   int symb_id;
471   try
472     {
473       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
474     }
475   catch (AlreadyDeclaredException &e)
476     {
477       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
478       exit(EXIT_FAILURE);
479     }
480 
481   aux_vars.emplace_back(symb_id, (endo ? AuxVarType::endoLag : AuxVarType::exoLag), orig_symb_id, orig_lead_lag, 0, 0, expr_arg, "");
482 
483   return symb_id;
484 }
485 
486 int
addEndoLeadAuxiliaryVar(int index,expr_t expr_arg)487 SymbolTable::addEndoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
488 {
489   return addLeadAuxiliaryVarInternal(true, index, expr_arg);
490 }
491 
492 int
addEndoLagAuxiliaryVar(int orig_symb_id,int orig_lead_lag,expr_t expr_arg)493 SymbolTable::addEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
494 {
495   return addLagAuxiliaryVarInternal(true, orig_symb_id, orig_lead_lag, expr_arg);
496 }
497 
498 int
addExoLeadAuxiliaryVar(int index,expr_t expr_arg)499 SymbolTable::addExoLeadAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
500 {
501   return addLeadAuxiliaryVarInternal(false, index, expr_arg);
502 }
503 
504 int
addExoLagAuxiliaryVar(int orig_symb_id,int orig_lead_lag,expr_t expr_arg)505 SymbolTable::addExoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
506 {
507   return addLagAuxiliaryVarInternal(false, orig_symb_id, orig_lead_lag, expr_arg);
508 }
509 
510 int
addExpectationAuxiliaryVar(int information_set,int index,expr_t expr_arg)511 SymbolTable::addExpectationAuxiliaryVar(int information_set, int index, expr_t expr_arg) noexcept(false)
512 {
513   ostringstream varname;
514   int symb_id;
515 
516   varname << "AUX_EXPECT_" << (information_set < 0 ? "LAG" : "LEAD") << "_"
517           << abs(information_set) << "_" << index;
518 
519   try
520     {
521       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
522     }
523   catch (AlreadyDeclaredException &e)
524     {
525       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
526       exit(EXIT_FAILURE);
527     }
528 
529   aux_vars.emplace_back(symb_id, AuxVarType::expectation, 0, 0, 0, information_set, expr_arg, "");
530 
531   return symb_id;
532 }
533 
534 int
addDiffLagAuxiliaryVar(int index,expr_t expr_arg,int orig_symb_id,int orig_lag)535 SymbolTable::addDiffLagAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false)
536 {
537   ostringstream varname;
538   int symb_id;
539 
540   varname << "AUX_DIFF_LAG_" << index;
541 
542   try
543     {
544       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
545     }
546   catch (AlreadyDeclaredException &e)
547     {
548       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
549       exit(EXIT_FAILURE);
550     }
551 
552   aux_vars.emplace_back(symb_id, AuxVarType::diffLag, orig_symb_id, orig_lag, 0, 0, expr_arg, "");
553 
554   return symb_id;
555 }
556 
557 int
addDiffLeadAuxiliaryVar(int index,expr_t expr_arg,int orig_symb_id,int orig_lead)558 SymbolTable::addDiffLeadAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lead) noexcept(false)
559 {
560   ostringstream varname;
561   int symb_id;
562 
563   varname << "AUX_DIFF_LEAD_" << index;
564 
565   try
566     {
567       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
568     }
569   catch (AlreadyDeclaredException &e)
570     {
571       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
572       exit(EXIT_FAILURE);
573     }
574 
575   aux_vars.emplace_back(symb_id, AuxVarType::diffLead, orig_symb_id, orig_lead, 0, 0, expr_arg, "");
576 
577   return symb_id;
578 }
579 
580 int
addDiffAuxiliaryVar(int index,expr_t expr_arg,int orig_symb_id,int orig_lag)581 SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg, int orig_symb_id, int orig_lag) noexcept(false)
582 {
583   ostringstream varname;
584   int symb_id;
585 
586   varname << "AUX_DIFF_" << index;
587 
588   try
589     {
590       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
591     }
592   catch (AlreadyDeclaredException &e)
593     {
594       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
595       exit(EXIT_FAILURE);
596     }
597 
598   aux_vars.emplace_back(symb_id, AuxVarType::diff, orig_symb_id, orig_lag, 0, 0, expr_arg, "");
599 
600   return symb_id;
601 }
602 
603 int
addDiffAuxiliaryVar(int index,expr_t expr_arg)604 SymbolTable::addDiffAuxiliaryVar(int index, expr_t expr_arg) noexcept(false)
605 {
606   return addDiffAuxiliaryVar(index, expr_arg, -1, 0);
607 }
608 
609 int
addUnaryOpAuxiliaryVar(int index,expr_t expr_arg,string unary_op,int orig_symb_id,int orig_lag)610 SymbolTable::addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, int orig_symb_id, int orig_lag) noexcept(false)
611 {
612   ostringstream varname;
613   int symb_id;
614 
615   varname << "AUX_UOP_" << index;
616   try
617     {
618       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
619     }
620   catch (AlreadyDeclaredException &e)
621     {
622       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
623       exit(EXIT_FAILURE);
624     }
625 
626   aux_vars.emplace_back(symb_id, AuxVarType::unaryOp, orig_symb_id, orig_lag, 0, 0, expr_arg, unary_op);
627 
628   return symb_id;
629 }
630 
631 int
addVarModelEndoLagAuxiliaryVar(int orig_symb_id,int orig_lead_lag,expr_t expr_arg)632 SymbolTable::addVarModelEndoLagAuxiliaryVar(int orig_symb_id, int orig_lead_lag, expr_t expr_arg) noexcept(false)
633 {
634   int symb_id;
635   ostringstream varname;
636   varname << "AUX_VARMODEL_" << orig_symb_id << "_" << -orig_lead_lag;
637 
638   try
639     {
640       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
641     }
642   catch (AlreadyDeclaredException &e)
643     {
644       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
645       exit(EXIT_FAILURE);
646     }
647 
648   aux_vars.emplace_back(symb_id, AuxVarType::varModel, orig_symb_id, orig_lead_lag, 0, 0, expr_arg, "");
649 
650   return symb_id;
651 }
652 
653 int
addMultiplierAuxiliaryVar(int index)654 SymbolTable::addMultiplierAuxiliaryVar(int index) noexcept(false)
655 {
656   ostringstream varname;
657   int symb_id;
658   varname << "MULT_" << index+1;
659 
660   try
661     {
662       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
663     }
664   catch (AlreadyDeclaredException &e)
665     {
666       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
667       exit(EXIT_FAILURE);
668     }
669 
670   aux_vars.emplace_back(symb_id, AuxVarType::multiplier, 0, 0, index, 0, nullptr, "");
671   return symb_id;
672 }
673 
674 int
addDiffForwardAuxiliaryVar(int orig_symb_id,expr_t expr_arg)675 SymbolTable::addDiffForwardAuxiliaryVar(int orig_symb_id, expr_t expr_arg) noexcept(false)
676 {
677   ostringstream varname;
678   int symb_id;
679   varname << "AUX_DIFF_FWRD_" << orig_symb_id+1;
680 
681   try
682     {
683       symb_id = addSymbol(varname.str(), SymbolType::endogenous);
684     }
685   catch (AlreadyDeclaredException &e)
686     {
687       cerr << "ERROR: you should rename your variable called " << varname.str() << ", this name is internally used by Dynare" << endl;
688       exit(EXIT_FAILURE);
689     }
690 
691   aux_vars.emplace_back(symb_id, AuxVarType::diffForward, orig_symb_id, 0, 0, 0, expr_arg, "");
692   return symb_id;
693 }
694 
695 int
searchAuxiliaryVars(int orig_symb_id,int orig_lead_lag) const696 SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false)
697 {
698   for (const auto &aux_var : aux_vars)
699     if ((aux_var.get_type() == AuxVarType::endoLag || aux_var.get_type() == AuxVarType::exoLag)
700         && aux_var.get_orig_symb_id() == orig_symb_id && aux_var.get_orig_lead_lag() == orig_lead_lag)
701       return aux_var.get_symb_id();
702   throw SearchFailedException(orig_symb_id, orig_lead_lag);
703 }
704 
705 int
getOrigSymbIdForAuxVar(int aux_var_symb_id) const706 SymbolTable::getOrigSymbIdForAuxVar(int aux_var_symb_id) const noexcept(false)
707 {
708   for (const auto &aux_var : aux_vars)
709     if ((aux_var.get_type() == AuxVarType::endoLag
710          || aux_var.get_type() == AuxVarType::exoLag
711          || aux_var.get_type() == AuxVarType::diff
712          || aux_var.get_type() == AuxVarType::diffLag
713          || aux_var.get_type() == AuxVarType::diffLead)
714         && aux_var.get_symb_id() == aux_var_symb_id)
715       return aux_var.get_orig_symb_id();
716   throw UnknownSymbolIDException(aux_var_symb_id);
717 }
718 
719 int
getOrigLeadLagForDiffAuxVar(int diff_aux_var_symb_id) const720 SymbolTable::getOrigLeadLagForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false)
721 {
722   int lag = 0;
723   for (const auto &aux_var : aux_vars)
724     if ((aux_var.get_type() == AuxVarType::diffLag || aux_var.get_type() == AuxVarType::diffLead)
725         && aux_var.get_symb_id() == diff_aux_var_symb_id)
726       lag += 1 + getOrigLeadLagForDiffAuxVar(aux_var.get_orig_symb_id());
727   return lag;
728 }
729 
730 int
getOrigSymbIdForDiffAuxVar(int diff_aux_var_symb_id) const731 SymbolTable::getOrigSymbIdForDiffAuxVar(int diff_aux_var_symb_id) const noexcept(false)
732 {
733   int orig_symb_id = -1;
734   for (const auto &aux_var : aux_vars)
735     if (aux_var.get_symb_id() == diff_aux_var_symb_id)
736       if (aux_var.get_type() == AuxVarType::diff)
737         orig_symb_id = diff_aux_var_symb_id;
738       else if (aux_var.get_type() == AuxVarType::diffLag || aux_var.get_type() == AuxVarType::diffLead)
739         orig_symb_id = getOrigSymbIdForDiffAuxVar(aux_var.get_orig_symb_id());
740   return orig_symb_id;
741 }
742 
743 expr_t
getAuxiliaryVarsExprNode(int symb_id) const744 SymbolTable::getAuxiliaryVarsExprNode(int symb_id) const noexcept(false)
745 // throw exception if it is a Lagrange multiplier
746 {
747   for (const auto &aux_var : aux_vars)
748     if (aux_var.get_symb_id() == symb_id)
749       if (expr_t expr_node = aux_var.get_expr_node();
750           expr_node)
751         return expr_node;
752       else
753         throw SearchFailedException(symb_id);
754   throw SearchFailedException(symb_id);
755 }
756 
757 void
markPredetermined(int symb_id)758 SymbolTable::markPredetermined(int symb_id) noexcept(false)
759 {
760   validateSymbID(symb_id);
761 
762   if (frozen)
763     throw FrozenException();
764 
765   assert(getType(symb_id) == SymbolType::endogenous);
766 
767   predetermined_variables.insert(symb_id);
768 }
769 
770 bool
isPredetermined(int symb_id) const771 SymbolTable::isPredetermined(int symb_id) const noexcept(false)
772 {
773   validateSymbID(symb_id);
774   return (predetermined_variables.find(symb_id) != predetermined_variables.end());
775 }
776 
777 int
predeterminedNbr() const778 SymbolTable::predeterminedNbr() const
779 {
780   return (predetermined_variables.size());
781 }
782 
783 void
addObservedVariable(int symb_id)784 SymbolTable::addObservedVariable(int symb_id) noexcept(false)
785 {
786   validateSymbID(symb_id);
787   assert(getType(symb_id) == SymbolType::endogenous);
788   varobs.push_back(symb_id);
789 }
790 
791 int
observedVariablesNbr() const792 SymbolTable::observedVariablesNbr() const
793 {
794   return static_cast<int>(varobs.size());
795 }
796 
797 bool
isObservedVariable(int symb_id) const798 SymbolTable::isObservedVariable(int symb_id) const
799 {
800   return find(varobs.begin(), varobs.end(), symb_id) != varobs.end();
801 }
802 
803 int
getObservedVariableIndex(int symb_id) const804 SymbolTable::getObservedVariableIndex(int symb_id) const
805 {
806   auto it = find(varobs.begin(), varobs.end(), symb_id);
807   assert(it != varobs.end());
808   return static_cast<int>(it - varobs.begin());
809 }
810 
811 void
addObservedExogenousVariable(int symb_id)812 SymbolTable::addObservedExogenousVariable(int symb_id) noexcept(false)
813 {
814   validateSymbID(symb_id);
815   assert(getType(symb_id) != SymbolType::endogenous);
816   varexobs.push_back(symb_id);
817 }
818 
819 int
observedExogenousVariablesNbr() const820 SymbolTable::observedExogenousVariablesNbr() const
821 {
822   return static_cast<int>(varexobs.size());
823 }
824 
825 bool
isObservedExogenousVariable(int symb_id) const826 SymbolTable::isObservedExogenousVariable(int symb_id) const
827 {
828   return find(varexobs.begin(), varexobs.end(), symb_id) != varexobs.end();
829 }
830 
831 int
getObservedExogenousVariableIndex(int symb_id) const832 SymbolTable::getObservedExogenousVariableIndex(int symb_id) const
833 {
834   auto it = find(varexobs.begin(), varexobs.end(), symb_id);
835   assert(it != varexobs.end());
836   return static_cast<int>(it - varexobs.begin());
837 }
838 
839 vector <int>
getTrendVarIds() const840 SymbolTable::getTrendVarIds() const
841 {
842   vector <int> trendVars;
843   for (const auto &it : symbol_table)
844     if (getType(it.second) == SymbolType::trend || getType(it.second) == SymbolType::logTrend)
845       trendVars.push_back(it.second);
846   return trendVars;
847 }
848 
849 set<int>
getExogenous() const850 SymbolTable::getExogenous() const
851 {
852   set <int> exogs;
853   for (const auto &it : symbol_table)
854     if (getType(it.second) == SymbolType::exogenous)
855       exogs.insert(it.second);
856   return exogs;
857 }
858 
859 set<int>
getObservedExogenous() const860 SymbolTable::getObservedExogenous() const
861 {
862   set <int> oexogs;
863   for (const auto &it : symbol_table)
864     if (getType(it.second) == SymbolType::exogenous)
865       if (isObservedExogenousVariable(it.second))
866         oexogs.insert(it.second);
867   return oexogs;
868 }
869 
870 set<int>
getEndogenous() const871 SymbolTable::getEndogenous() const
872 {
873   set <int> endogs;
874   for (const auto &it : symbol_table)
875     if (getType(it.second) == SymbolType::endogenous)
876       endogs.insert(it.second);
877   return endogs;
878 }
879 
880 bool
isAuxiliaryVariable(int symb_id) const881 SymbolTable::isAuxiliaryVariable(int symb_id) const
882 {
883   for (const auto &aux_var : aux_vars)
884     if (aux_var.get_symb_id() == symb_id)
885       return true;
886   return false;
887 }
888 
889 bool
isAuxiliaryVariableButNotMultiplier(int symb_id) const890 SymbolTable::isAuxiliaryVariableButNotMultiplier(int symb_id) const
891 {
892   for (const auto &aux_var : aux_vars)
893     if (aux_var.get_symb_id() == symb_id && aux_var.get_type() != AuxVarType::multiplier)
894       return true;
895   return false;
896 }
897 
898 bool
isDiffAuxiliaryVariable(int symb_id) const899 SymbolTable::isDiffAuxiliaryVariable(int symb_id) const
900 {
901   for (const auto &aux_var : aux_vars)
902     if (aux_var.get_symb_id() == symb_id
903         && (aux_var.get_type() == AuxVarType::diff
904             || aux_var.get_type() == AuxVarType::diffLag
905             || aux_var.get_type() == AuxVarType::diffLead))
906       return true;
907   return false;
908 }
909 
910 set<int>
getOrigEndogenous() const911 SymbolTable::getOrigEndogenous() const
912 {
913   set <int> origendogs;
914   for (const auto &it : symbol_table)
915     if (getType(it.second) == SymbolType::endogenous && !isAuxiliaryVariable(it.second))
916       origendogs.insert(it.second);
917   return origendogs;
918 }
919 
920 void
writeJuliaOutput(ostream & output) const921 SymbolTable::writeJuliaOutput(ostream &output) const noexcept(false)
922 {
923   if (!frozen)
924     throw NotYetFrozenException();
925 
926   output << "# Endogenous Variables" << endl
927          << "model_.endo = [" << endl;
928   if (endo_nbr() > 0)
929     for (int id = 0; id < endo_nbr(); id++)
930       output << R"(              DynareModel.Endo(")"
931              << getName(endo_ids[id]) << R"(", raw")"
932              << getTeXName(endo_ids[id]) << R"(", ")"
933              << getLongName(endo_ids[id]) << R"("))" << endl;
934   output << "             ]" << endl;
935   output << "model_.endo_nbr = " << endo_nbr() << ";" << endl;
936 
937   output << "# Exogenous Variables" << endl
938          << "model_.exo = [" << endl;
939   if (exo_nbr() > 0)
940     for (int id = 0; id < exo_nbr(); id++)
941       output << R"(             DynareModel.Exo(")"
942              << getName(exo_ids[id]) << R"(", raw")"
943              << getTeXName(exo_ids[id]) << R"(", ")"
944              << getLongName(exo_ids[id]) << R"("))" << endl;
945   output << "            ]" << endl;
946   output << "model_.exo_nbr = " << exo_nbr() << ";" << endl;
947 
948   if (exo_det_nbr() > 0)
949     {
950       output << "# Exogenous Deterministic Variables" << endl
951              << "model_.exo_det = [" << endl;
952       if (exo_det_nbr() > 0)
953         for (int id = 0; id < exo_det_nbr(); id++)
954           output << R"(                 DynareModel.ExoDet(")"
955                  << getName(exo_det_ids[id]) << R"(", raw")"
956                  << getTeXName(exo_det_ids[id]) << R"(", ")"
957                  << getLongName(exo_det_ids[id]) << R"("))" << endl;
958       output << "                ]" << endl;
959       output << "model_.exo_det_nbr = " << exo_det_nbr() << ";" << endl;
960     }
961 
962   output << "# Parameters" << endl
963          << "model_.param = [" << endl;
964   if (param_nbr() > 0)
965     for (int id = 0; id < param_nbr(); id++)
966       output << R"(               DynareModel.Param(")"
967              << getName(param_ids[id]) << R"(", raw")"
968              << getTeXName(param_ids[id]) << R"(", ")"
969              << getLongName(param_ids[id]) << R"("))" << endl;
970   output << "              ]" << endl;
971   output << "model_.param_nbr = " << param_nbr() << ";" << endl;
972 
973   output << "model_.orig_endo_nbr = " << orig_endo_nbr() << endl;
974 
975   if (aux_vars.size() > 0)
976     {
977       output << "# Auxiliary Variables" << endl
978              << "model_.aux_vars = [" << endl;
979       for (const auto &aux_var : aux_vars)
980         {
981           output << "                   DynareModel.AuxVars("
982                  << getTypeSpecificID(aux_var.get_symb_id()) + 1 << ", "
983                  << aux_var.get_type_id() << ", ";
984           switch (aux_var.get_type())
985             {
986             case AuxVarType::endoLead:
987             case AuxVarType::exoLead:
988             case AuxVarType::endoLag:
989             case AuxVarType::exoLag:
990             case AuxVarType::varModel:
991               output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", "
992                      << aux_var.get_orig_lead_lag() << ", typemin(Int), string(), string()";
993               break;
994             case AuxVarType::unaryOp:
995               if (aux_var.get_orig_symb_id() >= 0)
996                 output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", " << aux_var.get_orig_lead_lag();
997               else
998                 output << "typemin(Int), typemin(Int)";
999               output << ", typemin(Int), string(), "
1000                      << R"(")" << aux_var.get_unary_op() << R"(")" << endl;
1001               break;
1002             case AuxVarType::diff:
1003             case AuxVarType::diffLag:
1004             case AuxVarType::diffLead:
1005               if (aux_var.get_orig_symb_id() >= 0)
1006                 output << getTypeSpecificID(aux_var.get_orig_symb_id()) + 1 << ", "
1007                        << aux_var.get_orig_lead_lag() << ", typemin(Int), string(), string()";
1008               break;
1009             case AuxVarType::multiplier:
1010               output << "typemin(Int), typemin(Int), " << aux_var.get_equation_number_for_multiplier() + 1
1011                      << ", string(), string()";
1012               break;
1013             case AuxVarType::diffForward:
1014               output << getTypeSpecificID(aux_var.get_orig_symb_id())+1 << ", typemin(Int), typemin(Int), string(), string()";
1015               break;
1016             case AuxVarType::expectation:
1017               output << R"(typemin(Int), typemin(Int), typemin(Int), "\mathbb{E}_{t)"
1018                      << (aux_var.get_information_set() < 0 ? "" : "+")
1019                      << aux_var.get_information_set() << "}(";
1020               aux_var.get_expr_node()->writeOutput(output, ExprNodeOutputType::latexDynamicModel);
1021               output << R"lit()")lit";
1022               break;
1023             default:
1024               output << " typemin(Int), typemin(Int), typemin(Int), string(), string()";
1025             }
1026           output << ")" << endl;
1027         }
1028       output << "]" << endl;
1029     }
1030 
1031   if (predeterminedNbr() > 0)
1032     {
1033       output << "# Predetermined Variables" << endl
1034              << "model_.pred_vars = [ " << endl;
1035       for (int predetermined_variable : predetermined_variables)
1036         output << "                   DynareModel.PredVars("
1037                << getTypeSpecificID(predetermined_variable)+1 << ")" << endl;
1038       output << "                  ]" << endl;
1039     }
1040 
1041   if (observedVariablesNbr() > 0)
1042     {
1043       output << "# Observed Variables" << endl
1044              << "options_.obs_vars = [" << endl;
1045       for (int varob : varobs)
1046         output << "                    DynareModel.ObsVars("
1047                << getTypeSpecificID(varob)+1 << ")" << endl;
1048       output << "                   ]" << endl;
1049     }
1050 }
1051 
1052 void
writeJsonOutput(ostream & output) const1053 SymbolTable::writeJsonOutput(ostream &output) const
1054 {
1055   output << R"("endogenous": )";
1056   writeJsonVarVector(output, endo_ids);
1057 
1058   output << R"(, "exogenous":)";
1059   writeJsonVarVector(output, exo_ids);
1060 
1061   output << R"(, "exogenous_deterministic": )";
1062   writeJsonVarVector(output, exo_det_ids);
1063 
1064   output << R"(, "parameters": )";
1065   writeJsonVarVector(output, param_ids);
1066 }
1067 
1068 void
writeJsonVarVector(ostream & output,const vector<int> & varvec) const1069 SymbolTable::writeJsonVarVector(ostream &output, const vector<int> &varvec) const
1070 {
1071   output << "[";
1072   for (size_t i = 0; i < varvec.size(); i++)
1073     {
1074       if (i != 0)
1075         output << ", ";
1076       output << "{"
1077              << R"("name":")" << getName(varvec[i]) << R"(", )"
1078              << R"("texName":")" << boost::replace_all_copy(getTeXName(varvec[i]), R"(\)", R"(\\)") << R"(", )"
1079              << R"("longName":")" << boost::replace_all_copy(getLongName(varvec[i]), R"(\)", R"(\\)") << R"("})"
1080              << endl;
1081     }
1082   output << "]" << endl;
1083 }
1084 
1085 int
getUltimateOrigSymbID(int symb_id) const1086 SymbolTable::getUltimateOrigSymbID(int symb_id) const
1087 {
1088   while (isAuxiliaryVariable(symb_id))
1089     try
1090       {
1091         symb_id = getOrigSymbIdForAuxVar(symb_id);
1092       }
1093     catch (UnknownSymbolIDException &)
1094       {
1095         break;
1096       }
1097   return symb_id;
1098 }
1099 
1100 int
getEquationNumberForMultiplier(int symb_id) const1101 SymbolTable::getEquationNumberForMultiplier(int symb_id) const
1102 {
1103   for (const auto &aux_var : aux_vars)
1104     if (aux_var.get_symb_id() == symb_id && aux_var.get_type() == AuxVarType::multiplier)
1105       return aux_var.get_equation_number_for_multiplier();
1106   return -1;
1107 }
1108