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 <iostream>
21 #include <cmath>
22 #include <cstdlib>
23 #include <cassert>
24 #include <algorithm>
25 #include <numeric>
26 #include <regex>
27
28 #include "DynamicModel.hh"
29
30 void
copyHelper(const DynamicModel & m)31 DynamicModel::copyHelper(const DynamicModel &m)
32 {
33 auto f = [this](const ExprNode *e) { return e->clone(*this); };
34
35 for (const auto &it : m.static_only_equations)
36 static_only_equations.push_back(dynamic_cast<BinaryOpNode *>(f(it)));
37
38 auto convert_vector_tt = [f](vector<temporary_terms_t> vtt)
39 {
40 vector<temporary_terms_t> vtt2;
41 for (const auto &tt : vtt)
42 {
43 temporary_terms_t tt2;
44 for (const auto &it : tt)
45 tt2.insert(f(it));
46 vtt2.push_back(tt2);
47 }
48 return vtt2;
49 };
50
51 for (const auto &it : m.v_temporary_terms)
52 v_temporary_terms.push_back(convert_vector_tt(it));
53
54 for (const auto &it : m.first_chain_rule_derivatives)
55 first_chain_rule_derivatives[it.first] = f(it.second);
56
57 for (const auto &it : m.equation_type_and_normalized_equation)
58 equation_type_and_normalized_equation.emplace_back(it.first, f(it.second));
59
60 for (const auto &it : m.blocks_derivatives)
61 {
62 block_derivatives_equation_variable_laglead_nodeid_t v;
63 for (const auto &it2 : it)
64 v.emplace_back(get<0>(it2), get<1>(it2), get<2>(it2), f(get<3>(it2)));
65 blocks_derivatives.push_back(v);
66 }
67
68 for (const auto &it : m.dynamic_jacobian)
69 dynamic_jacobian[it.first] = f(it.second);
70
71 auto convert_derivative_t = [f](derivative_t dt)
72 {
73 derivative_t dt2;
74 for (const auto &it : dt)
75 dt2[it.first] = f(it.second);
76 return dt2;
77 };
78 for (const auto &it : m.derivative_endo)
79 derivative_endo.push_back(convert_derivative_t(it));
80 for (const auto &it : m.derivative_other_endo)
81 derivative_other_endo.push_back(convert_derivative_t(it));
82 for (const auto &it : m.derivative_exo)
83 derivative_exo.push_back(convert_derivative_t(it));
84 for (const auto &it : m.derivative_exo_det)
85 derivative_exo_det.push_back(convert_derivative_t(it));
86 }
87
DynamicModel(SymbolTable & symbol_table_arg,NumericalConstants & num_constants_arg,ExternalFunctionsTable & external_functions_table_arg,TrendComponentModelTable & trend_component_model_table_arg,VarModelTable & var_model_table_arg)88 DynamicModel::DynamicModel(SymbolTable &symbol_table_arg,
89 NumericalConstants &num_constants_arg,
90 ExternalFunctionsTable &external_functions_table_arg,
91 TrendComponentModelTable &trend_component_model_table_arg,
92 VarModelTable &var_model_table_arg) :
93 ModelTree{symbol_table_arg, num_constants_arg, external_functions_table_arg, true},
94 trend_component_model_table{trend_component_model_table_arg},
95 var_model_table{var_model_table_arg}
96 {
97 }
98
DynamicModel(const DynamicModel & m)99 DynamicModel::DynamicModel(const DynamicModel &m) :
100 ModelTree{m},
101 trend_component_model_table{m.trend_component_model_table},
102 var_model_table{m.var_model_table},
103 balanced_growth_test_tol{m.balanced_growth_test_tol},
104 static_only_equations_lineno{m.static_only_equations_lineno},
105 static_only_equations_equation_tags{m.static_only_equations_equation_tags},
106 static_only_equation_tags_xref{m.static_only_equation_tags_xref},
107 deriv_id_table{m.deriv_id_table},
108 inv_deriv_id_table{m.inv_deriv_id_table},
109 dyn_jacobian_cols_table{m.dyn_jacobian_cols_table},
110 max_lag{m.max_lag},
111 max_lead{m.max_lead},
112 max_endo_lag{m.max_endo_lag},
113 max_endo_lead{m.max_endo_lead},
114 max_exo_lag{m.max_exo_lag},
115 max_exo_lead{m.max_exo_lead},
116 max_exo_det_lag{m.max_exo_det_lag},
117 max_exo_det_lead{m.max_exo_det_lead},
118 max_lag_orig{m.max_lag_orig},
119 max_lead_orig{m.max_lead_orig},
120 max_lag_with_diffs_expanded_orig{m.max_lag_with_diffs_expanded_orig},
121 max_endo_lag_orig{m.max_endo_lag_orig},
122 max_endo_lead_orig{m.max_endo_lead_orig},
123 max_exo_lag_orig{m.max_exo_lag_orig},
124 max_exo_lead_orig{m.max_exo_lead_orig},
125 max_exo_det_lag_orig{m.max_exo_det_lag_orig},
126 max_exo_det_lead_orig{m.max_exo_det_lead_orig},
127 xrefs{m.xrefs},
128 xref_param{m.xref_param},
129 xref_endo{m.xref_endo},
130 xref_exo{m.xref_exo},
131 xref_exo_det{m.xref_exo_det},
132 nonzero_hessian_eqs{m.nonzero_hessian_eqs},
133 dynJacobianColsNbr{m.dynJacobianColsNbr},
134 v_temporary_terms_inuse{m.v_temporary_terms_inuse},
135 variableMapping{m.variableMapping},
136 map_idx{m.map_idx},
137 global_temporary_terms{m.global_temporary_terms},
138 block_type_firstequation_size_mfs{m.block_type_firstequation_size_mfs},
139 blocks_linear{m.blocks_linear},
140 other_endo_block{m.other_endo_block},
141 exo_block{m.exo_block},
142 exo_det_block{m.exo_det_block},
143 block_var_exo{m.block_var_exo},
144 block_exo_index{m.block_exo_index},
145 block_det_exo_index{m.block_det_exo_index},
146 block_other_endo_index{m.block_other_endo_index},
147 block_col_type{m.block_col_type},
148 variable_block_lead_lag{m.variable_block_lead_lag},
149 equation_block{m.equation_block},
150 var_expectation_functions_to_write{m.var_expectation_functions_to_write},
151 endo_max_leadlag_block{m.endo_max_leadlag_block},
152 other_endo_max_leadlag_block{m.other_endo_max_leadlag_block},
153 exo_max_leadlag_block{m.exo_max_leadlag_block},
154 exo_det_max_leadlag_block{m.exo_det_max_leadlag_block},
155 max_leadlag_block{m.max_leadlag_block}
156 {
157 copyHelper(m);
158 }
159
160 DynamicModel &
operator =(const DynamicModel & m)161 DynamicModel::operator=(const DynamicModel &m)
162 {
163 ModelTree::operator=(m);
164
165 assert(&trend_component_model_table == &m.trend_component_model_table);
166 assert(&var_model_table == &m.var_model_table);
167 balanced_growth_test_tol = m.balanced_growth_test_tol;
168
169 static_only_equations_lineno = m.static_only_equations_lineno;
170 static_only_equations_equation_tags = m.static_only_equations_equation_tags;
171 static_only_equation_tags_xref = m.static_only_equation_tags_xref;
172 deriv_id_table = m.deriv_id_table;
173 inv_deriv_id_table = m.inv_deriv_id_table;
174 dyn_jacobian_cols_table = m.dyn_jacobian_cols_table;
175 max_lag = m.max_lag;
176 max_lead = m.max_lead;
177 max_endo_lag = m.max_endo_lag;
178 max_endo_lead = m.max_endo_lead;
179 max_exo_lag = m.max_exo_lag;
180 max_exo_lead = m.max_exo_lead;
181 max_exo_det_lag = m.max_exo_det_lag;
182 max_exo_det_lead = m.max_exo_det_lead;
183 max_lag_orig = m.max_lag_orig;
184 max_lead_orig = m.max_lead_orig;
185 max_lag_with_diffs_expanded_orig = m.max_lag_with_diffs_expanded_orig;
186 max_endo_lag_orig = m.max_endo_lag_orig;
187 max_endo_lead_orig = m.max_endo_lead_orig;
188 max_exo_lag_orig = m.max_exo_lag_orig;
189 max_exo_lead_orig = m.max_exo_lead_orig;
190 max_exo_det_lag_orig = m.max_exo_det_lag_orig;
191 max_exo_det_lead_orig = m.max_exo_det_lead_orig;
192 xrefs = m.xrefs;
193 xref_param = m.xref_param;
194 xref_endo = m.xref_endo;
195 xref_exo = m.xref_exo;
196 xref_exo_det = m.xref_exo_det;
197 nonzero_hessian_eqs = m.nonzero_hessian_eqs;
198
199 dynJacobianColsNbr = m.dynJacobianColsNbr;
200
201 v_temporary_terms.clear();
202
203 v_temporary_terms_inuse = m.v_temporary_terms_inuse;
204
205 variableMapping = m.variableMapping;
206
207 first_chain_rule_derivatives.clear();
208
209 map_idx = m.map_idx;
210 global_temporary_terms = m.global_temporary_terms;
211
212 equation_type_and_normalized_equation.clear();
213
214 block_type_firstequation_size_mfs = m.block_type_firstequation_size_mfs;
215
216 blocks_derivatives.clear();
217 dynamic_jacobian.clear();
218
219 blocks_linear = m.blocks_linear;
220
221 derivative_endo.clear();
222 derivative_other_endo.clear();
223 derivative_exo.clear();
224 derivative_exo_det.clear();
225
226 other_endo_block = m.other_endo_block;
227 exo_block = m.exo_block;
228 exo_det_block = m.exo_det_block;
229 block_var_exo = m.block_var_exo;
230 block_exo_index = m.block_exo_index;
231 block_det_exo_index = m.block_det_exo_index;
232 block_other_endo_index = m.block_other_endo_index;
233 block_col_type = m.block_col_type;
234 variable_block_lead_lag = m.variable_block_lead_lag;
235 equation_block = m.equation_block;
236 var_expectation_functions_to_write = m.var_expectation_functions_to_write;
237
238 endo_max_leadlag_block = m.endo_max_leadlag_block;
239 other_endo_max_leadlag_block = m.other_endo_max_leadlag_block;
240 exo_max_leadlag_block = m.exo_max_leadlag_block;
241 exo_det_max_leadlag_block = m.exo_det_max_leadlag_block;
242 max_leadlag_block = m.max_leadlag_block;
243
244 copyHelper(m);
245
246 return *this;
247 }
248
249 void
compileDerivative(ofstream & code_file,unsigned int & instruction_number,int eq,int symb_id,int lag,const map_idx_t & map_idx) const250 DynamicModel::compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const
251 {
252 if (auto it = derivatives[1].find({ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, symb_id), lag) });
253 it != derivatives[1].end())
254 it->second->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
255 else
256 {
257 FLDZ_ fldz;
258 fldz.write(code_file, instruction_number);
259 }
260 }
261
262 void
compileChainRuleDerivative(ofstream & code_file,unsigned int & instruction_number,int eqr,int varr,int lag,const map_idx_t & map_idx) const263 DynamicModel::compileChainRuleDerivative(ofstream &code_file, unsigned int &instruction_number, int eqr, int varr, int lag, const map_idx_t &map_idx) const
264 {
265 if (auto it = first_chain_rule_derivatives.find({ eqr, varr, lag }); it != first_chain_rule_derivatives.end())
266 it->second->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
267 else
268 {
269 FLDZ_ fldz;
270 fldz.write(code_file, instruction_number);
271 }
272 }
273
274 void
computeTemporaryTermsOrdered()275 DynamicModel::computeTemporaryTermsOrdered()
276 {
277 map<expr_t, pair<int, int>> first_occurence;
278 map<expr_t, int> reference_count;
279 BinaryOpNode *eq_node;
280 first_chain_rule_derivatives_t::const_iterator it_chr;
281 ostringstream tmp_s;
282 v_temporary_terms.clear();
283 map_idx.clear();
284
285 unsigned int nb_blocks = getNbBlocks();
286 v_temporary_terms = vector<vector<temporary_terms_t>>(nb_blocks);
287 v_temporary_terms_inuse = vector<temporary_terms_inuse_t>(nb_blocks);
288 temporary_terms.clear();
289
290 if (!global_temporary_terms)
291 {
292 for (unsigned int block = 0; block < nb_blocks; block++)
293 {
294 reference_count.clear();
295 temporary_terms.clear();
296 unsigned int block_size = getBlockSize(block);
297 unsigned int block_nb_mfs = getBlockMfs(block);
298 unsigned int block_nb_recursives = block_size - block_nb_mfs;
299 v_temporary_terms[block] = vector<temporary_terms_t>(block_size);
300 for (unsigned int i = 0; i < block_size; i++)
301 {
302 if (i < block_nb_recursives && isBlockEquationRenormalized(block, i))
303 getBlockEquationRenormalizedExpr(block, i)->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, i);
304 else
305 {
306 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
307 eq_node->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, i);
308 }
309 }
310 for (const auto &it : blocks_derivatives[block])
311 {
312 expr_t id = get<3>(it);
313 id->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, block_size-1);
314 }
315 for (const auto &it : derivative_other_endo[block])
316 it.second->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, block_size-1);
317 v_temporary_terms_inuse[block] = {};
318 }
319 }
320 else
321 {
322 for (unsigned int block = 0; block < nb_blocks; block++)
323 {
324 // Compute the temporary terms reordered
325 unsigned int block_size = getBlockSize(block);
326 unsigned int block_nb_mfs = getBlockMfs(block);
327 unsigned int block_nb_recursives = block_size - block_nb_mfs;
328 v_temporary_terms[block] = vector<temporary_terms_t>(block_size);
329 for (unsigned int i = 0; i < block_size; i++)
330 {
331 if (i < block_nb_recursives && isBlockEquationRenormalized(block, i))
332 getBlockEquationRenormalizedExpr(block, i)->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, i);
333 else
334 {
335 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
336 eq_node->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, i);
337 }
338 }
339 for (const auto &it : blocks_derivatives[block])
340 {
341 expr_t id = get<3>(it);
342 id->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, block_size-1);
343 }
344 for (const auto &it : derivative_other_endo[block])
345 it.second->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, block, v_temporary_terms, block_size-1);
346 }
347 for (unsigned int block = 0; block < nb_blocks; block++)
348 {
349 // Collect the temporary terms reordered
350 unsigned int block_size = getBlockSize(block);
351 unsigned int block_nb_mfs = getBlockMfs(block);
352 unsigned int block_nb_recursives = block_size - block_nb_mfs;
353 set<int> temporary_terms_in_use;
354 for (unsigned int i = 0; i < block_size; i++)
355 {
356 if (i < block_nb_recursives && isBlockEquationRenormalized(block, i))
357 getBlockEquationRenormalizedExpr(block, i)->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
358 else
359 {
360 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
361 eq_node->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
362 }
363 }
364 for (const auto &it : blocks_derivatives[block])
365 {
366 expr_t id = get<3>(it);
367 id->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
368 }
369 for (const auto &it : derivative_other_endo[block])
370 it.second->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
371 for (const auto &it : derivative_exo[block])
372 it.second->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
373 for (const auto &it : derivative_exo_det[block])
374 it.second->collectTemporary_terms(temporary_terms, temporary_terms_in_use, block);
375 v_temporary_terms_inuse[block] = temporary_terms_in_use;
376 }
377 computeTemporaryTermsMapping();
378 }
379 }
380
381 void
computeTemporaryTermsMapping()382 DynamicModel::computeTemporaryTermsMapping()
383 {
384 // Add a mapping form node ID to temporary terms order
385 int j = 0;
386 for (auto temporary_term : temporary_terms)
387 map_idx[temporary_term->idx] = j++;
388 }
389
390 void
writeModelEquationsOrdered_M(const string & basename) const391 DynamicModel::writeModelEquationsOrdered_M(const string &basename) const
392 {
393 string tmp_s, sps;
394 ostringstream tmp_output, tmp1_output, global_output;
395 expr_t lhs = nullptr, rhs = nullptr;
396 BinaryOpNode *eq_node;
397 ostringstream Ufoss;
398 vector<string> Uf(symbol_table.endo_nbr(), "");
399 map<expr_t, int> reference_count;
400 temporary_terms_t local_temporary_terms;
401 ofstream output;
402 int nze, nze_exo, nze_exo_det, nze_other_endo;
403 vector<int> feedback_variables;
404 ExprNodeOutputType local_output_type;
405
406 local_output_type = ExprNodeOutputType::matlabDynamicModelSparse;
407 if (global_temporary_terms)
408 local_temporary_terms = temporary_terms;
409
410 //----------------------------------------------------------------------
411 //For each block
412 for (unsigned int block = 0; block < getNbBlocks(); block++)
413 {
414
415 //recursive_variables.clear();
416 feedback_variables.clear();
417 //For a block composed of a single equation determines wether we have to evaluate or to solve the equation
418 nze = blocks_derivatives[block].size();
419 nze_other_endo = derivative_other_endo[block].size();
420 nze_exo = derivative_exo[block].size();
421 nze_exo_det = derivative_exo_det[block].size();
422 BlockSimulationType simulation_type = getBlockSimulationType(block);
423 unsigned int block_size = getBlockSize(block);
424 unsigned int block_mfs = getBlockMfs(block);
425 unsigned int block_recursive = block_size - block_mfs;
426 deriv_node_temp_terms_t tef_terms;
427 local_output_type = ExprNodeOutputType::matlabDynamicModelSparse;
428 if (global_temporary_terms)
429 local_temporary_terms = temporary_terms;
430
431 int prev_lag;
432 unsigned int prev_var, count_col, count_col_endo, count_col_exo, count_col_exo_det, count_col_other_endo;
433 map<tuple<int, int, int>, expr_t> tmp_block_endo_derivative;
434 for (const auto &it : blocks_derivatives[block])
435 tmp_block_endo_derivative[{ get<2>(it), get<1>(it), get<0>(it) }] = get<3>(it);
436 prev_var = 999999999;
437 prev_lag = -9999999;
438 count_col_endo = 0;
439 for (const auto &it : tmp_block_endo_derivative)
440 {
441 int lag = get<0>(it.first);
442 unsigned int var = get<1>(it.first);
443 if (var != prev_var || lag != prev_lag)
444 {
445 prev_var = var;
446 prev_lag = lag;
447 count_col_endo++;
448 }
449 }
450 map<tuple<int, int, int>, expr_t> tmp_block_exo_derivative;
451 for (const auto &it : derivative_exo[block])
452 tmp_block_exo_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
453 prev_var = 999999999;
454 prev_lag = -9999999;
455 count_col_exo = 0;
456 for (const auto &it : tmp_block_exo_derivative)
457 {
458 int lag = get<0>(it.first);
459 unsigned int var = get<1>(it.first);
460 if (var != prev_var || lag != prev_lag)
461 {
462 prev_var = var;
463 prev_lag = lag;
464 count_col_exo++;
465 }
466 }
467 map<tuple<int, int, int>, expr_t> tmp_block_exo_det_derivative;
468 for (const auto &it : derivative_exo_det[block])
469 tmp_block_exo_det_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
470 prev_var = 999999999;
471 prev_lag = -9999999;
472 count_col_exo_det = 0;
473 for (const auto &it : tmp_block_exo_det_derivative)
474 {
475 int lag = get<0>(it.first);
476 unsigned int var = get<1>(it.first);
477 if (var != prev_var || lag != prev_lag)
478 {
479 prev_var = var;
480 prev_lag = lag;
481 count_col_exo_det++;
482 }
483 }
484 map<tuple<int, int, int>, expr_t> tmp_block_other_endo_derivative;
485 for (const auto &it : derivative_other_endo[block])
486 tmp_block_other_endo_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
487 prev_var = 999999999;
488 prev_lag = -9999999;
489 count_col_other_endo = 0;
490 for (const auto &it : tmp_block_other_endo_derivative)
491 {
492 int lag = get<0>(it.first);
493 unsigned int var = get<1>(it.first);
494 if (var != prev_var || lag != prev_lag)
495 {
496 prev_var = var;
497 prev_lag = lag;
498 count_col_other_endo++;
499 }
500 }
501
502 tmp1_output.str("");
503 tmp1_output << packageDir(basename + ".block") << "/dynamic_" << block+1 << ".m";
504 output.open(tmp1_output.str(), ios::out | ios::binary);
505 output << "%" << endl
506 << "% " << tmp1_output.str() << " : Computes dynamic model for Dynare" << endl
507 << "%" << endl
508 << "% Warning : this file is generated automatically by Dynare" << endl
509 << "% from model file (.mod)" << endl << endl
510 << "%/" << endl;
511 if (simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
512 {
513 output << "function [y, g1, g2, g3, varargout] = dynamic_" << block+1 << "(y, x, params, steady_state, jacobian_eval, y_kmin, periods)" << endl;
514 }
515 else if (simulation_type == SOLVE_FORWARD_COMPLETE || simulation_type == SOLVE_BACKWARD_COMPLETE)
516 output << "function [residual, y, g1, g2, g3, varargout] = dynamic_" << block+1 << "(y, x, params, steady_state, it_, jacobian_eval)" << endl;
517 else if (simulation_type == SOLVE_BACKWARD_SIMPLE || simulation_type == SOLVE_FORWARD_SIMPLE)
518 output << "function [residual, y, g1, g2, g3, varargout] = dynamic_" << block+1 << "(y, x, params, steady_state, it_, jacobian_eval)" << endl;
519 else
520 output << "function [residual, y, g1, g2, g3, b, varargout] = dynamic_" << block+1 << "(y, x, params, steady_state, periods, jacobian_eval, y_kmin, y_size, Periods)" << endl;
521 BlockType block_type;
522 if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
523 block_type = SIMULTAN;
524 else if (simulation_type == SOLVE_FORWARD_COMPLETE || simulation_type == SOLVE_BACKWARD_COMPLETE)
525 block_type = SIMULTANS;
526 else if ((simulation_type == SOLVE_FORWARD_SIMPLE || simulation_type == SOLVE_BACKWARD_SIMPLE
527 || simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
528 && getBlockFirstEquation(block) < prologue)
529 block_type = PROLOGUE;
530 else if ((simulation_type == SOLVE_FORWARD_SIMPLE || simulation_type == SOLVE_BACKWARD_SIMPLE
531 || simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
532 && getBlockFirstEquation(block) >= equations.size() - epilogue)
533 block_type = EPILOGUE;
534 else
535 block_type = SIMULTANS;
536 output << " % ////////////////////////////////////////////////////////////////////////" << endl
537 << " % //" << string(" Block ").substr(int (log10(block + 1))) << block + 1 << " " << BlockType0(block_type)
538 << " //" << endl
539 << " % // Simulation type "
540 << BlockSim(simulation_type) << " //" << endl
541 << " % ////////////////////////////////////////////////////////////////////////" << endl;
542 //The Temporary terms
543 if (simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
544 {
545 output << " if(jacobian_eval)" << endl
546 << " g1 = spalloc(" << block_mfs << ", " << count_col_endo << ", " << nze << ");" << endl
547 << " g1_x=spalloc(" << block_size << ", " << count_col_exo << ", " << nze_exo << ");" << endl
548 << " g1_xd=spalloc(" << block_size << ", " << count_col_exo_det << ", " << nze_exo_det << ");" << endl
549 << " g1_o=spalloc(" << block_size << ", " << count_col_other_endo << ", " << nze_other_endo << ");" << endl
550 << " end;" << endl;
551 }
552 else
553 {
554 output << " if(jacobian_eval)" << endl
555 << " g1 = spalloc(" << block_size << ", " << count_col_endo << ", " << nze << ");" << endl
556 << " g1_x=spalloc(" << block_size << ", " << count_col_exo << ", " << nze_exo << ");" << endl
557 << " g1_xd=spalloc(" << block_size << ", " << count_col_exo_det << ", " << nze_exo_det << ");" << endl
558 << " g1_o=spalloc(" << block_size << ", " << count_col_other_endo << ", " << nze_other_endo << ");" << endl
559 << " else" << endl;
560 if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
561 output << " g1 = spalloc(" << block_mfs << "*Periods, "
562 << block_mfs << "*(Periods+" << max_leadlag_block[block].first+max_leadlag_block[block].second+1 << ")"
563 << ", " << nze << "*Periods);" << endl;
564 else
565 output << " g1 = spalloc(" << block_mfs
566 << ", " << block_mfs << ", " << nze << ");" << endl;
567 output << " end;" << endl;
568 }
569
570 output << " g2=0;g3=0;" << endl;
571 if (v_temporary_terms_inuse[block].size())
572 {
573 tmp_output.str("");
574 for (int it : v_temporary_terms_inuse[block])
575 tmp_output << " T" << it;
576 output << " global" << tmp_output.str() << ";" << endl;
577 }
578 if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
579 {
580 temporary_terms_t tt2;
581 for (int i = 0; i < static_cast<int>(block_size); i++)
582 {
583 if (v_temporary_terms[block][i].size() && global_temporary_terms)
584 {
585 output << " " << "% //Temporary variables initialization" << endl
586 << " " << "T_zeros = zeros(y_kmin+periods, 1);" << endl;
587 for (auto it : v_temporary_terms[block][i])
588 {
589 output << " ";
590 // In the following, "Static" is used to avoid getting the "(it_)" subscripting
591 it->writeOutput(output, ExprNodeOutputType::matlabStaticModelSparse, local_temporary_terms, {});
592 output << " = T_zeros;" << endl;
593 }
594 }
595 }
596 }
597 if (simulation_type == SOLVE_BACKWARD_SIMPLE || simulation_type == SOLVE_FORWARD_SIMPLE || simulation_type == SOLVE_BACKWARD_COMPLETE || simulation_type == SOLVE_FORWARD_COMPLETE)
598 output << " residual=zeros(" << block_mfs << ",1);" << endl;
599 else if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
600 output << " residual=zeros(" << block_mfs << ",y_kmin+periods);" << endl;
601 if (simulation_type == EVALUATE_BACKWARD)
602 output << " for it_ = (y_kmin+periods):-1:y_kmin+1" << endl;
603 if (simulation_type == EVALUATE_FORWARD)
604 output << " for it_ = y_kmin+1:(y_kmin+periods)" << endl;
605
606 if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
607 {
608 output << " b = zeros(periods*y_size,1);" << endl
609 << " for it_ = y_kmin+1:(periods+y_kmin)" << endl
610 << " Per_y_=it_*y_size;" << endl
611 << " Per_J_=(it_-y_kmin-1)*y_size;" << endl
612 << " Per_K_=(it_-1)*y_size;" << endl;
613 sps = " ";
614 }
615 else
616 if (simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
617 sps = " ";
618 else
619 sps = "";
620 // The equations
621 temporary_terms_idxs_t temporary_terms_idxs;
622 for (unsigned int i = 0; i < block_size; i++)
623 {
624 temporary_terms_t tt2;
625 if (v_temporary_terms[block].size())
626 {
627 output << " " << "% //Temporary variables" << endl;
628 for (auto it : v_temporary_terms[block][i])
629 {
630 if (dynamic_cast<AbstractExternalFunctionNode *>(it) != nullptr)
631 it->writeExternalFunctionOutput(output, local_output_type, tt2, temporary_terms_idxs, tef_terms);
632
633 output << " " << sps;
634 it->writeOutput(output, local_output_type, local_temporary_terms, {}, tef_terms);
635 output << " = ";
636 it->writeOutput(output, local_output_type, tt2, {}, tef_terms);
637 // Insert current node into tt2
638 tt2.insert(it);
639 output << ";" << endl;
640 }
641 }
642
643 int variable_ID = getBlockVariableID(block, i);
644 int equation_ID = getBlockEquationID(block, i);
645 EquationType equ_type = getBlockEquationType(block, i);
646 string sModel = symbol_table.getName(symbol_table.getID(SymbolType::endogenous, variable_ID));
647 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
648 lhs = eq_node->arg1;
649 rhs = eq_node->arg2;
650 tmp_output.str("");
651 lhs->writeOutput(tmp_output, local_output_type, local_temporary_terms, {});
652 switch (simulation_type)
653 {
654 case EVALUATE_BACKWARD:
655 case EVALUATE_FORWARD:
656 evaluation: if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
657 output << " % equation " << getBlockEquationID(block, i)+1 << " variable : " << sModel
658 << " (" << variable_ID+1 << ") " << c_Equation_Type(equ_type) << endl;
659 output << " ";
660 if (equ_type == E_EVALUATE)
661 {
662 output << tmp_output.str();
663 output << " = ";
664 rhs->writeOutput(output, local_output_type, local_temporary_terms, {});
665 }
666 else if (equ_type == E_EVALUATE_S)
667 {
668 output << "%" << tmp_output.str();
669 output << " = ";
670 if (isBlockEquationRenormalized(block, i))
671 {
672 rhs->writeOutput(output, local_output_type, local_temporary_terms, {});
673 output << endl << " ";
674 tmp_output.str("");
675 eq_node = static_cast<BinaryOpNode *>(getBlockEquationRenormalizedExpr(block, i));
676 lhs = eq_node->arg1;
677 rhs = eq_node->arg2;
678 lhs->writeOutput(output, local_output_type, local_temporary_terms, {});
679 output << " = ";
680 rhs->writeOutput(output, local_output_type, local_temporary_terms, {});
681 }
682 }
683 else
684 {
685 cerr << "Type mismatch for equation " << equation_ID+1 << endl;
686 exit(EXIT_FAILURE);
687 }
688 output << ";" << endl;
689 break;
690 case SOLVE_BACKWARD_SIMPLE:
691 case SOLVE_FORWARD_SIMPLE:
692 case SOLVE_BACKWARD_COMPLETE:
693 case SOLVE_FORWARD_COMPLETE:
694 if (i < block_recursive)
695 goto evaluation;
696 feedback_variables.push_back(variable_ID);
697 output << " % equation " << equation_ID+1 << " variable : " << sModel
698 << " (" << variable_ID+1 << ") " << c_Equation_Type(equ_type) << " symb_id=" << symbol_table.getID(SymbolType::endogenous, variable_ID) << endl;
699 output << " " << "residual(" << i+1-block_recursive << ") = (";
700 goto end;
701 case SOLVE_TWO_BOUNDARIES_COMPLETE:
702 case SOLVE_TWO_BOUNDARIES_SIMPLE:
703 if (i < block_recursive)
704 goto evaluation;
705 feedback_variables.push_back(variable_ID);
706 output << " % equation " << equation_ID+1 << " variable : " << sModel
707 << " (" << variable_ID+1 << ") " << c_Equation_Type(equ_type) << " symb_id=" << symbol_table.getID(SymbolType::endogenous, variable_ID) << endl;
708 Ufoss << " b(" << i+1-block_recursive << "+Per_J_) = -residual(" << i+1-block_recursive << ", it_)";
709 Uf[equation_ID] += Ufoss.str();
710 Ufoss.str("");
711 output << " residual(" << i+1-block_recursive << ", it_) = (";
712 goto end;
713 default:
714 end:
715 output << tmp_output.str();
716 output << ") - (";
717 rhs->writeOutput(output, local_output_type, local_temporary_terms, {});
718 output << ");" << endl;
719 #ifdef CONDITION
720 if (simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE)
721 output << " condition(" << i+1 << ")=0;" << endl;
722 #endif
723 }
724 }
725 // The Jacobian if we have to solve the block
726 if (simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE || simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE)
727 output << " " << sps << "% Jacobian " << endl << " if jacobian_eval" << endl;
728 else
729 if (simulation_type == SOLVE_BACKWARD_SIMPLE || simulation_type == SOLVE_FORWARD_SIMPLE
730 || simulation_type == SOLVE_BACKWARD_COMPLETE || simulation_type == SOLVE_FORWARD_COMPLETE)
731 output << " % Jacobian " << endl << " if jacobian_eval" << endl;
732 else
733 output << " % Jacobian " << endl << " if jacobian_eval" << endl;
734 prev_var = 999999999;
735 prev_lag = -9999999;
736 count_col = 0;
737 for (const auto &it : tmp_block_endo_derivative)
738 {
739 int lag;
740 unsigned int var, eq;
741 tie(lag, var, eq) = it.first;
742 int eqr = getBlockEquationID(block, eq);
743 int varr = getBlockVariableID(block, var);
744 if (var != prev_var || lag != prev_lag)
745 {
746 prev_var = var;
747 prev_lag = lag;
748 count_col++;
749 }
750
751 expr_t id = it.second;
752
753 output << " g1(" << eq+1 << ", " << count_col << ") = ";
754 id->writeOutput(output, local_output_type, local_temporary_terms, {});
755 output << "; % variable=" << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, varr))
756 << "(" << lag
757 << ") " << varr+1 << ", " << var+1
758 << ", equation=" << eqr+1 << ", " << eq+1 << endl;
759 }
760 prev_var = 999999999;
761 prev_lag = -9999999;
762 count_col = 0;
763 for (const auto &it : tmp_block_exo_derivative)
764 {
765 int lag;
766 unsigned int var, eq;
767 tie(lag, var, eq) = it.first;
768 int eqr = getBlockInitialEquationID(block, eq);
769 if (var != prev_var || lag != prev_lag)
770 {
771 prev_var = var;
772 prev_lag = lag;
773 count_col++;
774 }
775 expr_t id = it.second;
776 output << " g1_x(" << eqr+1 << ", " << count_col << ") = ";
777 id->writeOutput(output, local_output_type, local_temporary_terms, {});
778 output << "; % variable=" << symbol_table.getName(symbol_table.getID(SymbolType::exogenous, var))
779 << "(" << lag
780 << ") " << var+1
781 << ", equation=" << eq+1 << endl;
782 }
783 prev_var = 999999999;
784 prev_lag = -9999999;
785 count_col = 0;
786 for (const auto &it : tmp_block_exo_det_derivative)
787 {
788 int lag;
789 unsigned int var, eq;
790 tie(lag, var, eq) = it.first;
791 int eqr = getBlockInitialEquationID(block, eq);
792 if (var != prev_var || lag != prev_lag)
793 {
794 prev_var = var;
795 prev_lag = lag;
796 count_col++;
797 }
798 expr_t id = it.second;
799 output << " g1_xd(" << eqr+1 << ", " << count_col << ") = ";
800 id->writeOutput(output, local_output_type, local_temporary_terms, {});
801 output << "; % variable=" << symbol_table.getName(symbol_table.getID(SymbolType::exogenous, var))
802 << "(" << lag
803 << ") " << var+1
804 << ", equation=" << eq+1 << endl;
805 }
806 prev_var = 999999999;
807 prev_lag = -9999999;
808 count_col = 0;
809 for (const auto &it : tmp_block_other_endo_derivative)
810 {
811 int lag;
812 unsigned int var, eq;
813 tie(lag, var, eq) = it.first;
814 int eqr = getBlockInitialEquationID(block, eq);
815 if (var != prev_var || lag != prev_lag)
816 {
817 prev_var = var;
818 prev_lag = lag;
819 count_col++;
820 }
821 expr_t id = it.second;
822
823 output << " g1_o(" << eqr+1 << ", " << /*var+1+(lag+block_max_lag)*block_size*/ count_col << ") = ";
824 id->writeOutput(output, local_output_type, local_temporary_terms, {});
825 output << "; % variable=" << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, var))
826 << "(" << lag
827 << ") " << var+1
828 << ", equation=" << eq+1 << endl;
829 }
830 output << " varargout{1}=g1_x;" << endl
831 << " varargout{2}=g1_xd;" << endl
832 << " varargout{3}=g1_o;" << endl;
833
834 switch (simulation_type)
835 {
836 case EVALUATE_FORWARD:
837 case EVALUATE_BACKWARD:
838 output << " end;" << endl
839 << " end;" << endl;
840 break;
841 case SOLVE_BACKWARD_SIMPLE:
842 case SOLVE_FORWARD_SIMPLE:
843 case SOLVE_BACKWARD_COMPLETE:
844 case SOLVE_FORWARD_COMPLETE:
845 output << " else" << endl;
846 for (const auto &it : blocks_derivatives[block])
847 {
848 unsigned int eq, var;
849 expr_t id;
850 int lag;
851 tie(eq, var, lag, id) = it;
852 unsigned int eqr = getBlockEquationID(block, eq);
853 unsigned int varr = getBlockVariableID(block, var);
854 if (lag == 0)
855 {
856 output << " g1(" << eq+1 << ", " << var+1-block_recursive << ") = ";
857 id->writeOutput(output, local_output_type, local_temporary_terms, {});
858 output << "; % variable=" << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, varr))
859 << "(" << lag
860 << ") " << varr+1
861 << ", equation=" << eqr+1 << endl;
862 }
863
864 }
865 output << " end;" << endl;
866 break;
867 case SOLVE_TWO_BOUNDARIES_SIMPLE:
868 case SOLVE_TWO_BOUNDARIES_COMPLETE:
869 output << " else" << endl;
870 for (const auto &it : blocks_derivatives[block])
871 {
872 unsigned int eq, var;
873 int lag;
874 expr_t id;
875 tie(eq, var, lag, id) = it;
876 unsigned int eqr = getBlockEquationID(block, eq);
877 unsigned int varr = getBlockVariableID(block, var);
878 ostringstream tmp_output;
879 if (eq >= block_recursive && var >= block_recursive)
880 {
881 if (lag == 0)
882 Ufoss << "+g1(" << eq+1-block_recursive
883 << "+Per_J_, " << var+1-block_recursive
884 << "+Per_K_)*y(it_, " << varr+1 << ")";
885 else if (lag == 1)
886 Ufoss << "+g1(" << eq+1-block_recursive
887 << "+Per_J_, " << var+1-block_recursive
888 << "+Per_y_)*y(it_+1, " << varr+1 << ")";
889 else if (lag > 0)
890 Ufoss << "+g1(" << eq+1-block_recursive
891 << "+Per_J_, " << var+1-block_recursive
892 << "+y_size*(it_+" << lag-1 << "))*y(it_+" << lag << ", " << varr+1 << ")";
893 else
894 Ufoss << "+g1(" << eq+1-block_recursive
895 << "+Per_J_, " << var+1-block_recursive
896 << "+y_size*(it_" << lag-1 << "))*y(it_" << lag << ", " << varr+1 << ")";
897 Uf[eqr] += Ufoss.str();
898 Ufoss.str("");
899
900 if (lag == 0)
901 tmp_output << " g1(" << eq+1-block_recursive << "+Per_J_, "
902 << var+1-block_recursive << "+Per_K_) = ";
903 else if (lag == 1)
904 tmp_output << " g1(" << eq+1-block_recursive << "+Per_J_, "
905 << var+1-block_recursive << "+Per_y_) = ";
906 else if (lag > 0)
907 tmp_output << " g1(" << eq+1-block_recursive << "+Per_J_, "
908 << var+1-block_recursive << "+y_size*(it_+" << lag-1 << ")) = ";
909 else if (lag < 0)
910 tmp_output << " g1(" << eq+1-block_recursive << "+Per_J_, "
911 << var+1-block_recursive << "+y_size*(it_" << lag-1 << ")) = ";
912 output << " " << tmp_output.str();
913 id->writeOutput(output, local_output_type, local_temporary_terms, {});
914 output << ";";
915 output << " %2 variable=" << symbol_table.getName(symbol_table.getID(SymbolType::endogenous, varr))
916 << "(" << lag << ") " << varr+1
917 << ", equation=" << eqr+1 << " (" << eq+1 << ")" << endl;
918 }
919
920 #ifdef CONDITION
921 output << " if (fabs(condition[" << eqr << "])<fabs(u[" << u << "+Per_u_]))" << endl
922 << " condition(" << eqr << ")=u(" << u << "+Per_u_);" << endl;
923 #endif
924 }
925 for (unsigned int i = 0; i < block_size; i++)
926 {
927 if (i >= block_recursive)
928 output << " " << Uf[getBlockEquationID(block, i)] << ";" << endl;
929 #ifdef CONDITION
930 output << " if (fabs(condition(" << i+1 << "))<fabs(u(" << i << "+Per_u_)))" << endl
931 << " condition(" << i+1 << ")=u(" << i+1 << "+Per_u_);" << endl;
932 #endif
933 }
934 #ifdef CONDITION
935 for (m = 0; m <= ModelBlock->Block_List[block].Max_Lead+ModelBlock->Block_List[block].Max_Lag; m++)
936 {
937 k = m-ModelBlock->Block_List[block].Max_Lag;
938 for (i = 0; i < ModelBlock->Block_List[block].IM_lead_lag[m].size; i++)
939 {
940 unsigned int eq = ModelBlock->Block_List[block].IM_lead_lag[m].Equ_Index[i];
941 unsigned int var = ModelBlock->Block_List[block].IM_lead_lag[m].Var_Index[i];
942 unsigned int u = ModelBlock->Block_List[block].IM_lead_lag[m].u[i];
943 unsigned int eqr = ModelBlock->Block_List[block].IM_lead_lag[m].Equ[i];
944 output << " u(" << u+1 << "+Per_u_) = u(" << u+1 << "+Per_u_) / condition(" << eqr+1 << ");" << endl;
945 }
946 }
947 for (i = 0; i < ModelBlock->Block_List[block].Size; i++)
948 output << " u(" << i+1 << "+Per_u_) = u(" << i+1 << "+Per_u_) / condition(" << i+1 << ");" << endl;
949 #endif
950 output << " end;" << endl
951 << " end;" << endl;
952 break;
953 default:
954 break;
955 }
956 output << "end" << endl;
957 output.close();
958 }
959 }
960
961 void
writeModelEquationsCode(const string & basename,const map_idx_t & map_idx) const962 DynamicModel::writeModelEquationsCode(const string &basename, const map_idx_t &map_idx) const
963 {
964
965 ostringstream tmp_output;
966 ofstream code_file;
967 unsigned int instruction_number = 0;
968 bool file_open = false;
969
970 filesystem::create_directories(basename + "/model/bytecode");
971
972 string main_name = basename + "/model/bytecode/dynamic.cod";
973 code_file.open(main_name, ios::out | ios::binary | ios::ate);
974 if (!code_file.is_open())
975 {
976 cerr << R"(Error : Can't open file ")" << main_name << R"(" for writing)" << endl;
977 exit(EXIT_FAILURE);
978 }
979
980 int count_u;
981 int u_count_int = 0;
982 BlockSimulationType simulation_type;
983 if ((max_endo_lag > 0) && (max_endo_lead > 0))
984 simulation_type = SOLVE_TWO_BOUNDARIES_COMPLETE;
985 else if ((max_endo_lag >= 0) && (max_endo_lead == 0))
986 simulation_type = SOLVE_FORWARD_COMPLETE;
987 else
988 simulation_type = SOLVE_BACKWARD_COMPLETE;
989
990 Write_Inf_To_Bin_File(basename + "/model/bytecode/dynamic.bin", u_count_int, file_open, simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE, symbol_table.endo_nbr());
991 file_open = true;
992
993 //Temporary variables declaration
994 FDIMT_ fdimt(temporary_terms.size());
995 fdimt.write(code_file, instruction_number);
996
997 vector<unsigned int> exo, exo_det, other_endo;
998
999 for (int i = 0; i < symbol_table.exo_det_nbr(); i++)
1000 exo_det.push_back(i);
1001 for (int i = 0; i < symbol_table.exo_nbr(); i++)
1002 exo.push_back(i);
1003
1004 map<tuple<int, int, int>, expr_t> first_derivatives_reordered_endo;
1005 map<tuple<int, SymbolType, int, int>, expr_t> first_derivatives_reordered_exo;
1006 for (const auto & [indices, d1] : derivatives[1])
1007 {
1008 int deriv_id = indices[1];
1009 unsigned int eq = indices[0];
1010 int symb = getSymbIDByDerivID(deriv_id);
1011 unsigned int var = symbol_table.getTypeSpecificID(symb);
1012 int lag = getLagByDerivID(deriv_id);
1013 if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
1014 first_derivatives_reordered_endo[{ lag, var, eq }] = d1;
1015 else if (getTypeByDerivID(deriv_id) == SymbolType::exogenous || getTypeByDerivID(deriv_id) == SymbolType::exogenousDet)
1016 first_derivatives_reordered_exo[{ lag, getTypeByDerivID(deriv_id), var, eq }] = d1;
1017 }
1018 int prev_var = -1;
1019 int prev_lag = -999999999;
1020 int count_col_endo = 0;
1021 for (const auto &it : first_derivatives_reordered_endo)
1022 {
1023 int var, lag;
1024 tie(lag, var, ignore) = it.first;
1025 if (prev_var != var || prev_lag != lag)
1026 {
1027 prev_var = var;
1028 prev_lag = lag;
1029 count_col_endo++;
1030 }
1031 }
1032 prev_var = -1;
1033 prev_lag = -999999999;
1034 SymbolType prev_type{SymbolType::unusedEndogenous}; // Any non-exogenous type would do here
1035 int count_col_exo = 0;
1036 int count_col_det_exo = 0;
1037
1038 for (const auto &it : first_derivatives_reordered_exo)
1039 {
1040 int var, lag;
1041 SymbolType type;
1042 tie(lag, type, var, ignore) = it.first;
1043 if (prev_var != var || prev_lag != lag || prev_type != type)
1044 {
1045 prev_var = var;
1046 prev_lag = lag;
1047 prev_type = type;
1048 if (type == SymbolType::exogenous)
1049 count_col_exo++;
1050 else if (type == SymbolType::exogenousDet)
1051 count_col_det_exo++;
1052 }
1053 }
1054
1055 FBEGINBLOCK_ fbeginblock(symbol_table.endo_nbr(),
1056 simulation_type,
1057 0,
1058 symbol_table.endo_nbr(),
1059 variable_reordered,
1060 equation_reordered,
1061 false,
1062 symbol_table.endo_nbr(),
1063 max_endo_lag,
1064 max_endo_lead,
1065 u_count_int,
1066 count_col_endo,
1067 symbol_table.exo_det_nbr(),
1068 count_col_det_exo,
1069 symbol_table.exo_nbr(),
1070 count_col_exo,
1071 0,
1072 0,
1073 exo_det,
1074 exo,
1075 other_endo
1076 );
1077 fbeginblock.write(code_file, instruction_number);
1078
1079 compileTemporaryTerms(code_file, instruction_number, temporary_terms, map_idx, true, false);
1080
1081 compileModelEquations(code_file, instruction_number, temporary_terms, map_idx, true, false);
1082
1083 FENDEQU_ fendequ;
1084 fendequ.write(code_file, instruction_number);
1085
1086 // Get the current code_file position and jump if eval = true
1087 streampos pos1 = code_file.tellp();
1088 FJMPIFEVAL_ fjmp_if_eval(0);
1089 fjmp_if_eval.write(code_file, instruction_number);
1090 int prev_instruction_number = instruction_number;
1091
1092 vector<vector<tuple<int, int, int>>> my_derivatives(symbol_table.endo_nbr());;
1093 count_u = symbol_table.endo_nbr();
1094 for (const auto & [indices, d1] : derivatives[1])
1095 {
1096 int deriv_id = indices[1];
1097 if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
1098 {
1099 unsigned int eq = indices[0];
1100 int symb = getSymbIDByDerivID(deriv_id);
1101 unsigned int var = symbol_table.getTypeSpecificID(symb);
1102 int lag = getLagByDerivID(deriv_id);
1103 FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var, lag);
1104 fnumexpr.write(code_file, instruction_number);
1105 if (!my_derivatives[eq].size())
1106 my_derivatives[eq].clear();
1107 my_derivatives[eq].emplace_back(var, lag, count_u);
1108 d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1109
1110 FSTPU_ fstpu(count_u);
1111 fstpu.write(code_file, instruction_number);
1112 count_u++;
1113 }
1114 }
1115 for (int i = 0; i < symbol_table.endo_nbr(); i++)
1116 {
1117 FLDR_ fldr(i);
1118 fldr.write(code_file, instruction_number);
1119 if (my_derivatives[i].size())
1120 {
1121 for (auto it = my_derivatives[i].begin(); it != my_derivatives[i].end(); ++it)
1122 {
1123 FLDU_ fldu(get<2>(*it));
1124 fldu.write(code_file, instruction_number);
1125 FLDV_ fldv{static_cast<int>(SymbolType::endogenous), static_cast<unsigned int>(get<0>(*it)), get<1>(*it)};
1126 fldv.write(code_file, instruction_number);
1127 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)};
1128 fbinary.write(code_file, instruction_number);
1129 if (it != my_derivatives[i].begin())
1130 {
1131 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::plus)};
1132 fbinary.write(code_file, instruction_number);
1133 }
1134 }
1135 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::minus)};
1136 fbinary.write(code_file, instruction_number);
1137 }
1138 FSTPU_ fstpu(i);
1139 fstpu.write(code_file, instruction_number);
1140 }
1141
1142 // Get the current code_file position and jump = true
1143 streampos pos2 = code_file.tellp();
1144 FJMP_ fjmp(0);
1145 fjmp.write(code_file, instruction_number);
1146 // Set code_file position to previous JMPIFEVAL_ and set the number of instructions to jump
1147 streampos pos3 = code_file.tellp();
1148 code_file.seekp(pos1);
1149 FJMPIFEVAL_ fjmp_if_eval1(instruction_number - prev_instruction_number);
1150 fjmp_if_eval1.write(code_file, instruction_number);
1151 code_file.seekp(pos3);
1152 prev_instruction_number = instruction_number;
1153
1154 // The Jacobian
1155 prev_var = -1;
1156 prev_lag = -999999999;
1157 count_col_endo = 0;
1158 for (const auto &it : first_derivatives_reordered_endo)
1159 {
1160 unsigned int eq;
1161 int var, lag;
1162 tie(lag, var, eq) = it.first;
1163 expr_t d1 = it.second;
1164 FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var, lag);
1165 fnumexpr.write(code_file, instruction_number);
1166 if (prev_var != var || prev_lag != lag)
1167 {
1168 prev_var = var;
1169 prev_lag = lag;
1170 count_col_endo++;
1171 }
1172 d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1173 FSTPG3_ fstpg3(eq, var, lag, count_col_endo-1);
1174 fstpg3.write(code_file, instruction_number);
1175 }
1176 prev_var = -1;
1177 prev_lag = -999999999;
1178 count_col_exo = 0;
1179 for (const auto &it : first_derivatives_reordered_exo)
1180 {
1181 int lag, var, eq;
1182 tie(lag, ignore, var, eq) = it.first;
1183 expr_t d1 = it.second;
1184 FNUMEXPR_ fnumexpr(FirstExoDerivative, eq, var, lag);
1185 fnumexpr.write(code_file, instruction_number);
1186 if (prev_var != var || prev_lag != lag)
1187 {
1188 prev_var = var;
1189 prev_lag = lag;
1190 count_col_exo++;
1191 }
1192 d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1193 FSTPG3_ fstpg3(eq, var, lag, count_col_exo-1);
1194 fstpg3.write(code_file, instruction_number);
1195 }
1196 // Set codefile position to previous JMP_ and set the number of instructions to jump
1197 pos1 = code_file.tellp();
1198 code_file.seekp(pos2);
1199 FJMP_ fjmp1(instruction_number - prev_instruction_number);
1200 fjmp1.write(code_file, instruction_number);
1201 code_file.seekp(pos1);
1202
1203 FENDBLOCK_ fendblock;
1204 fendblock.write(code_file, instruction_number);
1205 FEND_ fend;
1206 fend.write(code_file, instruction_number);
1207 code_file.close();
1208 }
1209
1210 void
writeModelEquationsCode_Block(const string & basename,const map_idx_t & map_idx,bool linear_decomposition) const1211 DynamicModel::writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx, bool linear_decomposition) const
1212 {
1213 struct Uff_l
1214 {
1215 int u, var, lag;
1216 Uff_l *pNext;
1217 };
1218
1219 struct Uff
1220 {
1221 Uff_l *Ufl, *Ufl_First;
1222 };
1223
1224 int i, v;
1225 string tmp_s;
1226 ostringstream tmp_output;
1227 ofstream code_file;
1228 unsigned int instruction_number = 0;
1229 expr_t lhs = nullptr, rhs = nullptr;
1230 BinaryOpNode *eq_node;
1231 Uff Uf[symbol_table.endo_nbr()];
1232 map<expr_t, int> reference_count;
1233 deriv_node_temp_terms_t tef_terms;
1234 vector<int> feedback_variables;
1235 bool file_open = false;
1236 string main_name;
1237 filesystem::create_directories(basename + "/model/bytecode");
1238 if (linear_decomposition)
1239 main_name = basename + "/model/bytecode/non_linear.cod";
1240 else
1241 main_name = basename + "/model/bytecode/dynamic.cod";
1242 code_file.open(main_name, ios::out | ios::binary | ios::ate);
1243 if (!code_file.is_open())
1244 {
1245 cerr << R"(Error : Can't open file ")" << main_name << R"(" for writing)" << endl;
1246 exit(EXIT_FAILURE);
1247 }
1248 //Temporary variables declaration
1249
1250 FDIMT_ fdimt(temporary_terms.size());
1251 fdimt.write(code_file, instruction_number);
1252
1253 for (unsigned int block = 0; block < getNbBlocks(); block++)
1254 {
1255 feedback_variables.clear();
1256 if (block > 0)
1257 {
1258 FENDBLOCK_ fendblock;
1259 fendblock.write(code_file, instruction_number);
1260 }
1261 int count_u;
1262 int u_count_int = 0;
1263 BlockSimulationType simulation_type = getBlockSimulationType(block);
1264 unsigned int block_size = getBlockSize(block);
1265 unsigned int block_mfs = getBlockMfs(block);
1266 unsigned int block_recursive = block_size - block_mfs;
1267 int block_max_lag = max_leadlag_block[block].first;
1268 int block_max_lead = max_leadlag_block[block].second;
1269
1270 if (simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE || simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE
1271 || simulation_type == SOLVE_BACKWARD_COMPLETE || simulation_type == SOLVE_FORWARD_COMPLETE)
1272 {
1273 Write_Inf_To_Bin_File_Block(basename, block, u_count_int, file_open,
1274 simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE, linear_decomposition);
1275 file_open = true;
1276 }
1277 map<tuple<int, int, int>, expr_t> tmp_block_endo_derivative;
1278 for (const auto &it : blocks_derivatives[block])
1279 tmp_block_endo_derivative[{ get<2>(it), get<1>(it), get<0>(it) }] = get<3>(it);
1280 map<tuple<int, int, int>, expr_t> tmp_exo_derivative;
1281 for (const auto &it : derivative_exo[block])
1282 tmp_exo_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
1283 map<tuple<int, int, int>, expr_t> tmp_exo_det_derivative;
1284 for (const auto &it : derivative_exo_det[block])
1285 tmp_exo_det_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
1286 map<tuple<int, int, int>, expr_t> tmp_other_endo_derivative;
1287 for (const auto &it : derivative_other_endo[block])
1288 tmp_other_endo_derivative[{ get<0>(it.first), get<2>(it.first), get<1>(it.first) }] = it.second;
1289 int prev_var = -1;
1290 int prev_lag = -999999999;
1291 int count_col_endo = 0;
1292 for (const auto &it : tmp_block_endo_derivative)
1293 {
1294 int lag, var;
1295 tie(lag, var, ignore) = it.first;
1296 if (prev_var != var || prev_lag != lag)
1297 {
1298 prev_var = var;
1299 prev_lag = lag;
1300 count_col_endo++;
1301 }
1302 }
1303 unsigned int count_col_det_exo = 0;
1304 vector<unsigned int> exo_det;
1305 for (const auto &it : exo_det_block[block])
1306 for (const auto &it1 : it.second)
1307 {
1308 count_col_det_exo++;
1309 if (find(exo_det.begin(), exo_det.end(), it1) == exo_det.end())
1310 exo_det.push_back(it1);
1311 }
1312
1313 unsigned int count_col_exo = 0;
1314 vector<unsigned int> exo;
1315 for (const auto &it : exo_block[block])
1316 for (const auto &it1 : it.second)
1317 {
1318 count_col_exo++;
1319 if (find(exo.begin(), exo.end(), it1) == exo.end())
1320 exo.push_back(it1);
1321 }
1322
1323 vector<unsigned int> other_endo;
1324 unsigned int count_col_other_endo = 0;
1325 for (const auto &it : other_endo_block[block])
1326 for (const auto &it1 : it.second)
1327 {
1328 count_col_other_endo++;
1329 if (find(other_endo.begin(), other_endo.end(), it1) == other_endo.end())
1330 other_endo.push_back(it1);
1331 }
1332
1333 FBEGINBLOCK_ fbeginblock(block_mfs,
1334 simulation_type,
1335 getBlockFirstEquation(block),
1336 block_size,
1337 variable_reordered,
1338 equation_reordered,
1339 blocks_linear[block],
1340 symbol_table.endo_nbr(),
1341 block_max_lag,
1342 block_max_lead,
1343 u_count_int,
1344 count_col_endo,
1345 exo_det.size(),
1346 count_col_det_exo,
1347 exo.size(),
1348 getBlockExoColSize(block),
1349 other_endo.size(),
1350 count_col_other_endo,
1351 exo_det,
1352 exo,
1353 other_endo
1354 );
1355 fbeginblock.write(code_file, instruction_number);
1356
1357 if (linear_decomposition)
1358 compileTemporaryTerms(code_file, instruction_number, temporary_terms, map_idx, true, false);
1359
1360 // The equations
1361 for (i = 0; i < static_cast<int>(block_size); i++)
1362 {
1363 //The Temporary terms
1364 temporary_terms_t tt2;
1365 if (v_temporary_terms[block][i].size() && !linear_decomposition)
1366 {
1367 for (auto it : v_temporary_terms[block][i])
1368 {
1369 if (dynamic_cast<AbstractExternalFunctionNode *>(it) != nullptr)
1370 it->compileExternalFunctionOutput(code_file, instruction_number, false, tt2, map_idx, true, false, tef_terms);
1371
1372 FNUMEXPR_ fnumexpr(TemporaryTerm, static_cast<int>(map_idx.find(it->idx)->second));
1373 fnumexpr.write(code_file, instruction_number);
1374 it->compile(code_file, instruction_number, false, tt2, map_idx, true, false, tef_terms);
1375 FSTPT_ fstpt(static_cast<int>(map_idx.find(it->idx)->second));
1376 fstpt.write(code_file, instruction_number);
1377 // Insert current node into tt2
1378 tt2.insert(it);
1379 #ifdef DEBUGC
1380 cout << "FSTPT " << v << endl;
1381 instruction_number++;
1382 code_file.write(&FOK, sizeof(FOK));
1383 code_file.write(reinterpret_cast<char *>(&k), sizeof(k));
1384 ki++;
1385 #endif
1386
1387 }
1388 }
1389 #ifdef DEBUGC
1390 for (const auto &it : v_temporary_terms[block][i])
1391 {
1392 auto ii = map_idx.find(it->idx);
1393 cout << "map_idx[" << it->idx <<"]=" << ii->second << endl;
1394 }
1395 #endif
1396
1397 int variable_ID, equation_ID;
1398 EquationType equ_type;
1399
1400 switch (simulation_type)
1401 {
1402 evaluation:
1403 case EVALUATE_BACKWARD:
1404 case EVALUATE_FORWARD:
1405 equ_type = getBlockEquationType(block, i);
1406 {
1407 FNUMEXPR_ fnumexpr(ModelEquation, getBlockEquationID(block, i));
1408 fnumexpr.write(code_file, instruction_number);
1409 }
1410 if (equ_type == E_EVALUATE)
1411 {
1412 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
1413 lhs = eq_node->arg1;
1414 rhs = eq_node->arg2;
1415 rhs->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1416 lhs->compile(code_file, instruction_number, true, temporary_terms, map_idx, true, false);
1417 }
1418 else if (equ_type == E_EVALUATE_S)
1419 {
1420 eq_node = static_cast<BinaryOpNode *>(getBlockEquationRenormalizedExpr(block, i));
1421 lhs = eq_node->arg1;
1422 rhs = eq_node->arg2;
1423 rhs->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1424 lhs->compile(code_file, instruction_number, true, temporary_terms, map_idx, true, false);
1425 }
1426 break;
1427 case SOLVE_BACKWARD_COMPLETE:
1428 case SOLVE_FORWARD_COMPLETE:
1429 case SOLVE_TWO_BOUNDARIES_COMPLETE:
1430 case SOLVE_TWO_BOUNDARIES_SIMPLE:
1431 if (i < static_cast<int>(block_recursive))
1432 goto evaluation;
1433 variable_ID = getBlockVariableID(block, i);
1434 equation_ID = getBlockEquationID(block, i);
1435 feedback_variables.push_back(variable_ID);
1436 Uf[equation_ID].Ufl = nullptr;
1437 goto end;
1438 default:
1439 end:
1440 FNUMEXPR_ fnumexpr(ModelEquation, getBlockEquationID(block, i));
1441 fnumexpr.write(code_file, instruction_number);
1442 eq_node = static_cast<BinaryOpNode *>(getBlockEquationExpr(block, i));
1443 lhs = eq_node->arg1;
1444 rhs = eq_node->arg2;
1445 lhs->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1446 rhs->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1447
1448 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::minus)};
1449 fbinary.write(code_file, instruction_number);
1450 FSTPR_ fstpr(i - block_recursive);
1451 fstpr.write(code_file, instruction_number);
1452 }
1453 }
1454 FENDEQU_ fendequ;
1455 fendequ.write(code_file, instruction_number);
1456
1457 // Get the current code_file position and jump if eval = true
1458 streampos pos1 = code_file.tellp();
1459 FJMPIFEVAL_ fjmp_if_eval(0);
1460 fjmp_if_eval.write(code_file, instruction_number);
1461 int prev_instruction_number = instruction_number;
1462 // The Jacobian if we have to solve the block determinsitic block
1463 if (simulation_type != EVALUATE_BACKWARD
1464 && simulation_type != EVALUATE_FORWARD)
1465 {
1466 switch (simulation_type)
1467 {
1468 case SOLVE_BACKWARD_SIMPLE:
1469 case SOLVE_FORWARD_SIMPLE:
1470 {
1471 FNUMEXPR_ fnumexpr(FirstEndoDerivative, getBlockEquationID(block, 0), getBlockVariableID(block, 0), 0);
1472 fnumexpr.write(code_file, instruction_number);
1473 }
1474 compileDerivative(code_file, instruction_number, getBlockEquationID(block, 0), getBlockVariableID(block, 0), 0, map_idx);
1475 {
1476 FSTPG_ fstpg(0);
1477 fstpg.write(code_file, instruction_number);
1478 }
1479 break;
1480
1481 case SOLVE_BACKWARD_COMPLETE:
1482 case SOLVE_FORWARD_COMPLETE:
1483 case SOLVE_TWO_BOUNDARIES_COMPLETE:
1484 case SOLVE_TWO_BOUNDARIES_SIMPLE:
1485 count_u = feedback_variables.size();
1486 for (const auto &it : blocks_derivatives[block])
1487 {
1488 unsigned int eq, var;
1489 int lag;
1490 tie(eq, var, lag, ignore) = it;
1491 unsigned int eqr = getBlockEquationID(block, eq);
1492 unsigned int varr = getBlockVariableID(block, var);
1493 if (eq >= block_recursive and var >= block_recursive)
1494 {
1495 if (lag != 0 && (simulation_type == SOLVE_FORWARD_COMPLETE || simulation_type == SOLVE_BACKWARD_COMPLETE))
1496 continue;
1497 if (!Uf[eqr].Ufl)
1498 {
1499 Uf[eqr].Ufl = static_cast<Uff_l *>(malloc(sizeof(Uff_l)));
1500 Uf[eqr].Ufl_First = Uf[eqr].Ufl;
1501 }
1502 else
1503 {
1504 Uf[eqr].Ufl->pNext = static_cast<Uff_l *>(malloc(sizeof(Uff_l)));
1505 Uf[eqr].Ufl = Uf[eqr].Ufl->pNext;
1506 }
1507 Uf[eqr].Ufl->pNext = nullptr;
1508 Uf[eqr].Ufl->u = count_u;
1509 Uf[eqr].Ufl->var = varr;
1510 Uf[eqr].Ufl->lag = lag;
1511 FNUMEXPR_ fnumexpr(FirstEndoDerivative, eqr, varr, lag);
1512 fnumexpr.write(code_file, instruction_number);
1513 compileChainRuleDerivative(code_file, instruction_number, eqr, varr, lag, map_idx);
1514 FSTPU_ fstpu(count_u);
1515 fstpu.write(code_file, instruction_number);
1516 count_u++;
1517 }
1518 }
1519 for (i = 0; i < static_cast<int>(block_size); i++)
1520 {
1521 if (i >= static_cast<int>(block_recursive))
1522 {
1523 FLDR_ fldr(i-block_recursive);
1524 fldr.write(code_file, instruction_number);
1525
1526 FLDZ_ fldz;
1527 fldz.write(code_file, instruction_number);
1528
1529 v = getBlockEquationID(block, i);
1530 for (Uf[v].Ufl = Uf[v].Ufl_First; Uf[v].Ufl; Uf[v].Ufl = Uf[v].Ufl->pNext)
1531 {
1532 FLDU_ fldu(Uf[v].Ufl->u);
1533 fldu.write(code_file, instruction_number);
1534 FLDV_ fldv{static_cast<int>(SymbolType::endogenous), static_cast<unsigned int>(Uf[v].Ufl->var), Uf[v].Ufl->lag};
1535 fldv.write(code_file, instruction_number);
1536
1537 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)};
1538 fbinary.write(code_file, instruction_number);
1539
1540 FCUML_ fcuml;
1541 fcuml.write(code_file, instruction_number);
1542 }
1543 Uf[v].Ufl = Uf[v].Ufl_First;
1544 while (Uf[v].Ufl)
1545 {
1546 Uf[v].Ufl_First = Uf[v].Ufl->pNext;
1547 free(Uf[v].Ufl);
1548 Uf[v].Ufl = Uf[v].Ufl_First;
1549 }
1550 FBINARY_ fbinary{static_cast<int>(BinaryOpcode::minus)};
1551 fbinary.write(code_file, instruction_number);
1552
1553 FSTPU_ fstpu(i - block_recursive);
1554 fstpu.write(code_file, instruction_number);
1555 }
1556 }
1557 break;
1558 default:
1559 break;
1560 }
1561 }
1562 // Get the current code_file position and jump = true
1563 streampos pos2 = code_file.tellp();
1564 FJMP_ fjmp(0);
1565 fjmp.write(code_file, instruction_number);
1566 // Set code_file position to previous JMPIFEVAL_ and set the number of instructions to jump
1567 streampos pos3 = code_file.tellp();
1568 code_file.seekp(pos1);
1569 FJMPIFEVAL_ fjmp_if_eval1(instruction_number - prev_instruction_number);
1570 fjmp_if_eval1.write(code_file, instruction_number);
1571 code_file.seekp(pos3);
1572 prev_instruction_number = instruction_number;
1573 // The Jacobian if we have to solve the block determinsitic block
1574
1575 prev_var = -1;
1576 prev_lag = -999999999;
1577 count_col_endo = 0;
1578 for (const auto &it : tmp_block_endo_derivative)
1579 {
1580 int lag, var;
1581 unsigned int eq;
1582 tie(lag, var, eq) = it.first;
1583 unsigned int eqr = getBlockEquationID(block, eq);
1584 unsigned int varr = getBlockVariableID(block, var);
1585 if (prev_var != var || prev_lag != lag)
1586 {
1587 prev_var = var;
1588 prev_lag = lag;
1589 count_col_endo++;
1590 }
1591 FNUMEXPR_ fnumexpr(FirstEndoDerivative, eqr, varr, lag);
1592 fnumexpr.write(code_file, instruction_number);
1593 compileDerivative(code_file, instruction_number, eqr, varr, lag, map_idx);
1594 FSTPG3_ fstpg3(eq, var, lag, count_col_endo-1);
1595 fstpg3.write(code_file, instruction_number);
1596 }
1597 prev_var = -1;
1598 prev_lag = -999999999;
1599 count_col_exo = 0;
1600 for (const auto &it : tmp_exo_derivative)
1601 {
1602 int lag, eq, var;
1603 tie(lag, var, eq) = it.first;
1604 int eqr = getBlockInitialEquationID(block, eq);
1605 int varr = getBlockInitialExogenousID(block, var);
1606 if (prev_var != var || prev_lag != lag)
1607 {
1608 prev_var = var;
1609 prev_lag = lag;
1610 count_col_exo++;
1611 }
1612 expr_t id = it.second;
1613
1614 FNUMEXPR_ fnumexpr(FirstExoDerivative, eqr, varr, lag);
1615 fnumexpr.write(code_file, instruction_number);
1616 id->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1617 FSTPG3_ fstpg3(eq, var, lag, count_col_exo-1);
1618 fstpg3.write(code_file, instruction_number);
1619 }
1620 prev_var = -1;
1621 prev_lag = -999999999;
1622 int count_col_exo_det = 0;
1623 for (const auto &it : tmp_exo_det_derivative)
1624 {
1625 int lag, eq, var;
1626 tie(lag, var, eq) = it.first;
1627 int eqr = getBlockInitialEquationID(block, eq);
1628 int varr = getBlockInitialDetExogenousID(block, var);
1629 if (prev_var != var || prev_lag != lag)
1630 {
1631 prev_var = var;
1632 prev_lag = lag;
1633 count_col_exo_det++;
1634 }
1635 expr_t id = it.second;
1636
1637 FNUMEXPR_ fnumexpr(FirstExodetDerivative, eqr, varr, lag);
1638 fnumexpr.write(code_file, instruction_number);
1639 id->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1640 FSTPG3_ fstpg3(eq, var, lag, count_col_exo_det-1);
1641 fstpg3.write(code_file, instruction_number);
1642 }
1643 prev_var = -1;
1644 prev_lag = -999999999;
1645 count_col_other_endo = 0;
1646 for (const auto &it : tmp_other_endo_derivative)
1647 {
1648 int lag, eq, var;
1649 tie(lag, var, eq) = it.first;
1650 int eqr = getBlockInitialEquationID(block, eq);
1651 int varr = getBlockInitialOtherEndogenousID(block, var);;
1652 if (prev_var != var || prev_lag != lag)
1653 {
1654 prev_var = var;
1655 prev_lag = lag;
1656 count_col_other_endo++;
1657 }
1658 expr_t id = it.second;
1659
1660 FNUMEXPR_ fnumexpr(FirstOtherEndoDerivative, eqr, varr, lag);
1661 fnumexpr.write(code_file, instruction_number);
1662 id->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
1663 FSTPG3_ fstpg3(eq, var, lag, count_col_other_endo-1);
1664 fstpg3.write(code_file, instruction_number);
1665 }
1666
1667 // Set codefile position to previous JMP_ and set the number of instructions to jump
1668 pos1 = code_file.tellp();
1669 code_file.seekp(pos2);
1670 FJMP_ fjmp1(instruction_number - prev_instruction_number);
1671 fjmp1.write(code_file, instruction_number);
1672 code_file.seekp(pos1);
1673 }
1674 FENDBLOCK_ fendblock;
1675 fendblock.write(code_file, instruction_number);
1676 FEND_ fend;
1677 fend.write(code_file, instruction_number);
1678 code_file.close();
1679 }
1680
1681 void
writeDynamicMFile(const string & basename) const1682 DynamicModel::writeDynamicMFile(const string &basename) const
1683 {
1684 writeDynamicModel(basename, false, false);
1685 }
1686
1687 void
writeDynamicJuliaFile(const string & basename) const1688 DynamicModel::writeDynamicJuliaFile(const string &basename) const
1689 {
1690 writeDynamicModel(basename, false, true);
1691 }
1692
1693 void
writeDynamicCFile(const string & basename) const1694 DynamicModel::writeDynamicCFile(const string &basename) const
1695 {
1696 filesystem::create_directories(basename + "/model/src");
1697 string filename = basename + "/model/src/dynamic.c";
1698 string filename_mex = basename + "/model/src/dynamic_mex.c";
1699 ofstream mDynamicModelFile, mDynamicMexFile;
1700
1701 int ntt = temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size();
1702
1703 mDynamicModelFile.open(filename, ios::out | ios::binary);
1704 if (!mDynamicModelFile.is_open())
1705 {
1706 cerr << "Error: Can't open file " << filename << " for writing" << endl;
1707 exit(EXIT_FAILURE);
1708 }
1709 mDynamicModelFile << "/*" << endl
1710 << " * " << filename << " : Computes dynamic model for Dynare" << endl
1711 << " *" << endl
1712 << " * Warning : this file is generated automatically by Dynare" << endl
1713 << " * from model file (.mod)" << endl
1714 << " */" << endl
1715 << "#include <math.h>" << endl;
1716
1717 mDynamicModelFile << "#include <stdlib.h>" << endl;
1718
1719 if (external_functions_table.get_total_number_of_unique_model_block_external_functions())
1720 // External Matlab function, implies Dynamic function will call mex
1721 mDynamicModelFile
1722 #ifndef __APPLE__
1723 << "#include <uchar.h>" << endl // For MATLAB ≤ R2011a
1724 #else
1725 << "typedef uint_least16_t char16_t;" << endl
1726 << "typedef uint_least32_t char32_t;" << endl // uchar.h does not exist on macOS
1727 #endif
1728 << R"(#include "mex.h")" << endl;
1729
1730 mDynamicModelFile << "#define max(a, b) (((a) > (b)) ? (a) : (b))" << endl
1731 << "#define min(a, b) (((a) > (b)) ? (b) : (a))" << endl;
1732
1733 // Write function definition if BinaryOpcode::powerDeriv is used
1734 writePowerDerivCHeader(mDynamicModelFile);
1735
1736 mDynamicModelFile << endl;
1737
1738 // Writing the function body
1739 writeDynamicModel(mDynamicModelFile, true, false);
1740
1741 mDynamicModelFile << endl;
1742
1743 writePowerDeriv(mDynamicModelFile);
1744 mDynamicModelFile.close();
1745
1746 mDynamicMexFile.open(filename_mex, ios::out | ios::binary);
1747 if (!mDynamicMexFile.is_open())
1748 {
1749 cerr << "Error: Can't open file " << filename_mex << " for writing" << endl;
1750 exit(EXIT_FAILURE);
1751 }
1752
1753 // Writing the gateway routine
1754 mDynamicMexFile << "/*" << endl
1755 << " * " << filename_mex << " : The gateway routine used to call the Dynamic function "
1756 << "located in " << filename << endl
1757 << " *" << endl
1758 << " * Warning : this file is generated automatically by Dynare" << endl
1759 << " * from model file (.mod)" << endl
1760 << endl
1761 << " */" << endl
1762 << endl
1763 << "#include <stdlib.h>" << endl
1764 #ifndef __APPLE__
1765 << "#include <uchar.h>" << endl // For MATLAB ≤ R2011a
1766 #else
1767 << "typedef uint_least16_t char16_t;" << endl
1768 << "typedef uint_least32_t char32_t;" << endl // uchar.h does not exist on macOS
1769 #endif
1770 << R"(#include "mex.h")" << endl
1771 << endl
1772 << "void dynamic_resid_tt(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, double *T);" << endl
1773 << "void dynamic_resid(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, const double *T, double *residual);" << endl
1774 << "void dynamic_g1_tt(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, double *T);" << endl
1775 << "void dynamic_g1(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, const double *T, double *g1);" << endl
1776 << "void dynamic_g2_tt(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, double *T);" << endl
1777 << "void dynamic_g2(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, const double *T, double *v2);" << endl
1778 << "void dynamic_g3_tt(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, double *T);" << endl
1779 << "void dynamic_g3(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, const double *T, double *v3);" << endl
1780 << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl
1781 << "{" << endl
1782 << " /* Check that no derivatives of higher order than computed are being requested */" << endl
1783 << " if (nlhs > " << computed_derivs_order + 1 << ")" << endl
1784 << R"( mexErrMsgTxt("Derivatives of higher order than computed have been requested");)" << endl
1785 << " /* Create a pointer to the input matrix y. */" << endl
1786 << " double *y = mxGetPr(prhs[0]);" << endl
1787 << endl
1788 << " /* Create a pointer to the input matrix x. */" << endl
1789 << " double *x = mxGetPr(prhs[1]);" << endl
1790 << endl
1791 << " /* Create a pointer to the input matrix params. */" << endl
1792 << " double *params = mxGetPr(prhs[2]);" << endl
1793 << endl
1794 << " /* Create a pointer to the input matrix steady_state. */" << endl
1795 << " double *steady_state = mxGetPr(prhs[3]);" << endl
1796 << endl
1797 << " /* Fetch time index */" << endl
1798 << " int it_ = (int) mxGetScalar(prhs[4]) - 1;" << endl
1799 << endl
1800 << " /* Gets number of rows of matrix x. */" << endl
1801 << " int nb_row_x = mxGetM(prhs[1]);" << endl
1802 << endl
1803 << " double *T = (double *) malloc(sizeof(double)*" << ntt << ");"
1804 << endl
1805 << " if (nlhs >= 1)" << endl
1806 << " {" << endl
1807 << " /* Set the output pointer to the output matrix residual. */" << endl
1808 << " plhs[0] = mxCreateDoubleMatrix(" << equations.size() << ",1, mxREAL);" << endl
1809 << " double *residual = mxGetPr(plhs[0]);" << endl
1810 << " dynamic_resid_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
1811 << " dynamic_resid(y, x, nb_row_x, params, steady_state, it_, T, residual);" << endl
1812 << " }" << endl
1813 << endl
1814 << " if (nlhs >= 2)" << endl
1815 << " {" << endl
1816 << " /* Set the output pointer to the output matrix g1. */" << endl
1817 << " plhs[1] = mxCreateDoubleMatrix(" << equations.size() << ", " << dynJacobianColsNbr << ", mxREAL);" << endl
1818 << " double *g1 = mxGetPr(plhs[1]);" << endl
1819 << " dynamic_g1_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
1820 << " dynamic_g1(y, x, nb_row_x, params, steady_state, it_, T, g1);" << endl
1821 << " }" << endl
1822 << endl
1823 << " if (nlhs >= 3)" << endl
1824 << " {" << endl
1825 << " /* Set the output pointer to the output matrix v2. */" << endl
1826 << " plhs[2] = mxCreateDoubleMatrix(" << NNZDerivatives[2] << ", " << 3
1827 << ", mxREAL);" << endl
1828 << " double *v2 = mxGetPr(plhs[2]);" << endl
1829 << " dynamic_g2_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
1830 << " dynamic_g2(y, x, nb_row_x, params, steady_state, it_, T, v2);" << endl
1831 << " }" << endl
1832 << endl
1833 << " if (nlhs >= 4)" << endl
1834 << " {" << endl
1835 << " /* Set the output pointer to the output matrix v3. */" << endl
1836 << " plhs[3] = mxCreateDoubleMatrix(" << NNZDerivatives[3] << ", " << 3 << ", mxREAL);" << endl
1837 << " double *v3 = mxGetPr(plhs[3]);" << endl
1838 << " dynamic_g3_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
1839 << " dynamic_g3(y, x, nb_row_x, params, steady_state, it_, T, v3);" << endl
1840 << " }" << endl
1841 << endl
1842 << " free(T);"
1843 << "}" << endl;
1844 mDynamicMexFile.close();
1845 }
1846
1847 string
reform(const string & name1) const1848 DynamicModel::reform(const string &name1) const
1849 {
1850 string name = name1;
1851 int pos = name.find(R"(\)", 0);
1852 while (pos >= 0)
1853 {
1854 if (name.substr(pos + 1, 1) != R"(\)")
1855 {
1856 name = name.insert(pos, R"(\)");
1857 pos++;
1858 }
1859 pos++;
1860 pos = name.find(R"(\)", pos);
1861 }
1862 return name;
1863 }
1864
1865 void
printNonZeroHessianEquations(ostream & output) const1866 DynamicModel::printNonZeroHessianEquations(ostream &output) const
1867 {
1868 if (nonzero_hessian_eqs.size() != 1)
1869 output << "[";
1870 for (auto it = nonzero_hessian_eqs.begin();
1871 it != nonzero_hessian_eqs.end(); ++it)
1872 {
1873 if (it != nonzero_hessian_eqs.begin())
1874 output << " ";
1875 output << *it + 1;
1876 }
1877 if (nonzero_hessian_eqs.size() != 1)
1878 output << "]";
1879 }
1880
1881 void
Write_Inf_To_Bin_File_Block(const string & basename,int num,int & u_count_int,bool & file_open,bool is_two_boundaries,bool linear_decomposition) const1882 DynamicModel::Write_Inf_To_Bin_File_Block(const string &basename, int num,
1883 int &u_count_int, bool &file_open, bool is_two_boundaries, bool linear_decomposition) const
1884 {
1885 int j;
1886 std::ofstream SaveCode;
1887 string filename;
1888
1889 if (!linear_decomposition)
1890 filename = basename + "/model/bytecode/dynamic.bin";
1891 else
1892 filename = basename + "/model/bytecode/non_linear.bin";
1893
1894 if (file_open)
1895 SaveCode.open(filename, ios::out | ios::in | ios::binary | ios::ate);
1896 else
1897 SaveCode.open(filename, ios::out | ios::binary);
1898 if (!SaveCode.is_open())
1899 {
1900 cerr << R"(Error : Can't open file ")" << filename << R"(" for writing)" << endl;
1901 exit(EXIT_FAILURE);
1902 }
1903 u_count_int = 0;
1904 unsigned int block_size = getBlockSize(num);
1905 unsigned int block_mfs = getBlockMfs(num);
1906 unsigned int block_recursive = block_size - block_mfs;
1907 for (const auto &it : blocks_derivatives[num])
1908 {
1909 unsigned int eq, var;
1910 int lag;
1911 tie(eq, var, lag, ignore) = it;
1912 if (lag != 0 && !is_two_boundaries)
1913 continue;
1914 if (eq >= block_recursive && var >= block_recursive)
1915 {
1916 int v = eq - block_recursive;
1917 SaveCode.write(reinterpret_cast<char *>(&v), sizeof(v));
1918 int varr = var - block_recursive + lag * block_mfs;
1919 SaveCode.write(reinterpret_cast<char *>(&varr), sizeof(varr));
1920 SaveCode.write(reinterpret_cast<char *>(&lag), sizeof(lag));
1921 int u = u_count_int + block_mfs;
1922 SaveCode.write(reinterpret_cast<char *>(&u), sizeof(u));
1923 u_count_int++;
1924 }
1925 }
1926
1927 if (is_two_boundaries)
1928 u_count_int += block_mfs;
1929 for (j = block_recursive; j < static_cast<int>(block_size); j++)
1930 {
1931 unsigned int varr = getBlockVariableID(num, j);
1932 SaveCode.write(reinterpret_cast<char *>(&varr), sizeof(varr));
1933 }
1934 for (j = block_recursive; j < static_cast<int>(block_size); j++)
1935 {
1936 unsigned int eqr = getBlockEquationID(num, j);
1937 SaveCode.write(reinterpret_cast<char *>(&eqr), sizeof(eqr));
1938 }
1939 SaveCode.close();
1940 }
1941
1942 void
writeSparseDynamicMFile(const string & basename) const1943 DynamicModel::writeSparseDynamicMFile(const string &basename) const
1944 {
1945 string sp;
1946 ofstream mDynamicModelFile;
1947 ostringstream tmp, tmp1, tmp_eq;
1948 string filename = packageDir(basename) + "/dynamic.m";
1949 mDynamicModelFile.open(filename, ios::out | ios::binary);
1950 if (!mDynamicModelFile.is_open())
1951 {
1952 cerr << "Error: Can't open file " << filename << " for writing" << endl;
1953 exit(EXIT_FAILURE);
1954 }
1955 mDynamicModelFile << "%" << endl
1956 << "% " << filename << " : Computes dynamic model for Dynare" << endl
1957 << "%" << endl
1958 << "% Warning : this file is generated automatically by Dynare" << endl
1959 << "% from model file (.mod)" << endl << endl
1960 << "%/" << endl;
1961
1962 int Nb_SGE = 0;
1963 bool open_par = false;
1964
1965 mDynamicModelFile << "function [varargout] = dynamic(options_, M_, oo_, varargin)" << endl
1966 << " g2=[];g3=[];" << endl;
1967 //Temporary variables declaration
1968 bool OK = true;
1969 ostringstream tmp_output;
1970 for (auto temporary_term : temporary_terms)
1971 {
1972 if (OK)
1973 OK = false;
1974 else
1975 tmp_output << " ";
1976 // In the following, "Static" is used to avoid getting the "(it_)" subscripting
1977 temporary_term->writeOutput(tmp_output, ExprNodeOutputType::matlabStaticModelSparse, temporary_terms, {});
1978 }
1979 if (tmp_output.str().length() > 0)
1980 mDynamicModelFile << " global " << tmp_output.str() << ";" << endl;
1981
1982 mDynamicModelFile << " T_init=zeros(1,options_.periods+M_.maximum_lag+M_.maximum_lead);" << endl;
1983 tmp_output.str("");
1984 for (auto temporary_term : temporary_terms)
1985 {
1986 tmp_output << " ";
1987 // In the following, "Static" is used to avoid getting the "(it_)" subscripting
1988 temporary_term->writeOutput(tmp_output, ExprNodeOutputType::matlabStaticModelSparse, temporary_terms, {});
1989 tmp_output << "=T_init;" << endl;
1990 }
1991 if (tmp_output.str().length() > 0)
1992 mDynamicModelFile << tmp_output.str();
1993
1994 mDynamicModelFile << " y_kmin=M_.maximum_lag;" << endl
1995 << " y_kmax=M_.maximum_lead;" << endl
1996 << " y_size=M_.endo_nbr;" << endl
1997 << " if(length(varargin)>0)" << endl
1998 << " %it is a simple evaluation of the dynamic model for time _it" << endl
1999 << " y=varargin{1};" << endl
2000 << " x=varargin{2};" << endl
2001 << " params=varargin{3};" << endl
2002 << " steady_state=varargin{4};" << endl
2003 << " it_=varargin{5};" << endl
2004 << " dr=varargin{6};" << endl
2005 << " Per_u_=0;" << endl
2006 << " Per_y_=it_*y_size;" << endl
2007 << " ys=y(it_,:);" << endl;
2008 tmp.str("");
2009 tmp_eq.str("");
2010 unsigned int nb_blocks = getNbBlocks();
2011 unsigned int block = 0;
2012 for (int count_call = 1; block < nb_blocks; block++, count_call++)
2013 {
2014 unsigned int block_size = getBlockSize(block),
2015 block_mfs = getBlockMfs(block),
2016 block_recursive = block_size - block_mfs;
2017 BlockSimulationType simulation_type = getBlockSimulationType(block);
2018
2019 if (simulation_type == EVALUATE_FORWARD || simulation_type == EVALUATE_BACKWARD)
2020 {
2021 for (unsigned int ik = 0; ik < block_size; ik++)
2022 {
2023 tmp << " " << getBlockVariableID(block, ik)+1;
2024 tmp_eq << " " << getBlockEquationID(block, ik)+1;
2025 }
2026 }
2027 else
2028 {
2029 for (unsigned int ik = block_recursive; ik < block_size; ik++)
2030 {
2031 tmp << " " << getBlockVariableID(block, ik)+1;
2032 tmp_eq << " " << getBlockEquationID(block, ik)+1;
2033 }
2034 }
2035 mDynamicModelFile << " y_index_eq=[" << tmp_eq.str() << "];" << endl
2036 << " y_index=[" << tmp.str() << "];" << endl;
2037
2038 switch (simulation_type)
2039 {
2040 case EVALUATE_FORWARD:
2041 case EVALUATE_BACKWARD:
2042 mDynamicModelFile << " [y, dr(" << count_call << ").g1, dr(" << count_call << ").g2, dr(" << count_call << ").g3, dr(" << count_call << ").g1_x, dr(" << count_call << ").g1_xd, dr(" << count_call << ").g1_o]=" << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, 1, it_-1, 1);" << endl
2043 << " residual(y_index_eq)=ys(y_index)-y(it_, y_index);" << endl;
2044 break;
2045 case SOLVE_FORWARD_SIMPLE:
2046 case SOLVE_BACKWARD_SIMPLE:
2047 mDynamicModelFile << " [r, y, dr(" << count_call << ").g1, dr(" << count_call << ").g2, dr(" << count_call << ").g3, dr(" << count_call << ").g1_x, dr(" << count_call << ").g1_xd, dr(" << count_call << ").g1_o]=" << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, it_, 1);" << endl
2048 << " residual(y_index_eq)=r;" << endl;
2049 break;
2050 case SOLVE_FORWARD_COMPLETE:
2051 case SOLVE_BACKWARD_COMPLETE:
2052 mDynamicModelFile << " [r, y, dr(" << count_call << ").g1, dr(" << count_call << ").g2, dr(" << count_call << ").g3, dr(" << count_call << ").g1_x, dr(" << count_call << ").g1_xd, dr(" << count_call << ").g1_o]=" << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, it_, 1);" << endl
2053 << " residual(y_index_eq)=r;" << endl;
2054 break;
2055 case SOLVE_TWO_BOUNDARIES_COMPLETE:
2056 case SOLVE_TWO_BOUNDARIES_SIMPLE:
2057 mDynamicModelFile << " [r, y, dr(" << count_call << ").g1, dr(" << count_call << ").g2, dr(" << count_call << ").g3, b, dr(" << count_call << ").g1_x, dr(" << count_call << ").g1_xd, dr(" << count_call << ").g1_o]=" << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, it_-" << max_lag << ", 1, " << max_lag << ", " << block_recursive << "," << "options_.periods" << ");" << endl
2058 << " residual(y_index_eq)=r(:,M_.maximum_lag+1);" << endl;
2059 break;
2060 default:
2061 break;
2062 }
2063 tmp_eq.str("");
2064 tmp.str("");
2065 }
2066 if (tmp1.str().length())
2067 {
2068 mDynamicModelFile << tmp1.str();
2069 tmp1.str("");
2070 }
2071 mDynamicModelFile << " varargout{1}=residual;" << endl
2072 << " varargout{2}=dr;" << endl
2073 << " return;" << endl
2074 << " end;" << endl
2075 << " %it is the deterministic simulation of the block decomposed dynamic model" << endl
2076 << " if(options_.stack_solve_algo==0)" << endl
2077 << " mthd='Sparse LU';" << endl
2078 << " elseif(options_.stack_solve_algo==1)" << endl
2079 << " mthd='Relaxation';" << endl
2080 << " elseif(options_.stack_solve_algo==2)" << endl
2081 << " mthd='GMRES';" << endl
2082 << " elseif(options_.stack_solve_algo==3)" << endl
2083 << " mthd='BICGSTAB';" << endl
2084 << " elseif(options_.stack_solve_algo==4)" << endl
2085 << " mthd='OPTIMPATH';" << endl
2086 << " else" << endl
2087 << " mthd='UNKNOWN';" << endl
2088 << " end;" << endl
2089 << " if options_.verbosity" << endl
2090 << " printline(41)" << endl
2091 << " disp(sprintf('MODEL SIMULATION (method=%s):',mthd))" << endl
2092 << " skipline()" << endl
2093 << " end" << endl
2094 << " periods=options_.periods;" << endl
2095 << " maxit_=options_.simul.maxit;" << endl
2096 << " solve_tolf=options_.solve_tolf;" << endl
2097 << " y=oo_.endo_simul';" << endl
2098 << " x=oo_.exo_simul;" << endl
2099 << " params=M_.params;" << endl
2100 << " steady_state=oo_.steady_state;" << endl
2101 << " oo_.deterministic_simulation.status = 0;" << endl;
2102 for (block = 0; block < nb_blocks; block++)
2103 {
2104 unsigned int block_size = getBlockSize(block);
2105 unsigned int block_mfs = getBlockMfs(block);
2106 unsigned int block_recursive = block_size - block_mfs;
2107 BlockSimulationType simulation_type = getBlockSimulationType(block);
2108
2109 if (simulation_type == EVALUATE_FORWARD && block_size)
2110 {
2111 if (open_par)
2112 mDynamicModelFile << " end" << endl;
2113 mDynamicModelFile << " oo_.deterministic_simulation.status = 1;" << endl
2114 << " oo_.deterministic_simulation.error = 0;" << endl
2115 << " oo_.deterministic_simulation.iterations = 0;" << endl
2116 << " if(isfield(oo_.deterministic_simulation,'block'))" << endl
2117 << " blck_num = length(oo_.deterministic_simulation.block)+1;" << endl
2118 << " else" << endl
2119 << " blck_num = 1;" << endl
2120 << " end;" << endl
2121 << " oo_.deterministic_simulation.block(blck_num).status = 1;" << endl
2122 << " oo_.deterministic_simulation.block(blck_num).error = 0;" << endl
2123 << " oo_.deterministic_simulation.block(blck_num).iterations = 0;" << endl
2124 << " g1=[];g2=[];g3=[];" << endl
2125 << " y=" << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, 0, y_kmin, periods);" << endl
2126 << " tmp = y(:,M_.block_structure.block(" << block + 1 << ").variable);" << endl
2127 << " if any(isnan(tmp) | isinf(tmp))" << endl
2128 << " disp(['Inf or Nan value during the evaluation of block " << block <<"']);" << endl
2129 << " oo_.deterministic_simulation.status = 0;" << endl
2130 << " oo_.deterministic_simulation.error = 100;" << endl
2131 << " varargout{1} = oo_;" << endl
2132 << " return;" << endl
2133 << " end;" << endl;
2134 }
2135 else if (simulation_type == EVALUATE_BACKWARD && block_size)
2136 {
2137 if (open_par)
2138 mDynamicModelFile << " end" << endl;
2139 mDynamicModelFile << " oo_.deterministic_simulation.status = 1;" << endl
2140 << " oo_.deterministic_simulation.error = 0;" << endl
2141 << " oo_.deterministic_simulation.iterations = 0;" << endl
2142 << " if(isfield(oo_.deterministic_simulation,'block'))" << endl
2143 << " blck_num = length(oo_.deterministic_simulation.block)+1;" << endl
2144 << " else" << endl
2145 << " blck_num = 1;" << endl
2146 << " end;" << endl
2147 << " oo_.deterministic_simulation.block(blck_num).status = 1;" << endl
2148 << " oo_.deterministic_simulation.block(blck_num).error = 0;" << endl
2149 << " oo_.deterministic_simulation.block(blck_num).iterations = 0;" << endl
2150 << " g1=[];g2=[];g3=[];" << endl
2151 << " y = " << basename << ".block.dynamic_" << block + 1 << "(y, x, params, steady_state, 0, y_kmin, periods);" << endl
2152 << " tmp = y(:,M_.block_structure.block(" << block + 1 << ").variable);" << endl
2153 << " if any(isnan(tmp) | isinf(tmp))" << endl
2154 << " disp(['Inf or Nan value during the evaluation of block " << block <<"']);" << endl
2155 << " oo_.deterministic_simulation.status = 0;" << endl
2156 << " oo_.deterministic_simulation.error = 100;" << endl
2157 << " varargout{1} = oo_;" << endl
2158 << " return;" << endl
2159 << " end;" << endl;
2160 }
2161 else if ((simulation_type == SOLVE_FORWARD_COMPLETE || simulation_type == SOLVE_FORWARD_SIMPLE) && block_size)
2162 {
2163 if (open_par)
2164 mDynamicModelFile << " end" << endl;
2165 open_par = false;
2166 mDynamicModelFile << " g1=0;" << endl
2167 << " r=0;" << endl;
2168 tmp.str("");
2169 for (unsigned int ik = block_recursive; ik < block_size; ik++)
2170 tmp << " " << getBlockVariableID(block, ik)+1;
2171 mDynamicModelFile << " y_index = [" << tmp.str() << "];" << endl;
2172 int nze = blocks_derivatives[block].size();
2173 mDynamicModelFile << " if(isfield(oo_.deterministic_simulation,'block'))" << endl
2174 << " blck_num = length(oo_.deterministic_simulation.block)+1;" << endl
2175 << " else" << endl
2176 << " blck_num = 1;" << endl
2177 << " end;" << endl
2178 << " y = solve_one_boundary('" << basename << ".block.dynamic_" << block + 1 << "'"
2179 << ", y, x, params, steady_state, y_index, " << nze
2180 << ", options_.periods, " << blocks_linear[block]
2181 << ", blck_num, y_kmin, options_.simul.maxit, options_.solve_tolf, options_.slowc, " << cutoff << ", options_.stack_solve_algo, 1, 1, 0, M_, options_, oo_);" << endl
2182 << " tmp = y(:,M_.block_structure.block(" << block + 1 << ").variable);" << endl
2183 << " if any(isnan(tmp) | isinf(tmp))" << endl
2184 << " disp(['Inf or Nan value during the resolution of block " << block <<"']);" << endl
2185 << " oo_.deterministic_simulation.status = 0;" << endl
2186 << " oo_.deterministic_simulation.error = 100;" << endl
2187 << " varargout{1} = oo_;" << endl
2188 << " return;" << endl
2189 << " end;" << endl;
2190 }
2191 else if ((simulation_type == SOLVE_BACKWARD_COMPLETE || simulation_type == SOLVE_BACKWARD_SIMPLE) && block_size)
2192 {
2193 if (open_par)
2194 mDynamicModelFile << " end" << endl;
2195 open_par = false;
2196 mDynamicModelFile << " g1=0;" << endl
2197 << " r=0;" << endl;
2198 tmp.str("");
2199 for (unsigned int ik = block_recursive; ik < block_size; ik++)
2200 tmp << " " << getBlockVariableID(block, ik)+1;
2201 mDynamicModelFile << " y_index = [" << tmp.str() << "];" << endl;
2202 int nze = blocks_derivatives[block].size();
2203
2204 mDynamicModelFile << " if(isfield(oo_.deterministic_simulation,'block'))" << endl
2205 << " blck_num = length(oo_.deterministic_simulation.block)+1;" << endl
2206 << " else" << endl
2207 << " blck_num = 1;" << endl
2208 << " end;" << endl
2209 << " y = solve_one_boundary('" << basename << ".block.dynamic_" << block + 1 << "'"
2210 <<", y, x, params, steady_state, y_index, " << nze
2211 <<", options_.periods, " << blocks_linear[block]
2212 <<", blck_num, y_kmin, options_.simul.maxit, options_.solve_tolf, options_.slowc, " << cutoff << ", options_.stack_solve_algo, 1, 1, 0, M_, options_, oo_);" << endl
2213 << " tmp = y(:,M_.block_structure.block(" << block + 1 << ").variable);" << endl
2214 << " if any(isnan(tmp) | isinf(tmp))" << endl
2215 << " disp(['Inf or Nan value during the resolution of block " << block <<"']);" << endl
2216 << " oo_.deterministic_simulation.status = 0;" << endl
2217 << " oo_.deterministic_simulation.error = 100;" << endl
2218 << " varargout{1} = oo_;" << endl
2219 << " return;" << endl
2220 << " end;" << endl;
2221 }
2222 else if ((simulation_type == SOLVE_TWO_BOUNDARIES_COMPLETE || simulation_type == SOLVE_TWO_BOUNDARIES_SIMPLE) && block_size)
2223 {
2224 if (open_par)
2225 mDynamicModelFile << " end" << endl;
2226 open_par = false;
2227 Nb_SGE++;
2228 int nze = blocks_derivatives[block].size();
2229 mDynamicModelFile << " y_index=[";
2230 for (unsigned int ik = block_recursive; ik < block_size; ik++)
2231 mDynamicModelFile << " " << getBlockVariableID(block, ik)+1;
2232 mDynamicModelFile << " ];" << endl
2233 << " if(isfield(oo_.deterministic_simulation,'block'))" << endl
2234 << " blck_num = length(oo_.deterministic_simulation.block)+1;" << endl
2235 << " else" << endl
2236 << " blck_num = 1;" << endl
2237 << " end;" << endl
2238 << " [y oo_] = solve_two_boundaries('" << basename << ".block.dynamic_" << block + 1 << "'"
2239 <<", y, x, params, steady_state, y_index, " << nze
2240 <<", options_.periods, " << max_leadlag_block[block].first
2241 <<", " << max_leadlag_block[block].second
2242 <<", " << blocks_linear[block]
2243 <<", blck_num, y_kmin, options_.simul.maxit, options_.solve_tolf, options_.slowc, " << cutoff << ", options_.stack_solve_algo, options_, M_, oo_);" << endl
2244 << " tmp = y(:,M_.block_structure.block(" << block + 1 << ").variable);" << endl
2245 << " if any(isnan(tmp) | isinf(tmp))" << endl
2246 << " disp(['Inf or Nan value during the resolution of block " << block <<"']);" << endl
2247 << " oo_.deterministic_simulation.status = 0;" << endl
2248 << " oo_.deterministic_simulation.error = 100;" << endl
2249 << " varargout{1} = oo_;" << endl
2250 << " return;" << endl
2251 << " end;" << endl;
2252 }
2253 }
2254 if (open_par)
2255 mDynamicModelFile << " end;" << endl;
2256 open_par = false;
2257 mDynamicModelFile << " oo_.endo_simul = y';" << endl
2258 << " varargout{1} = oo_;" << endl
2259 << "return;" << endl
2260 << "end" << endl;
2261
2262 mDynamicModelFile.close();
2263
2264 writeModelEquationsOrdered_M(basename);
2265 }
2266
2267 void
writeWrapperFunctions(const string & basename,const string & ending) const2268 DynamicModel::writeWrapperFunctions(const string &basename, const string &ending) const
2269 {
2270 string name;
2271 if (ending == "g1")
2272 name = "dynamic_resid_g1";
2273 else if (ending == "g2")
2274 name = "dynamic_resid_g1_g2";
2275 else if (ending == "g3")
2276 name = "dynamic_resid_g1_g2_g3";
2277
2278 string filename = packageDir(basename) + "/" + name + ".m";
2279 ofstream output;
2280 output.open(filename, ios::out | ios::binary);
2281 if (!output.is_open())
2282 {
2283 cerr << "Error: Can't open file " << filename << " for writing" << endl;
2284 exit(EXIT_FAILURE);
2285 }
2286
2287 if (ending == "g1")
2288 output << "function [residual, g1] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl
2289 << "% function [residual, g1] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl;
2290 else if (ending == "g2")
2291 output << "function [residual, g1, g2] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl
2292 << "% function [residual, g1, g2] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl;
2293 else if (ending == "g3")
2294 output << "function [residual, g1, g2, g3] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl
2295 << "% function [residual, g1, g2, g3] = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl;
2296
2297 output << "%" << endl
2298 << "% Wrapper function automatically created by Dynare" << endl
2299 << "%" << endl
2300 << endl
2301 << " if T_flag" << endl
2302 << " T = " << basename << ".dynamic_" << ending << "_tt(T, y, x, params, steady_state, it_);" << endl
2303 << " end" << endl;
2304
2305 if (ending == "g1")
2306 output << " residual = " << basename << ".dynamic_resid(T, y, x, params, steady_state, it_, false);" << endl
2307 << " g1 = " << basename << ".dynamic_g1(T, y, x, params, steady_state, it_, false);" << endl;
2308 else if (ending == "g2")
2309 output << " [residual, g1] = " << basename << ".dynamic_resid_g1(T, y, x, params, steady_state, it_, false);" << endl
2310 << " g2 = " << basename << ".dynamic_g2(T, y, x, params, steady_state, it_, false);" << endl;
2311 else if (ending == "g3")
2312 output << " [residual, g1, g2] = " << basename << ".dynamic_resid_g1_g2(T, y, x, params, steady_state, it_, false);" << endl
2313 << " g3 = " << basename << ".dynamic_g3(T, y, x, params, steady_state, it_, false);" << endl;
2314
2315 output << endl << "end" << endl;
2316 output.close();
2317 }
2318
2319 void
writeDynamicModelHelper(const string & basename,const string & name,const string & retvalname,const string & name_tt,size_t ttlen,const string & previous_tt_name,const ostringstream & init_s,const ostringstream & end_s,const ostringstream & s,const ostringstream & s_tt) const2320 DynamicModel::writeDynamicModelHelper(const string &basename,
2321 const string &name, const string &retvalname,
2322 const string &name_tt, size_t ttlen,
2323 const string &previous_tt_name,
2324 const ostringstream &init_s,
2325 const ostringstream &end_s,
2326 const ostringstream &s, const ostringstream &s_tt) const
2327 {
2328 string filename = packageDir(basename) + "/" + name_tt + ".m";
2329 ofstream output;
2330 output.open(filename, ios::out | ios::binary);
2331 if (!output.is_open())
2332 {
2333 cerr << "Error: Can't open file " << filename << " for writing" << endl;
2334 exit(EXIT_FAILURE);
2335 }
2336
2337 output << "function T = " << name_tt << "(T, y, x, params, steady_state, it_)" << endl
2338 << "% function T = " << name_tt << "(T, y, x, params, steady_state, it_)" << endl
2339 << "%" << endl
2340 << "% File created by Dynare Preprocessor from .mod file" << endl
2341 << "%" << endl
2342 << "% Inputs:" << endl
2343 << "% T [#temp variables by 1] double vector of temporary terms to be filled by function" << endl
2344 << "% y [#dynamic variables by 1] double vector of endogenous variables in the order stored" << endl
2345 << "% in M_.lead_lag_incidence; see the Manual" << endl
2346 << "% x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in declaration order)" << endl
2347 << "% for all simulation periods" << endl
2348 << "% steady_state [M_.endo_nbr by 1] double vector of steady state values" << endl
2349 << "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
2350 << "% it_ scalar double time period for exogenous variables for which" << endl
2351 << "% to evaluate the model" << endl
2352 << "%" << endl
2353 << "% Output:" << endl
2354 << "% T [#temp variables by 1] double vector of temporary terms" << endl
2355 << "%" << endl << endl
2356 << "assert(length(T) >= " << ttlen << ");" << endl
2357 << endl;
2358
2359 if (!previous_tt_name.empty())
2360 output << "T = " << basename << "." << previous_tt_name << "(T, y, x, params, steady_state, it_);" << endl << endl;
2361
2362 output << s_tt.str() << endl
2363 << "end" << endl;
2364 output.close();
2365
2366 filename = packageDir(basename) + "/" + name + ".m";
2367 output.open(filename, ios::out | ios::binary);
2368 if (!output.is_open())
2369 {
2370 cerr << "Error: Can't open file " << filename << " for writing" << endl;
2371 exit(EXIT_FAILURE);
2372 }
2373
2374 output << "function " << retvalname << " = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl
2375 << "% function " << retvalname << " = " << name << "(T, y, x, params, steady_state, it_, T_flag)" << endl
2376 << "%" << endl
2377 << "% File created by Dynare Preprocessor from .mod file" << endl
2378 << "%" << endl
2379 << "% Inputs:" << endl
2380 << "% T [#temp variables by 1] double vector of temporary terms to be filled by function" << endl
2381 << "% y [#dynamic variables by 1] double vector of endogenous variables in the order stored" << endl
2382 << "% in M_.lead_lag_incidence; see the Manual" << endl
2383 << "% x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in declaration order)" << endl
2384 << "% for all simulation periods" << endl
2385 << "% steady_state [M_.endo_nbr by 1] double vector of steady state values" << endl
2386 << "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
2387 << "% it_ scalar double time period for exogenous variables for which" << endl
2388 << "% to evaluate the model" << endl
2389 << "% T_flag boolean boolean flag saying whether or not to calculate temporary terms" << endl
2390 << "%" << endl
2391 << "% Output:" << endl
2392 << "% " << retvalname << endl
2393 << "%" << endl << endl;
2394
2395 if (!name_tt.empty())
2396 output << "if T_flag" << endl
2397 << " T = " << basename << "." << name_tt << "(T, y, x, params, steady_state, it_);" << endl
2398 << "end" << endl;
2399
2400 output << init_s.str() << endl
2401 << s.str()
2402 << end_s.str() << endl
2403 << "end" << endl;
2404 output.close();
2405 }
2406
2407 void
writeDynamicMatlabCompatLayer(const string & basename) const2408 DynamicModel::writeDynamicMatlabCompatLayer(const string &basename) const
2409 {
2410 string filename = packageDir(basename) + "/dynamic.m";
2411 ofstream output;
2412 output.open(filename, ios::out | ios::binary);
2413 if (!output.is_open())
2414 {
2415 cerr << "Error: Can't open file " << filename << " for writing" << endl;
2416 exit(EXIT_FAILURE);
2417 }
2418 int ntt = temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size();
2419
2420 output << "function [residual, g1, g2, g3] = dynamic(y, x, params, steady_state, it_)" << endl
2421 << " T = NaN(" << ntt << ", 1);" << endl
2422 << " if nargout <= 1" << endl
2423 << " residual = " << basename << ".dynamic_resid(T, y, x, params, steady_state, it_, true);" << endl
2424 << " elseif nargout == 2" << endl
2425 << " [residual, g1] = " << basename << ".dynamic_resid_g1(T, y, x, params, steady_state, it_, true);" << endl
2426 << " elseif nargout == 3" << endl
2427 << " [residual, g1, g2] = " << basename << ".dynamic_resid_g1_g2(T, y, x, params, steady_state, it_, true);" << endl
2428 << " else" << endl
2429 << " [residual, g1, g2, g3] = " << basename << ".dynamic_resid_g1_g2_g3(T, y, x, params, steady_state, it_, true);" << endl
2430 << " end" << endl
2431 << "end" << endl;
2432
2433 output.close();
2434 }
2435
2436 void
writeDynamicModel(ostream & DynamicOutput,bool use_dll,bool julia) const2437 DynamicModel::writeDynamicModel(ostream &DynamicOutput, bool use_dll, bool julia) const
2438 {
2439 writeDynamicModel("", DynamicOutput, use_dll, julia);
2440 }
2441
2442 void
writeDynamicModel(const string & basename,bool use_dll,bool julia) const2443 DynamicModel::writeDynamicModel(const string &basename, bool use_dll, bool julia) const
2444 {
2445 ofstream DynamicOutput;
2446 writeDynamicModel(basename, DynamicOutput, use_dll, julia);
2447 }
2448
2449 void
writeDynamicModel(const string & basename,ostream & DynamicOutput,bool use_dll,bool julia) const2450 DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput, bool use_dll, bool julia) const
2451 {
2452 vector<ostringstream> d_output(derivatives.size()); // Derivatives output (at all orders, including 0=residual)
2453 vector<ostringstream> tt_output(derivatives.size()); // Temp terms output (at all orders)
2454
2455 ExprNodeOutputType output_type = (use_dll ? ExprNodeOutputType::CDynamicModel :
2456 julia ? ExprNodeOutputType::juliaDynamicModel : ExprNodeOutputType::matlabDynamicModel);
2457
2458 deriv_node_temp_terms_t tef_terms;
2459 temporary_terms_t temp_term_union;
2460
2461 writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs,
2462 tt_output[0], output_type, tef_terms);
2463
2464 writeTemporaryTerms(temporary_terms_derivatives[0],
2465 temp_term_union,
2466 temporary_terms_idxs,
2467 tt_output[0], output_type, tef_terms);
2468
2469 writeModelEquations(d_output[0], output_type, temp_term_union);
2470
2471 int nrows = equations.size();
2472 int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr;
2473
2474 // Writing Jacobian
2475 if (!derivatives[1].empty())
2476 {
2477 writeTemporaryTerms(temporary_terms_derivatives[1],
2478 temp_term_union,
2479 temporary_terms_idxs,
2480 tt_output[1], output_type, tef_terms);
2481
2482 for (const auto &first_derivative : derivatives[1])
2483 {
2484 auto [eq, var] = vectorToTuple<2>(first_derivative.first);
2485 expr_t d1 = first_derivative.second;
2486
2487 jacobianHelper(d_output[1], eq, getDynJacobianCol(var), output_type);
2488 d_output[1] << "=";
2489 d1->writeOutput(d_output[1], output_type,
2490 temp_term_union, temporary_terms_idxs, tef_terms);
2491 d_output[1] << ";" << endl;
2492 }
2493 }
2494
2495 // Write derivatives for order ≥ 2
2496 for (size_t i = 2; i < derivatives.size(); i++)
2497 if (!derivatives[i].empty())
2498 {
2499 writeTemporaryTerms(temporary_terms_derivatives[i],
2500 temp_term_union,
2501 temporary_terms_idxs,
2502 tt_output[i], output_type, tef_terms);
2503
2504 /* When creating the sparse matrix (in MATLAB or C mode), since storage
2505 is in column-major order, output the first column, then the second,
2506 then the third. This gives a significant performance boost in use_dll
2507 mode (at both compilation and runtime), because it facilitates memory
2508 accesses and expression reusage. */
2509 ostringstream col0_output, col1_output, col2_output;
2510
2511 int k = 0; // Current line index in the 3-column matrix
2512 for (const auto &[vidx, d] : derivatives[i])
2513 {
2514 int eq = vidx[0];
2515
2516 int col_idx = 0;
2517 for (size_t j = 1; j < vidx.size(); j++)
2518 {
2519 col_idx *= dynJacobianColsNbr;
2520 col_idx += getDynJacobianCol(vidx[j]);
2521 }
2522
2523 if (output_type == ExprNodeOutputType::juliaDynamicModel)
2524 {
2525 d_output[i] << " @inbounds " << "g" << i << "[" << eq + 1 << "," << col_idx + 1 << "] = ";
2526 d->writeOutput(d_output[i], output_type, temp_term_union, temporary_terms_idxs, tef_terms);
2527 d_output[i] << endl;
2528 }
2529 else
2530 {
2531 sparseHelper(i, col0_output, k, 0, output_type);
2532 col0_output << "=" << eq + 1 << ";" << endl;
2533
2534 sparseHelper(i, col1_output, k, 1, output_type);
2535 col1_output << "=" << col_idx + 1 << ";" << endl;
2536
2537 sparseHelper(i, col2_output, k, 2, output_type);
2538 col2_output << "=";
2539 d->writeOutput(col2_output, output_type, temp_term_union, temporary_terms_idxs, tef_terms);
2540 col2_output << ";" << endl;
2541
2542 k++;
2543 }
2544
2545 // Output symetric elements at order 2
2546 if (i == 2 && vidx[1] != vidx[2])
2547 {
2548 int col_idx_sym = getDynJacobianCol(vidx[2]) * dynJacobianColsNbr + getDynJacobianCol(vidx[1]);
2549
2550 if (output_type == ExprNodeOutputType::juliaDynamicModel)
2551 d_output[2] << " @inbounds g2[" << eq + 1 << "," << col_idx_sym + 1 << "] = "
2552 << "g2[" << eq + 1 << "," << col_idx + 1 << "]" << endl;
2553 else
2554 {
2555 sparseHelper(2, col0_output, k, 0, output_type);
2556 col0_output << "=" << eq + 1 << ";" << endl;
2557
2558 sparseHelper(2, col1_output, k, 1, output_type);
2559 col1_output << "=" << col_idx_sym + 1 << ";" << endl;
2560
2561 sparseHelper(2, col2_output, k, 2, output_type);
2562 col2_output << "=";
2563 sparseHelper(2, col2_output, k-1, 2, output_type);
2564 col2_output << ";" << endl;
2565
2566 k++;
2567 }
2568 }
2569 }
2570 if (output_type != ExprNodeOutputType::juliaDynamicModel)
2571 d_output[i] << col0_output.str() << col1_output.str() << col2_output.str();
2572 }
2573
2574 if (output_type == ExprNodeOutputType::matlabDynamicModel)
2575 {
2576 // Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
2577 map<string, string> tmp_paren_vars;
2578 bool message_printed = false;
2579 for (auto &it : tt_output)
2580 fixNestedParenthesis(it, tmp_paren_vars, message_printed);
2581 for (auto &it : d_output)
2582 fixNestedParenthesis(it, tmp_paren_vars, message_printed);
2583
2584 ostringstream init_output, end_output;
2585 init_output << "residual = zeros(" << nrows << ", 1);";
2586 writeDynamicModelHelper(basename, "dynamic_resid", "residual",
2587 "dynamic_resid_tt",
2588 temporary_terms_mlv.size() + temporary_terms_derivatives[0].size(),
2589 "", init_output, end_output,
2590 d_output[0], tt_output[0]);
2591
2592 init_output.str("");
2593 init_output << "g1 = zeros(" << nrows << ", " << dynJacobianColsNbr << ");";
2594 writeDynamicModelHelper(basename, "dynamic_g1", "g1",
2595 "dynamic_g1_tt",
2596 temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
2597 "dynamic_resid_tt",
2598 init_output, end_output,
2599 d_output[1], tt_output[1]);
2600 writeWrapperFunctions(basename, "g1");
2601
2602 // For order ≥ 2
2603 int ncols = dynJacobianColsNbr;
2604 int ntt = temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size();
2605 for (size_t i = 2; i < derivatives.size(); i++)
2606 {
2607 ncols *= dynJacobianColsNbr;
2608 ntt += temporary_terms_derivatives[i].size();
2609 string gname = "g" + to_string(i);
2610 string vname = "v" + to_string(i);
2611 string gprevname = "g" + to_string(i-1);
2612
2613 init_output.str("");
2614 end_output.str("");
2615 if (derivatives[i].size())
2616 {
2617 init_output << vname << " = zeros(" << NNZDerivatives[i] << ",3);";
2618 end_output << gname << " = sparse("
2619 << vname << "(:,1),"
2620 << vname << "(:,2),"
2621 << vname << "(:,3),"
2622 << nrows << "," << ncols << ");";
2623 }
2624 else
2625 init_output << gname << " = sparse([],[],[]," << nrows << "," << ncols << ");";
2626 writeDynamicModelHelper(basename, "dynamic_" + gname, gname,
2627 "dynamic_" + gname + "_tt",
2628 ntt,
2629 "dynamic_" + gprevname + "_tt",
2630 init_output, end_output,
2631 d_output[i], tt_output[i]);
2632 if (i <= 3)
2633 writeWrapperFunctions(basename, gname);
2634 }
2635
2636 writeDynamicMatlabCompatLayer(basename);
2637 }
2638 else if (output_type == ExprNodeOutputType::CDynamicModel)
2639 {
2640 for (size_t i = 0; i < d_output.size(); i++)
2641 {
2642 string funcname = i == 0 ? "resid" : "g" + to_string(i);
2643 string argname = i == 0 ? "residual" : i == 1 ? "g1" : "v" + to_string(i);
2644 DynamicOutput << "void dynamic_" << funcname << "_tt(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, double *T)" << endl
2645 << "{" << endl
2646 << tt_output[i].str()
2647 << "}" << endl
2648 << endl
2649 << "void dynamic_" << funcname << "(const double *y, const double *x, int nb_row_x, const double *params, const double *steady_state, int it_, const double *T, double *" << argname << ")" << endl
2650 << "{" << endl;
2651 if (i == 0)
2652 DynamicOutput << " double lhs, rhs;" << endl;
2653 DynamicOutput << d_output[i].str()
2654 << "}" << endl
2655 << endl;
2656 }
2657 }
2658 else
2659 {
2660 string filename = basename + "Dynamic.jl";
2661 ofstream output;
2662 output.open(filename, ios::out | ios::binary);
2663 if (!output.is_open())
2664 {
2665 cerr << "Error: Can't open file " << filename << " for writing" << endl;
2666 exit(EXIT_FAILURE);
2667 }
2668
2669 output << "module " << basename << "Dynamic" << endl
2670 << "#" << endl
2671 << "# NB: this file was automatically generated by Dynare" << endl
2672 << "# from " << basename << ".mod" << endl
2673 << "#" << endl
2674 << "using Utils" << endl << endl
2675 << "export tmp_nbr, dynamic!, dynamicResid!, dynamicG1!, dynamicG2!, dynamicG3!" << endl << endl
2676 << "#=" << endl
2677 << "# The comments below apply to all functions contained in this module #" << endl
2678 << " NB: The arguments contained on the first line of the function" << endl
2679 << " definition are those that are modified in place" << endl << endl
2680 << "## Exported Functions ##" << endl
2681 << " dynamic! : Wrapper function; computes residuals, Jacobian, Hessian," << endl
2682 << " and third derivatives depending on the arguments provided" << endl
2683 << " dynamicResid! : Computes the dynamic model residuals" << endl
2684 << " dynamicG1! : Computes the dynamic model Jacobian" << endl
2685 << " dynamicG2! : Computes the dynamic model Hessian" << endl
2686 << " dynamicG3! : Computes the dynamic model third derivatives" << endl << endl
2687 << "## Exported Variables ##" << endl
2688 << " tmp_nbr : Vector{Int}(4) respectively the number of temporary variables" << endl
2689 << " for the residuals, g1, g2 and g3." << endl << endl
2690 << "## Local Functions ##" << endl
2691 << " dynamicResidTT! : Computes the dynamic model temporary terms for the residuals" << endl
2692 << " dynamicG1TT! : Computes the dynamic model temporary terms for the Jacobian" << endl
2693 << " dynamicG2TT! : Computes the dynamic model temporary terms for the Hessian" << endl
2694 << " dynamicG3TT! : Computes the dynamic model temporary terms for the third derivatives" << endl << endl
2695 << "## Function Arguments ##" << endl
2696 << " T : Vector{Float64}(num_temp_terms), temporary terms" << endl
2697 << " y : Vector{Float64}(num_dynamic_vars), endogenous variables in the order stored model_.lead_lag_incidence; see the manual" << endl
2698 << " x : Matrix{Float64}(nperiods,model_.exo_nbr), exogenous variables (in declaration order) for all simulation periods" << endl
2699 << " params : Vector{Float64}(model_.param_nbr), parameter values in declaration order" << endl
2700 << " steady_state : Vector{Float64}(model_endo_nbr)" << endl
2701 << " it_ : Int, time period for exogenous variables for which to evaluate the model" << endl
2702 << " residual : Vector{Float64}(model_.eq_nbr), residuals of the dynamic model equations in order of declaration of the equations." << endl
2703 << " g1 : Matrix{Float64}(model_.eq_nbr, num_dynamic_vars), Jacobian matrix of the dynamic model equations" << endl
2704 << " The rows and columns respectively correspond to equations in order of declaration and variables in order" << endl
2705 << " stored in model_.lead_lag_incidence" << endl
2706 << " g2 : spzeros(model_.eq_nbr, (num_dynamic_vars)^2) Hessian matrix of the dynamic model equations" << endl
2707 << " The rows and columns respectively correspond to equations in order of declaration and variables in order" << endl
2708 << " stored in model_.lead_lag_incidence" << endl
2709 << " g3 : spzeros(model_.eq_nbr, (num_dynamic_vars)^3) Third order derivative matrix of the dynamic model equations;" << endl
2710 << " The rows and columns respectively correspond to equations in order of declaration and variables in order" << endl
2711 << " stored in model_.lead_lag_incidence" << endl << endl
2712 << "## Remarks ##" << endl
2713 << " [1] `num_dynamic_vars` is the number of non zero entries in the lead lag incidence matrix, `model_.lead_lag_incidence.`" << endl
2714 << " [2] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the dynamic model called. The number of temporary variables" << endl
2715 << " used for the different returned objects (residuals, jacobian, hessian or third order derivatives) is given by the elements in `tmp_nbr`" << endl
2716 << " exported vector. The first element is the number of temporaries used for the computation of the residuals, the second element is the" << endl
2717 << " number of temporaries used for the evaluation of the jacobian matrix, etc. If one calls the version of the dynamic model computing the" << endl
2718 << " residuals, the jacobian and hessian matrices, then `T` must have at least `sum(tmp_nbr[1:3])` elements." << endl
2719 << "=#" << endl << endl;
2720
2721 // Write the number of temporary terms
2722 output << "tmp_nbr = zeros(Int,4)" << endl
2723 << "tmp_nbr[1] = " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << "# Number of temporary terms for the residuals" << endl
2724 << "tmp_nbr[2] = " << temporary_terms_derivatives[1].size() << "# Number of temporary terms for g1 (jacobian)" << endl
2725 << "tmp_nbr[3] = " << temporary_terms_derivatives[2].size() << "# Number of temporary terms for g2 (hessian)" << endl
2726 << "tmp_nbr[4] = " << temporary_terms_derivatives[3].size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl;
2727
2728 // dynamicResidTT!
2729 output << "function dynamicResidTT!(T::Vector{Float64}," << endl
2730 << " y::Vector{Float64}, x::Matrix{Float64}, "
2731 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2732 << tt_output[0].str()
2733 << " return nothing" << endl
2734 << "end" << endl << endl;
2735
2736 // dynamic!
2737 output << "function dynamicResid!(T::Vector{Float64}, residual::Vector{Float64}," << endl
2738 << " y::Vector{Float64}, x::Matrix{Float64}, "
2739 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
2740 << " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << endl
2741 << " @assert length(residual) == " << nrows << endl
2742 << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
2743 << " @assert length(params) == " << symbol_table.param_nbr() << endl
2744 << " if T_flag" << endl
2745 << " dynamicResidTT!(T, y, x, params, steady_state, it_)" << endl
2746 << " end" << endl
2747 << d_output[0].str()
2748 << " return nothing" << endl
2749 << "end" << endl << endl;
2750
2751 // dynamicG1TT!
2752 output << "function dynamicG1TT!(T::Vector{Float64}," << endl
2753 << " y::Vector{Float64}, x::Matrix{Float64}, "
2754 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2755 << " dynamicResidTT!(T, y, x, params, steady_state, it_)" << endl
2756 << tt_output[1].str()
2757 << " return nothing" << endl
2758 << "end" << endl << endl;
2759
2760 // dynamicG1!
2761 output << "function dynamicG1!(T::Vector{Float64}, g1::Matrix{Float64}," << endl
2762 << " y::Vector{Float64}, x::Matrix{Float64}, "
2763 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
2764 << " @assert length(T) >= "
2765 << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() << endl
2766 << " @assert size(g1) == (" << nrows << ", " << dynJacobianColsNbr << ")" << endl
2767 << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
2768 << " @assert length(params) == " << symbol_table.param_nbr() << endl
2769 << " if T_flag" << endl
2770 << " dynamicG1TT!(T, y, x, params, steady_state, it_)" << endl
2771 << " end" << endl
2772 << " fill!(g1, 0.0)" << endl
2773 << d_output[1].str()
2774 << " return nothing" << endl
2775 << "end" << endl << endl;
2776
2777 // dynamicG2TT!
2778 output << "function dynamicG2TT!(T::Vector{Float64}," << endl
2779 << " y::Vector{Float64}, x::Matrix{Float64}, "
2780 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2781 << " dynamicG1TT!(T, y, x, params, steady_state, it_)" << endl
2782 << tt_output[2].str()
2783 << " return nothing" << endl
2784 << "end" << endl << endl;
2785
2786 // dynamicG2!
2787 output << "function dynamicG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl
2788 << " y::Vector{Float64}, x::Matrix{Float64}, "
2789 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
2790 << " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() << endl
2791 << " @assert size(g2) == (" << nrows << ", " << hessianColsNbr << ")" << endl
2792 << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
2793 << " @assert length(params) == " << symbol_table.param_nbr() << endl
2794 << " if T_flag" << endl
2795 << " dynamicG2TT!(T, y, x, params, steady_state, it_)" << endl
2796 << " end" << endl
2797 << " fill!(g2, 0.0)" << endl
2798 << d_output[2].str()
2799 << " return nothing" << endl
2800 << "end" << endl << endl;
2801
2802 // dynamicG3TT!
2803 output << "function dynamicG3TT!(T::Vector{Float64}," << endl
2804 << " y::Vector{Float64}, x::Matrix{Float64}, "
2805 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2806 << " dynamicG2TT!(T, y, x, params, steady_state, it_)" << endl
2807 << tt_output[3].str()
2808 << " return nothing" << endl
2809 << "end" << endl << endl;
2810
2811 // dynamicG3!
2812 int ncols = hessianColsNbr * dynJacobianColsNbr;
2813 output << "function dynamicG3!(T::Vector{Float64}, g3::Matrix{Float64}," << endl
2814 << " y::Vector{Float64}, x::Matrix{Float64}, "
2815 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
2816 << " @assert length(T) >= "
2817 << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size() << endl
2818 << " @assert size(g3) == (" << nrows << ", " << ncols << ")" << endl
2819 << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
2820 << " @assert length(params) == " << symbol_table.param_nbr() << endl
2821 << " if T_flag" << endl
2822 << " dynamicG3TT!(T, y, x, params, steady_state, it_)" << endl
2823 << " end" << endl
2824 << " fill!(g3, 0.0)" << endl
2825 << d_output[3].str()
2826 << " return nothing" << endl
2827 << "end" << endl << endl;
2828
2829 // dynamic!
2830 output << "function dynamic!(T::Vector{Float64}, residual::Vector{Float64}," << endl
2831 << " y::Vector{Float64}, x::Matrix{Float64}, "
2832 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2833 << " dynamicResid!(T, residual, y, x, params, steady_state, it_, true)" << endl
2834 << " return nothing" << endl
2835 << "end" << endl
2836 << endl
2837 << "function dynamic!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}," << endl
2838 << " y::Vector{Float64}, x::Matrix{Float64}, "
2839 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2840 << " dynamicG1!(T, g1, y, x, params, steady_state, it_, true)" << endl
2841 << " dynamicResid!(T, residual, y, x, params, steady_state, it_, false)" << endl
2842 << " return nothing" << endl
2843 << "end" << endl
2844 << endl
2845 << "function dynamic!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}," << endl
2846 << " y::Vector{Float64}, x::Matrix{Float64}, "
2847 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2848 << " dynamicG2!(T, g2, y, x, params, steady_state, it_, true)" << endl
2849 << " dynamicG1!(T, g1, y, x, params, steady_state, it_, false)" << endl
2850 << " dynamicResid!(T, residual, y, x, params, steady_state, it_, false)" << endl
2851 << " return nothing" << endl
2852 << "end" << endl
2853 << endl
2854 << "function dynamic!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}, g3::Matrix{Float64}," << endl
2855 << " y::Vector{Float64}, x::Matrix{Float64}, "
2856 << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int)" << endl
2857 << " dynamicG3!(T, g3, y, x, params, steady_state, it_, true)" << endl
2858 << " dynamicG2!(T, g2, y, x, params, steady_state, it_, false)" << endl
2859 << " dynamicG1!(T, g1, y, x, params, steady_state, it_, false)" << endl
2860 << " dynamicResid!(T, residual, y, x, params, steady_state, it_, false)" << endl
2861 << " return nothing" << endl
2862 << "end" << endl
2863 << "end" << endl;
2864 output.close();
2865 }
2866 }
2867
2868 void
writeDynamicJacobianNonZeroElts(const string & basename) const2869 DynamicModel::writeDynamicJacobianNonZeroElts(const string &basename) const
2870 {
2871 vector<pair<int, int>> nzij_pred, nzij_current, nzij_fwrd; // pairs (tsid, equation)
2872 for (const auto &[indices, d1] : derivatives[1])
2873 {
2874 if (symbol_table.getType(getSymbIDByDerivID(indices[1])) != SymbolType::endogenous)
2875 continue;
2876 int tsid = symbol_table.getTypeSpecificID(getSymbIDByDerivID(indices[1]));
2877 int lag = getLagByDerivID(indices[1]);
2878 if (lag == -1)
2879 nzij_pred.emplace_back(tsid, indices[0]);
2880 else if (lag == 0)
2881 nzij_current.emplace_back(tsid, indices[0]);
2882 else
2883 nzij_fwrd.emplace_back(tsid, indices[0]);
2884 }
2885 sort(nzij_pred.begin(), nzij_pred.end());
2886 sort(nzij_current.begin(), nzij_current.end());
2887 sort(nzij_fwrd.begin(), nzij_fwrd.end());
2888
2889 ofstream output{"+" + basename + "/dynamic_g1_nz.m", ios::out | ios::binary};
2890 output << "function [nzij_pred, nzij_current, nzij_fwrd] = dynamic_g1_nz()" << endl
2891 << "% Returns the coordinates of non-zero elements in the Jacobian, in column-major order, for each lead/lag (only for endogenous)" << endl;
2892 auto print_nzij = [&output](const vector<pair<int, int>> &nzij, const string &name) {
2893 output << " " << name << " = zeros(" << nzij.size() << ", 2, 'int32');" << endl;
2894 int idx = 1;
2895 for (const auto &it : nzij)
2896 {
2897 output << " " << name << "(" << idx << ",1)=" << it.second+1 << ';'
2898 << " " << name << "(" << idx << ",2)=" << it.first+1 << ';' << endl;
2899 idx++;
2900 }
2901 };
2902 print_nzij(nzij_pred, "nzij_pred");
2903 print_nzij(nzij_current, "nzij_current");
2904 print_nzij(nzij_fwrd, "nzij_fwrd");
2905 output << "end" << endl;
2906 output.close();
2907 }
2908
2909 void
parseIncludeExcludeEquations(const string & inc_exc_eq_tags,set<pair<string,string>> & eq_tag_set,bool exclude_eqs)2910 DynamicModel::parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> &eq_tag_set, bool exclude_eqs)
2911 {
2912 string tags;
2913 if (filesystem::exists(inc_exc_eq_tags))
2914 {
2915 ifstream exclude_file;
2916 exclude_file.open(inc_exc_eq_tags, ifstream::in);
2917 if (!exclude_file.is_open())
2918 {
2919 cerr << "ERROR: Could not open " << inc_exc_eq_tags << endl;
2920 exit(EXIT_FAILURE);
2921 }
2922
2923 string line;
2924 bool tagname_on_first_line = false;
2925 while (getline(exclude_file, line))
2926 {
2927 removeLeadingTrailingWhitespace(line);
2928 if (!line.empty())
2929 if (tags.empty() && line.find("=") != string::npos)
2930 {
2931 tagname_on_first_line = true;
2932 tags += line + "(";
2933 }
2934 else
2935 if (line.find("'") != string::npos)
2936 tags += line + ",";
2937 else
2938 tags += "'" + line + "',";
2939 }
2940
2941 if (!tags.empty())
2942 {
2943 tags = tags.substr(0, tags.size()-1);
2944 if (tagname_on_first_line)
2945 tags += ")";
2946 }
2947 }
2948 else
2949 tags = inc_exc_eq_tags;
2950 removeLeadingTrailingWhitespace(tags);
2951
2952 if (tags.front() == '[' && tags.back() != ']')
2953 {
2954 cerr << "Error: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
2955 << ": if the first character is '[' the last must be ']'" << endl;
2956 exit(EXIT_FAILURE);
2957 }
2958
2959 if (tags.front() == '[' && tags.back() == ']')
2960 tags = tags.substr(1, tags.length() - 2);
2961 removeLeadingTrailingWhitespace(tags);
2962
2963 regex q(R"(^\w+\s*=)");
2964 smatch matches;
2965 string tagname = "name";
2966 if (regex_search(tags, matches, q))
2967 {
2968 tagname = matches[0].str();
2969 tags = tags.substr(tagname.size(), tags.length() - tagname.size() + 1);
2970 removeLeadingTrailingWhitespace(tags);
2971 if (tags.front() == '(' && tags.back() == ')')
2972 {
2973 tags = tags.substr(1, tags.length() - 2);
2974 removeLeadingTrailingWhitespace(tags);
2975 }
2976 tagname = tagname.substr(0, tagname.size()-1);
2977 removeLeadingTrailingWhitespace(tagname);
2978 }
2979
2980 string quote_regex = "'[^']+'";
2981 string non_quote_regex = R"([^,\s]+)";
2982 regex r(R"((\s*)" + quote_regex + "|" + non_quote_regex + R"(\s*)(,\s*()" + quote_regex + "|" + non_quote_regex + R"()\s*)*)");
2983 if (!regex_match(tags, r))
2984 {
2985 cerr << "Error: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
2986 << ": argument is of incorrect format." << endl;
2987 exit(EXIT_FAILURE);
2988 }
2989
2990 regex s(quote_regex + "|" + non_quote_regex);
2991 for (auto it = sregex_iterator(tags.begin(), tags.end(), s);
2992 it != sregex_iterator(); ++it)
2993 {
2994 auto str = it->str();
2995 if (str[0] == '\'' && str[str.size()-1] == '\'')
2996 str = str.substr(1, str.size()-2);
2997 eq_tag_set.insert({tagname, str});
2998 }
2999 }
3000
3001 void
includeExcludeEquations(const string & eqs,bool exclude_eqs)3002 DynamicModel::includeExcludeEquations(const string &eqs, bool exclude_eqs)
3003 {
3004 if (eqs.empty())
3005 return;
3006
3007 set<pair<string, string>> eq_tag_set;
3008 parseIncludeExcludeEquations(eqs, eq_tag_set, exclude_eqs);
3009
3010 vector<int> excluded_vars
3011 = ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
3012 equations, equations_lineno,
3013 equation_tags, equation_tags_xref, false);
3014
3015 // `static_only_equation_tags` is `vector<vector<pair<string, string>>>`
3016 // while `equation_tags` is `vector<pair<int, pair<string, string>>>`
3017 // so convert former structure to latter to conform with function call
3018 int n = 0;
3019 vector<pair<int, pair<string, string>>> tmp_static_only_equation_tags;
3020 for (auto &eqn_tags : static_only_equations_equation_tags)
3021 {
3022 for (auto &eqn_tag : eqn_tags)
3023 tmp_static_only_equation_tags.emplace_back(make_pair(n, eqn_tag));
3024 n++;
3025 }
3026 // Ignore output because variables are not excluded when equations marked 'static' are excluded
3027 ModelTree::includeExcludeEquations(eq_tag_set, exclude_eqs,
3028 static_only_equations, static_only_equations_lineno,
3029 tmp_static_only_equation_tags,
3030 static_only_equation_tags_xref, true);
3031 if (!eq_tag_set.empty())
3032 {
3033 cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs") << ": The equations specified by `";
3034 cerr << eq_tag_set.begin()->first << "= ";
3035 for (auto &it : eq_tag_set)
3036 cerr << it.second << ", ";
3037 cerr << "` were not found." << endl;
3038 exit(EXIT_FAILURE);
3039 }
3040
3041 if (staticOnlyEquationsNbr() != dynamicOnlyEquationsNbr())
3042 {
3043 cerr << "ERROR: " << (exclude_eqs ? "exclude_eqs" : "include_eqs")
3044 << ": You must remove the same number of equations marked `static` as equations marked `dynamic`." << endl;
3045 exit(EXIT_FAILURE);
3046 }
3047
3048 // convert back static equation info
3049 if (static_only_equations.empty())
3050 static_only_equations_equation_tags.clear();
3051 else
3052 {
3053 static_only_equations_equation_tags.resize(static_only_equations.size());
3054 fill(static_only_equations_equation_tags.begin(), static_only_equations_equation_tags.end(), vector<pair<string, string>>());
3055 for (auto &it : tmp_static_only_equation_tags)
3056 static_only_equations_equation_tags.at(it.first).emplace_back(it.second);
3057 }
3058
3059 // Collect list of used variables in updated list of equations
3060 set<pair<int, int>> eqn_vars;
3061 for (const auto &eqn : equations)
3062 eqn->collectDynamicVariables(SymbolType::endogenous, eqn_vars);
3063 for (const auto &eqn : static_only_equations)
3064 eqn->collectDynamicVariables(SymbolType::endogenous, eqn_vars);
3065
3066 // Change LHS variable type of excluded equation if it is used in an eqution that has been kept
3067 for (auto ev : excluded_vars)
3068 {
3069 bool found = false;
3070 for (const auto &it : eqn_vars)
3071 if (it.first == ev)
3072 {
3073 symbol_table.changeType(ev, SymbolType::exogenous);
3074 found = true;
3075 break;
3076 }
3077 if (!found)
3078 symbol_table.changeType(ev, SymbolType::excludedVariable);
3079 }
3080 }
3081
3082 void
writeOutput(ostream & output,const string & basename,bool block_decomposition,bool linear_decomposition,bool byte_code,bool use_dll,bool estimation_present,bool compute_xrefs,bool julia) const3083 DynamicModel::writeOutput(ostream &output, const string &basename, bool block_decomposition, bool linear_decomposition, bool byte_code, bool use_dll, bool estimation_present, bool compute_xrefs, bool julia) const
3084 {
3085 /* Writing initialisation for M_.lead_lag_incidence matrix
3086 M_.lead_lag_incidence is a matrix with as many columns as there are
3087 endogenous variables and as many rows as there are periods in the
3088 models (nbr of rows = M_.max_lag+M_.max_lead+1)
3089
3090 The matrix elements are equal to zero if a variable isn't present in the
3091 model at a given period.
3092 */
3093
3094 string modstruct, outstruct;
3095 if (julia)
3096 {
3097 modstruct = "model_.";
3098 outstruct = "oo_.";
3099 }
3100 else
3101 {
3102 modstruct = "M_.";
3103 outstruct = "oo_.";
3104 }
3105
3106 output << modstruct << "orig_maximum_endo_lag = " << max_endo_lag_orig << ";" << endl
3107 << modstruct << "orig_maximum_endo_lead = " << max_endo_lead_orig << ";" << endl
3108 << modstruct << "orig_maximum_exo_lag = " << max_exo_lag_orig << ";" << endl
3109 << modstruct << "orig_maximum_exo_lead = " << max_exo_lead_orig << ";" << endl
3110 << modstruct << "orig_maximum_exo_det_lag = " << max_exo_det_lag_orig << ";" << endl
3111 << modstruct << "orig_maximum_exo_det_lead = " << max_exo_det_lead_orig << ";" << endl
3112 << modstruct << "orig_maximum_lag = " << max_lag_orig << ";" << endl
3113 << modstruct << "orig_maximum_lead = " << max_lead_orig << ";" << endl
3114 << modstruct << "orig_maximum_lag_with_diffs_expanded = " << max_lag_with_diffs_expanded_orig << ";" << endl
3115 << modstruct << "lead_lag_incidence = [";
3116 // Loop on endogenous variables
3117 int nstatic = 0,
3118 nfwrd = 0,
3119 npred = 0,
3120 nboth = 0;
3121 for (int endoID = 0; endoID < symbol_table.endo_nbr(); endoID++)
3122 {
3123 output << endl;
3124 int sstatic = 1,
3125 sfwrd = 0,
3126 spred = 0,
3127 sboth = 0;
3128 // Loop on periods
3129 for (int lag = -max_endo_lag; lag <= max_endo_lead; lag++)
3130 {
3131 // Print variableID if exists with current period, otherwise print 0
3132 try
3133 {
3134 int varID = getDerivID(symbol_table.getID(SymbolType::endogenous, endoID), lag);
3135 output << " " << getDynJacobianCol(varID) + 1;
3136 if (lag == -1)
3137 {
3138 sstatic = 0;
3139 spred = 1;
3140 }
3141 else if (lag == 1)
3142 {
3143 if (spred == 1)
3144 {
3145 sboth = 1;
3146 spred = 0;
3147 }
3148 else
3149 {
3150 sstatic = 0;
3151 sfwrd = 1;
3152 }
3153 }
3154 }
3155 catch (UnknownDerivIDException &e)
3156 {
3157 output << " 0";
3158 }
3159 }
3160 nstatic += sstatic;
3161 nfwrd += sfwrd;
3162 npred += spred;
3163 nboth += sboth;
3164 output << ";";
3165 }
3166 output << "]';" << endl;
3167 output << modstruct << "nstatic = " << nstatic << ";" << endl
3168 << modstruct << "nfwrd = " << nfwrd << ";" << endl
3169 << modstruct << "npred = " << npred << ";" << endl
3170 << modstruct << "nboth = " << nboth << ";" << endl
3171 << modstruct << "nsfwrd = " << nfwrd+nboth << ";" << endl
3172 << modstruct << "nspred = " << npred+nboth << ";" << endl
3173 << modstruct << "ndynamic = " << npred+nboth+nfwrd << ";" << endl;
3174 if (!julia)
3175 {
3176 output << modstruct << "dynamic_tmp_nbr = [";
3177 for (size_t i = 0; i < temporary_terms_derivatives.size(); i++)
3178 output << temporary_terms_derivatives[i].size() + (i == 0 ? temporary_terms_mlv.size() : 0) << "; ";
3179 output << "];" << endl;
3180
3181 /* Write mapping between model local variables and indices in the temporary
3182 terms vector (dynare#1722) */
3183 output << modstruct << "model_local_variables_dynamic_tt_idxs = {" << endl;
3184 for (auto [mlv, value] : temporary_terms_mlv)
3185 output << " '" << symbol_table.getName(mlv->symb_id) << "', "
3186 << temporary_terms_idxs.at(mlv)+1 << ';' << endl;
3187 output << "};" << endl;
3188 }
3189
3190 // Write equation tags
3191 if (julia)
3192 {
3193 output << modstruct << "equation_tags = [" << endl;
3194 for (const auto &equation_tag : equation_tags)
3195 output << " EquationTag("
3196 << equation_tag.first + 1 << R"( , ")"
3197 << equation_tag.second.first << R"(" , ")"
3198 << equation_tag.second.second << R"("))" << endl;
3199 output << " ]" << endl;
3200 }
3201 else
3202 {
3203 output << modstruct << "equations_tags = {" << endl;
3204 for (const auto &equation_tag : equation_tags)
3205 output << " " << equation_tag.first + 1 << " , '"
3206 << equation_tag.second.first << "' , '"
3207 << equation_tag.second.second << "' ;" << endl;
3208 output << "};" << endl;
3209 }
3210
3211 // Write mapping for variables and equations they are present in
3212 for (const auto &variable : variableMapping)
3213 {
3214 output << modstruct << "mapping." << symbol_table.getName(variable.first) << ".eqidx = [";
3215 for (auto equation : variable.second)
3216 output << equation + 1 << " ";
3217 output << "];" << endl;
3218 }
3219
3220 /* Say if static and dynamic models differ (because of [static] and [dynamic]
3221 equation tags) */
3222 output << modstruct << "static_and_dynamic_models_differ = "
3223 << (static_only_equations.size() > 0 ? "true" : "false")
3224 << ";" << endl;
3225
3226 // Say if model contains an external function call
3227 bool has_external_function = false;
3228 for (auto equation : equations)
3229 if (equation->containsExternalFunction())
3230 {
3231 has_external_function = true;
3232 break;
3233 }
3234 output << modstruct << "has_external_function = "
3235 << (has_external_function ? "true" : "false")
3236 << ';' << endl;
3237
3238 vector<int> state_var;
3239 for (int endoID = 0; endoID < symbol_table.endo_nbr(); endoID++)
3240 // Loop on periods
3241 for (int lag = -max_endo_lag; lag < 0; lag++)
3242 try
3243 {
3244 getDerivID(symbol_table.getID(SymbolType::endogenous, variable_reordered[endoID]), lag);
3245 if (lag < 0 && find(state_var.begin(), state_var.end(), variable_reordered[endoID]+1) == state_var.end())
3246 state_var.push_back(variable_reordered[endoID]+1);
3247 }
3248 catch (UnknownDerivIDException &e)
3249 {
3250 }
3251
3252 //In case of sparse model, writes the block_decomposition structure of the model
3253 if (block_decomposition || linear_decomposition)
3254 {
3255 vector<int> state_equ;
3256 int count_lead_lag_incidence = 0;
3257 int max_lead, max_lag, max_lag_endo, max_lead_endo, max_lag_exo, max_lead_exo, max_lag_exo_det, max_lead_exo_det;
3258 unsigned int nb_blocks = getNbBlocks();
3259 for (unsigned int block = 0; block < nb_blocks; block++)
3260 {
3261 //For a block composed of a single equation determines wether we have to evaluate or to solve the equation
3262 count_lead_lag_incidence = 0;
3263 BlockSimulationType simulation_type = getBlockSimulationType(block);
3264 int block_size = getBlockSize(block);
3265 max_lag = max_leadlag_block[block].first;
3266 max_lead = max_leadlag_block[block].second;
3267 max_lag_endo = endo_max_leadlag_block[block].first;
3268 max_lead_endo = endo_max_leadlag_block[block].second;
3269 max_lag_exo = exo_max_leadlag_block[block].first;
3270 max_lead_exo = exo_max_leadlag_block[block].second;
3271 max_lag_exo_det = exo_det_max_leadlag_block[block].first;
3272 max_lead_exo_det = exo_det_max_leadlag_block[block].second;
3273 ostringstream tmp_s, tmp_s_eq;
3274 tmp_s.str("");
3275 tmp_s_eq.str("");
3276 for (int i = 0; i < block_size; i++)
3277 {
3278 tmp_s << " " << getBlockVariableID(block, i)+1;
3279 tmp_s_eq << " " << getBlockEquationID(block, i)+1;
3280 }
3281 set<int> exogenous;
3282 for (const auto &it : exo_block[block])
3283 for (int it1 : it.second)
3284 exogenous.insert(it1);
3285 set<int> exogenous_det;
3286 for (const auto &it : exo_det_block[block])
3287 for (int it1 : it.second)
3288 exogenous_det.insert(it1);
3289 set<int> other_endogenous;
3290 for (const auto &it : other_endo_block[block])
3291 for (int it1 : it.second)
3292 other_endogenous.insert(it1);
3293 output << "block_structure.block(" << block+1 << ").Simulation_Type = " << simulation_type << ";" << endl
3294 << "block_structure.block(" << block+1 << ").maximum_lag = " << max_lag << ";" << endl
3295 << "block_structure.block(" << block+1 << ").maximum_lead = " << max_lead << ";" << endl
3296 << "block_structure.block(" << block+1 << ").maximum_endo_lag = " << max_lag_endo << ";" << endl
3297 << "block_structure.block(" << block+1 << ").maximum_endo_lead = " << max_lead_endo << ";" << endl
3298 << "block_structure.block(" << block+1 << ").maximum_exo_lag = " << max_lag_exo << ";" << endl
3299 << "block_structure.block(" << block+1 << ").maximum_exo_lead = " << max_lead_exo << ";" << endl
3300 << "block_structure.block(" << block+1 << ").maximum_exo_det_lag = " << max_lag_exo_det << ";" << endl
3301 << "block_structure.block(" << block+1 << ").maximum_exo_det_lead = " << max_lead_exo_det << ";" << endl
3302 << "block_structure.block(" << block+1 << ").endo_nbr = " << block_size << ";" << endl
3303 << "block_structure.block(" << block+1 << ").mfs = " << getBlockMfs(block) << ";" << endl
3304 << "block_structure.block(" << block+1 << ").equation = [" << tmp_s_eq.str() << "];" << endl
3305 << "block_structure.block(" << block+1 << ").variable = [" << tmp_s.str() << "];" << endl
3306 << "block_structure.block(" << block+1 << ").exo_nbr = " << getBlockExoSize(block) << ";" << endl
3307 << "block_structure.block(" << block+1 << ").exogenous = [";
3308 int i = 0;
3309 for (int exo : exogenous)
3310 if (exo >= 0)
3311 {
3312 output << " " << exo+1;
3313 i++;
3314 }
3315 output << "];" << endl
3316 << "block_structure.block(" << block+1 << ").exogenous_det = [";
3317 i = 0;
3318 for (int exo_det : exogenous_det)
3319 if (exo_det >= 0)
3320 {
3321 output << " " << exo_det+1;
3322 i++;
3323 }
3324 output << "];" << endl
3325 << "block_structure.block(" << block+1 << ").exo_det_nbr = " << i << ";" << endl
3326 << "block_structure.block(" << block+1 << ").other_endogenous = [";
3327 i = 0;
3328 for (int other_endo : other_endogenous)
3329 if (other_endo >= 0)
3330 {
3331 output << " " << other_endo+1;
3332 i++;
3333 }
3334 output << "];" << endl
3335 << "block_structure.block(" << block+1 << ").other_endogenous_block = [";
3336 i = 0;
3337 for (int other_endo : other_endogenous)
3338 if (other_endo >= 0)
3339 {
3340 bool OK = true;
3341 unsigned int j;
3342 for (j = 0; j < block && OK; j++)
3343 for (unsigned int k = 0; k < getBlockSize(j) && OK; k++)
3344 OK = other_endo != getBlockVariableID(j, k);
3345 if (!OK)
3346 output << " " << j;
3347 i++;
3348 }
3349 output << "];" << endl;
3350
3351 output << "block_structure.block(" << block+1 << ").tm1 = zeros(" << i << ", " << state_var.size() << ");" << endl;
3352 int count_other_endogenous = 1;
3353 for (int other_endo : other_endogenous)
3354 {
3355 for (auto it = state_var.begin(); it != state_var.end(); ++it)
3356 if (*it == other_endo + 1)
3357 output << "block_structure.block(" << block+1 << ").tm1("
3358 << count_other_endogenous << ", "
3359 << it - state_var.begin()+1 << ") = 1;" << endl;
3360 count_other_endogenous++;
3361 }
3362
3363 output << "block_structure.block(" << block+1 << ").other_endo_nbr = " << i << ";" << endl;
3364
3365 tmp_s.str("");
3366 count_lead_lag_incidence = 0;
3367 dynamic_jacob_map_t reordered_dynamic_jacobian;
3368 for (const auto &it : blocks_derivatives[block])
3369 reordered_dynamic_jacobian[{ get<2>(it), get<1>(it), get<0>(it) }] = get<3>(it);
3370 output << "block_structure.block(" << block+1 << ").lead_lag_incidence = [];" << endl;
3371 int last_var = -1;
3372 vector<int> local_state_var;
3373 vector<int> local_stat_var;
3374 int n_static = 0, n_backward = 0, n_forward = 0, n_mixed = 0;
3375 for (int lag = -1; lag < 1+1; lag++)
3376 {
3377 last_var = -1;
3378 for (const auto &it : reordered_dynamic_jacobian)
3379 {
3380 if (lag == get<0>(it.first) && last_var != get<1>(it.first))
3381 {
3382 if (lag == -1)
3383 {
3384 local_state_var.push_back(getBlockVariableID(block, get<1>(it.first))+1);
3385 n_backward++;
3386 }
3387 else if (lag == 0)
3388 {
3389 if (find(local_state_var.begin(), local_state_var.end(), getBlockVariableID(block, get<1>(it.first))+1) == local_state_var.end())
3390 {
3391 local_stat_var.push_back(getBlockVariableID(block, get<1>(it.first))+1);
3392 n_static++;
3393 }
3394 }
3395 else
3396 {
3397 if (find(local_state_var.begin(), local_state_var.end(), getBlockVariableID(block, get<1>(it.first))+1) != local_state_var.end())
3398 {
3399 n_backward--;
3400 n_mixed++;
3401 }
3402 else
3403 {
3404 if (find(local_stat_var.begin(), local_stat_var.end(), getBlockVariableID(block, get<1>(it.first))+1) != local_stat_var.end())
3405 n_static--;
3406 n_forward++;
3407 }
3408 }
3409 count_lead_lag_incidence++;
3410 for (int i = last_var; i < get<1>(it.first)-1; i++)
3411 tmp_s << " 0";
3412 if (tmp_s.str().length())
3413 tmp_s << " ";
3414 tmp_s << count_lead_lag_incidence;
3415 last_var = get<1>(it.first);
3416 }
3417 }
3418 for (int i = last_var + 1; i < block_size; i++)
3419 tmp_s << " 0";
3420 output << "block_structure.block(" << block+1 << ").lead_lag_incidence = [ block_structure.block(" << block+1 << ").lead_lag_incidence; " << tmp_s.str() << "]; %lag = " << lag << endl;
3421 tmp_s.str("");
3422 }
3423 vector<int> inter_state_var;
3424 for (int &it_l : local_state_var)
3425 for (auto it = state_var.begin(); it != state_var.end(); ++it)
3426 if (*it == it_l)
3427 inter_state_var.push_back(it - state_var.begin()+1);
3428 output << "block_structure.block(" << block+1 << ").sorted_col_dr_ghx = [";
3429 for (int it : inter_state_var)
3430 output << it << " ";
3431 output << "];" << endl;
3432 count_lead_lag_incidence = 0;
3433 output << "block_structure.block(" << block+1 << ").lead_lag_incidence_other = [];" << endl;
3434 for (int lag = -1; lag <= 1; lag++)
3435 {
3436 tmp_s.str("");
3437 for (int other_endo : other_endogenous)
3438 {
3439 bool done = false;
3440 for (int i = 0; i < block_size; i++)
3441 {
3442 unsigned int eq = getBlockEquationID(block, i);
3443 if (derivative_other_endo[block].find({ lag, eq, other_endo })
3444 != derivative_other_endo[block].end())
3445 {
3446 count_lead_lag_incidence++;
3447 tmp_s << " " << count_lead_lag_incidence;
3448 done = true;
3449 break;
3450 }
3451 }
3452 if (!done)
3453 tmp_s << " 0";
3454 }
3455 output << "block_structure.block(" << block+1 << ").lead_lag_incidence_other = [ block_structure.block(" << block+1 << ").lead_lag_incidence_other; " << tmp_s.str() << "]; %lag = " << lag << endl;
3456 }
3457 output << "block_structure.block(" << block+1 << ").n_static = " << n_static << ";" << endl
3458 << "block_structure.block(" << block+1 << ").n_forward = " << n_forward << ";" << endl
3459 << "block_structure.block(" << block+1 << ").n_backward = " << n_backward << ";" << endl
3460 << "block_structure.block(" << block+1 << ").n_mixed = " << n_mixed << ";" << endl;
3461 }
3462 output << modstruct << "block_structure.block = block_structure.block;" << endl;
3463 string cst_s;
3464 int nb_endo = symbol_table.endo_nbr();
3465 output << modstruct << "block_structure.variable_reordered = [";
3466 for (int i = 0; i < nb_endo; i++)
3467 output << " " << variable_reordered[i]+1;
3468 output << "];" << endl;
3469 output << modstruct << "block_structure.equation_reordered = [";
3470 for (int i = 0; i < nb_endo; i++)
3471 output << " " << equation_reordered[i]+1;
3472 output << "];" << endl;
3473 vector<int> variable_inv_reordered(nb_endo);
3474
3475 for (int i = 0; i < nb_endo; i++)
3476 variable_inv_reordered[variable_reordered[i]] = i;
3477
3478 for (int it : state_var)
3479 state_equ.push_back(equation_reordered[variable_inv_reordered[it - 1]]+1);
3480
3481 map<tuple<int, int, int>, int> lag_row_incidence;
3482 for (const auto & [indices, d1] : derivatives[1])
3483 {
3484 int deriv_id = indices[1];
3485 if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
3486 {
3487 int eq = indices[0];
3488 int symb = getSymbIDByDerivID(deriv_id);
3489 int var = symbol_table.getTypeSpecificID(symb);
3490 int lag = getLagByDerivID(deriv_id);
3491 lag_row_incidence[{ lag, eq, var }] = 1;
3492 }
3493 }
3494 int prev_lag = -1000000;
3495 for (const auto &it : lag_row_incidence)
3496 {
3497 if (prev_lag != get<0>(it.first))
3498 {
3499 if (prev_lag != -1000000)
3500 output << "];" << endl;
3501 prev_lag = get<0>(it.first);
3502 output << modstruct << "block_structure.incidence(" << max_endo_lag+get<0>(it.first)+1 << ").lead_lag = " << prev_lag << ";" << endl
3503 << modstruct << "block_structure.incidence(" << max_endo_lag+get<0>(it.first)+1 << ").sparse_IM = [";
3504 }
3505 output << get<1>(it.first)+1 << " " << get<2>(it.first)+1 << ";" << endl;
3506 }
3507 output << "];" << endl;
3508 if (estimation_present)
3509 {
3510 ofstream KF_index_file;
3511 filesystem::create_directories(basename + "/model/bytecode");
3512 string main_name = basename + "/model/bytecode/kfi";
3513 KF_index_file.open(main_name, ios::out | ios::binary | ios::ate);
3514 int n_obs = symbol_table.observedVariablesNbr();
3515 int n_state = state_var.size();
3516 for (int it : state_var)
3517 if (symbol_table.isObservedVariable(symbol_table.getID(SymbolType::endogenous, it-1)))
3518 n_obs--;
3519
3520 int n = n_obs + n_state;
3521 output << modstruct << "nobs_non_statevar = " << n_obs << ";" << endl;
3522 int nb_diag = 0;
3523
3524 vector<int> i_nz_state_var(n);
3525 for (int i = 0; i < n_obs; i++)
3526 i_nz_state_var[i] = n;
3527 unsigned int lp = n_obs;
3528
3529 for (unsigned int block = 0; block < nb_blocks; block++)
3530 {
3531 int block_size = getBlockSize(block);
3532 int nze = 0;
3533
3534 for (int i = 0; i < block_size; i++)
3535 {
3536 int var = getBlockVariableID(block, i);
3537 if (find(state_var.begin(), state_var.end(), var+1) != state_var.end())
3538 nze++;
3539 }
3540 if (block == 0)
3541 {
3542 set<pair<int, int>> row_state_var_incidence;
3543 for (const auto &it : blocks_derivatives[block])
3544 if (auto it_state_var = find(state_var.begin(), state_var.end(), getBlockVariableID(block, get<1>(it))+1);
3545 it_state_var != state_var.end())
3546 if (auto it_state_equ = find(state_equ.begin(), state_equ.end(), getBlockEquationID(block, get<0>(it))+1);
3547 it_state_equ != state_equ.end())
3548 row_state_var_incidence.emplace(it_state_equ - state_equ.begin(), it_state_var - state_var.begin());
3549 auto row_state_var_incidence_it = row_state_var_incidence.begin();
3550 bool diag = true;
3551 int nb_diag_r = 0;
3552 while (row_state_var_incidence_it != row_state_var_incidence.end() && diag)
3553 {
3554 diag = (row_state_var_incidence_it->first == row_state_var_incidence_it->second);
3555 if (diag)
3556 {
3557 int equ = row_state_var_incidence_it->first;
3558 row_state_var_incidence_it++;
3559 if (equ != row_state_var_incidence_it->first)
3560 nb_diag_r++;
3561 }
3562
3563 }
3564 set<pair<int, int>> col_state_var_incidence;
3565 for (const auto &it : row_state_var_incidence)
3566 col_state_var_incidence.emplace(it.second, it.first);
3567 auto col_state_var_incidence_it = col_state_var_incidence.begin();
3568 diag = true;
3569 int nb_diag_c = 0;
3570 while (col_state_var_incidence_it != col_state_var_incidence.end() && diag)
3571 {
3572 diag = (col_state_var_incidence_it->first == col_state_var_incidence_it->second);
3573 if (diag)
3574 {
3575 int var = col_state_var_incidence_it->first;
3576 col_state_var_incidence_it++;
3577 if (var != col_state_var_incidence_it->first)
3578 nb_diag_c++;
3579 }
3580 }
3581 nb_diag = min(nb_diag_r, nb_diag_c);
3582 row_state_var_incidence.clear();
3583 col_state_var_incidence.clear();
3584 }
3585 for (int i = 0; i < nze; i++)
3586 i_nz_state_var[lp + i] = lp + nze;
3587 lp += nze;
3588 }
3589 output << modstruct << "nz_state_var = [";
3590 for (unsigned int i = 0; i < lp; i++)
3591 output << i_nz_state_var[i] << " ";
3592 output << "];" << endl;
3593 output << modstruct << "n_diag = " << nb_diag << ";" << endl;
3594 KF_index_file.write(reinterpret_cast<char *>(&nb_diag), sizeof(nb_diag));
3595
3596 using index_KF = pair<int, pair<int, int >>;
3597 vector<index_KF> v_index_KF;
3598 for (int i = 0; i < n; i++)
3599 for (int j = n_obs; j < n; j++)
3600 {
3601 int j1 = j - n_obs;
3602 int j1_n_state = j1 * n_state - n_obs;
3603 if ((i < n_obs) || (i >= nb_diag + n_obs) || (j1 >= nb_diag))
3604 for (int k = n_obs; k < i_nz_state_var[i]; k++)
3605 v_index_KF.emplace_back(i + j1 * n, pair(i + k * n, k + j1_n_state));
3606 }
3607 int size_v_index_KF = v_index_KF.size();
3608
3609 KF_index_file.write(reinterpret_cast<char *>(&size_v_index_KF), sizeof(size_v_index_KF));
3610 for (auto &it : v_index_KF)
3611 KF_index_file.write(reinterpret_cast<char *>(&it), sizeof(index_KF));
3612
3613 vector<index_KF> v_index_KF_2;
3614 int n_n_obs = n * n_obs;
3615 for (int i = 0; i < n; i++)
3616 for (int j = i; j < n; j++)
3617 {
3618 if ((i < n_obs) || (i >= nb_diag + n_obs) || (j < n_obs) || (j >= nb_diag + n_obs))
3619 for (int k = n_obs; k < i_nz_state_var[j]; k++)
3620 {
3621 int k_n = k * n;
3622 v_index_KF_2.emplace_back(i * n + j, pair(i + k_n - n_n_obs, j + k_n));
3623 }
3624 }
3625 int size_v_index_KF_2 = v_index_KF_2.size();
3626
3627 KF_index_file.write(reinterpret_cast<char *>(&size_v_index_KF_2), sizeof(size_v_index_KF_2));
3628 for (auto &it : v_index_KF_2)
3629 KF_index_file.write(reinterpret_cast<char *>(&it), sizeof(index_KF));
3630 KF_index_file.close();
3631 }
3632 }
3633
3634 output << modstruct << "state_var = [";
3635 for (int it : state_var)
3636 output << it << (julia ? "," : " ");
3637 output << "];" << endl;
3638
3639 // Writing initialization for some other variables
3640 if (!julia)
3641 output << modstruct << "exo_names_orig_ord = [1:" << symbol_table.exo_nbr() << "];" << endl;
3642 else
3643 output << modstruct << "exo_names_orig_ord = collect(1:" << symbol_table.exo_nbr() << ");" << endl;
3644
3645 output << modstruct << "maximum_lag = " << max_lag << ";" << endl
3646 << modstruct << "maximum_lead = " << max_lead << ";" << endl;
3647
3648 output << modstruct << "maximum_endo_lag = " << max_endo_lag << ";" << endl
3649 << modstruct << "maximum_endo_lead = " << max_endo_lead << ";" << endl
3650 << outstruct << "steady_state = zeros(" << symbol_table.endo_nbr() << (julia ? ")" : ", 1);") << endl;
3651
3652 output << modstruct << "maximum_exo_lag = " << max_exo_lag << ";" << endl
3653 << modstruct << "maximum_exo_lead = " << max_exo_lead << ";" << endl
3654 << outstruct << "exo_steady_state = zeros(" << symbol_table.exo_nbr() << (julia ? ")" : ", 1);") << endl;
3655
3656 if (symbol_table.exo_det_nbr())
3657 {
3658 output << modstruct << "maximum_exo_det_lag = " << max_exo_det_lag << ";" << endl
3659 << modstruct << "maximum_exo_det_lead = " << max_exo_det_lead << ";" << endl
3660 << outstruct << "exo_det_steady_state = zeros(" << symbol_table.exo_det_nbr() << (julia ? ")" : ", 1);") << endl;
3661 }
3662
3663 output << modstruct << "params = " << (julia ? "fill(NaN, " : "NaN(")
3664 << symbol_table.param_nbr() << (julia ? ")" : ", 1);") << endl;
3665
3666 // FIXME: implement this for Julia
3667 if (!julia)
3668 {
3669 string empty_cell = "cell(" + to_string(symbol_table.endo_nbr()) + ", 1)";
3670 output << modstruct << "endo_trends = struct('deflator', " << empty_cell
3671 << ", 'log_deflator', " << empty_cell << ", 'growth_factor', " << empty_cell
3672 << ", 'log_growth_factor', " << empty_cell << ");" << endl;
3673 for (int i = 0; i < symbol_table.endo_nbr(); i++)
3674 {
3675 int symb_id = symbol_table.getID(SymbolType::endogenous, i);
3676 if (auto it = nonstationary_symbols_map.find(symb_id); it != nonstationary_symbols_map.end())
3677 {
3678 auto [is_log, deflator] = it->second;
3679 output << modstruct << "endo_trends(" << i << ")."
3680 << (is_log ? "log_deflator" : "deflator") << " = '";
3681 deflator->writeJsonOutput(output, {}, {});
3682 output << "';" << endl;
3683
3684 auto growth_factor = const_cast<DynamicModel *>(this)->AddDivide(deflator, deflator->decreaseLeadsLags(1))->removeTrendLeadLag(trend_symbols_map)->replaceTrendVar();
3685 output << modstruct << "endo_trends(" << i << ")."
3686 << (is_log ? "log_growth_factor" : "growth_factor") << " = '";
3687 growth_factor->writeJsonOutput(output, {}, {});
3688 output << "';" << endl;
3689 }
3690 }
3691 }
3692
3693 if (compute_xrefs)
3694 writeXrefs(output);
3695
3696 // Write number of non-zero derivatives
3697 // Use -1 if the derivatives have not been computed
3698 output << modstruct << (julia ? "nnzderivatives" : "NNZDerivatives") << " = [";
3699 for (int i = 1; i < static_cast<int>(NNZDerivatives.size()); i++)
3700 output << (i > computed_derivs_order ? -1 : NNZDerivatives[i]) << "; ";
3701 output << "];" << endl;
3702
3703 // Write Pac Model Consistent Expectation parameter info
3704 for (auto &it : pac_mce_alpha_symb_ids)
3705 {
3706 output << modstruct << "pac." << it.first.first << ".equations." << it.first.second << ".mce.alpha = [";
3707 for (auto it : it.second)
3708 output << symbol_table.getTypeSpecificID(it) + 1 << " ";
3709 output << "];" << endl;
3710 }
3711
3712 // Write Pac Model Consistent Expectation Z1 info
3713 for (auto &it : pac_mce_z1_symb_ids)
3714 output << modstruct << "pac." << it.first.first << ".equations." << it.first.second << ".mce.z1 = "
3715 << symbol_table.getTypeSpecificID(it.second) + 1 << ";" << endl;
3716
3717 // Write Pac lag info
3718 for (auto &it : pac_eqtag_and_lag)
3719 output << modstruct << "pac." << it.first.first << ".equations." << it.second.first << ".max_lag = " << it.second.second << ";" << endl;
3720
3721 // Write Pac equation tag info
3722 map<string, vector<pair<string, string>>> for_writing;
3723 for (auto &it : pac_eqtag_and_lag)
3724 for_writing[it.first.first].emplace_back(it.first.second, it.second.first);
3725
3726 for (auto &it : for_writing)
3727 {
3728 output << modstruct << "pac." << it.first << ".tag_map = [";
3729 for (auto &it1 : it.second)
3730 output << "{'" << it1.first << "', '" << it1.second << "'};";
3731 output << "];" << endl;
3732 }
3733
3734 for (auto &it : pac_model_info)
3735 {
3736 vector<int> lhs = get<0>(it.second);
3737 output << modstruct << "pac." << it.first << ".lhs = [";
3738 for (auto it : lhs)
3739 output << it + 1 << " ";
3740 output << "];" << endl;
3741
3742 if (int growth_param_index = get<1>(it.second);
3743 growth_param_index >= 0)
3744 output << modstruct << "pac." << it.first << ".growth_neutrality_param_index = "
3745 << symbol_table.getTypeSpecificID(growth_param_index) + 1 << ";" << endl;
3746
3747 output << modstruct << "pac." << it.first << ".auxiliary_model_type = '" << get<2>(it.second) << "';" << endl;
3748 }
3749
3750 for (auto &pit : pac_equation_info)
3751 {
3752 auto [lhs_pac_var, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants, optim_additive_vars_params_and_constants] = pit.second;
3753 string substruct = pit.first.first + ".equations." + pit.first.second + ".";
3754
3755 output << modstruct << "pac." << substruct << "lhs_var = "
3756 << symbol_table.getTypeSpecificID(lhs_pac_var.first) + 1 << ";" << endl;
3757
3758 if (optim_share_index >= 0)
3759 output << modstruct << "pac." << substruct << "share_of_optimizing_agents_index = "
3760 << symbol_table.getTypeSpecificID(optim_share_index) + 1 << ";" << endl;
3761
3762 output << modstruct << "pac." << substruct << "ec.params = "
3763 << symbol_table.getTypeSpecificID(ec_params_and_vars.first) + 1 << ";" << endl
3764 << modstruct << "pac." << substruct << "ec.vars = [";
3765 for (auto it : ec_params_and_vars.second)
3766 output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
3767 output << "];" << endl
3768 << modstruct << "pac." << substruct << "ec.istarget = [";
3769 for (auto it : ec_params_and_vars.second)
3770 output << (get<1>(it) ? "true " : "false ");
3771 output << "];" << endl
3772 << modstruct << "pac." << substruct << "ec.scale = [";
3773 for (auto it : ec_params_and_vars.second)
3774 output << get<2>(it) << " ";
3775 output << "];" << endl
3776 << modstruct << "pac." << substruct << "ec.isendo = [";
3777 for (auto it : ec_params_and_vars.second)
3778 switch (symbol_table.getType(get<0>(it)))
3779 {
3780 case SymbolType::endogenous:
3781 output << "true ";
3782 break;
3783 case SymbolType::exogenous:
3784 output << "false ";
3785 break;
3786 default:
3787 cerr << "expecting endogenous or exogenous" << endl;
3788 exit(EXIT_FAILURE);
3789 }
3790 output << "];" << endl
3791 << modstruct << "pac." << substruct << "ar.params = [";
3792 for (auto &it : ar_params_and_vars)
3793 output << symbol_table.getTypeSpecificID(it.first) + 1 << " ";
3794 output << "];" << endl
3795 << modstruct << "pac." << substruct << "ar.vars = [";
3796 for (auto &it : ar_params_and_vars)
3797 output << symbol_table.getTypeSpecificID(it.second.first) + 1 << " ";
3798 output << "];" << endl
3799 << modstruct << "pac." << substruct << "ar.lags = [";
3800 for (auto &it : ar_params_and_vars)
3801 output << it.second.second << " ";
3802 output << "];" << endl;
3803 if (!non_optim_vars_params_and_constants.empty())
3804 {
3805 output << modstruct << "pac." << substruct << "non_optimizing_behaviour.params = [";
3806 for (auto &it : non_optim_vars_params_and_constants)
3807 if (get<2>(it) >= 0)
3808 output << symbol_table.getTypeSpecificID(get<2>(it)) + 1 << " ";
3809 else
3810 output << "NaN ";
3811 output << "];" << endl
3812 << modstruct << "pac." << substruct << "non_optimizing_behaviour.vars = [";
3813 for (auto &it : non_optim_vars_params_and_constants)
3814 output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
3815 output << "];" << endl
3816 << modstruct << "pac." << substruct << "non_optimizing_behaviour.isendo = [";
3817 for (auto &it : non_optim_vars_params_and_constants)
3818 switch (symbol_table.getType(get<0>(it)))
3819 {
3820 case SymbolType::endogenous:
3821 output << "true ";
3822 break;
3823 case SymbolType::exogenous:
3824 output << "false ";
3825 break;
3826 default:
3827 cerr << "expecting endogenous or exogenous" << endl;
3828 exit(EXIT_FAILURE);
3829 }
3830 output << "];" << endl
3831 << modstruct << "pac." << substruct << "non_optimizing_behaviour.lags = [";
3832 for (auto &it : non_optim_vars_params_and_constants)
3833 output << get<1>(it) << " ";
3834 output << "];" << endl
3835 << modstruct << "pac." << substruct << "non_optimizing_behaviour.scaling_factor = [";
3836 for (auto &it : non_optim_vars_params_and_constants)
3837 output << get<3>(it) << " ";
3838 output << "];" << endl;
3839 }
3840 if (!additive_vars_params_and_constants.empty())
3841 {
3842 output << modstruct << "pac." << substruct << "additive.params = [";
3843 for (auto &it : additive_vars_params_and_constants)
3844 if (get<2>(it) >= 0)
3845 output << symbol_table.getTypeSpecificID(get<2>(it)) + 1 << " ";
3846 else
3847 output << "NaN ";
3848 output << "];" << endl
3849 << modstruct << "pac." << substruct << "additive.vars = [";
3850 for (auto &it : additive_vars_params_and_constants)
3851 output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
3852 output << "];" << endl
3853 << modstruct << "pac." << substruct << "additive.isendo = [";
3854 for (auto &it : additive_vars_params_and_constants)
3855 switch (symbol_table.getType(get<0>(it)))
3856 {
3857 case SymbolType::endogenous:
3858 output << "true ";
3859 break;
3860 case SymbolType::exogenous:
3861 output << "false ";
3862 break;
3863 default:
3864 cerr << "expecting endogenous or exogenous" << endl;
3865 exit(EXIT_FAILURE);
3866 }
3867 output << "];" << endl
3868 << modstruct << "pac." << substruct << "additive.lags = [";
3869 for (auto &it : additive_vars_params_and_constants)
3870 output << get<1>(it) << " ";
3871 output << "];" << endl
3872 << modstruct << "pac." << substruct << "additive.scaling_factor = [";
3873 for (auto &it : additive_vars_params_and_constants)
3874 output << get<3>(it) << " ";
3875 output << "];" << endl;
3876 }
3877 if (!optim_additive_vars_params_and_constants.empty())
3878 {
3879 output << modstruct << "pac." << substruct << "optim_additive.params = [";
3880 for (auto &it : optim_additive_vars_params_and_constants)
3881 if (get<2>(it) >= 0)
3882 output << symbol_table.getTypeSpecificID(get<2>(it)) + 1 << " ";
3883 else
3884 output << "NaN ";
3885 output << "];" << endl
3886 << modstruct << "pac." << substruct << "optim_additive.vars = [";
3887 for (auto &it : optim_additive_vars_params_and_constants)
3888 output << symbol_table.getTypeSpecificID(get<0>(it)) + 1 << " ";
3889 output << "];" << endl
3890 << modstruct << "pac." << substruct << "optim_additive.isendo = [";
3891 for (auto &it : optim_additive_vars_params_and_constants)
3892 switch (symbol_table.getType(get<0>(it)))
3893 {
3894 case SymbolType::endogenous:
3895 output << "true ";
3896 break;
3897 case SymbolType::exogenous:
3898 output << "false ";
3899 break;
3900 default:
3901 cerr << "expecting endogenous or exogenous" << endl;
3902 exit(EXIT_FAILURE);
3903 }
3904 output << "];" << endl
3905 << modstruct << "pac." << substruct << "optim_additive.lags = [";
3906 for (auto &it : optim_additive_vars_params_and_constants)
3907 output << get<1>(it) << " ";
3908 output << "];" << endl
3909 << modstruct << "pac." << substruct << "optim_additive.scaling_factor = [";
3910 for (auto &it : optim_additive_vars_params_and_constants)
3911 output << get<3>(it) << " ";
3912 output << "];" << endl;
3913 }
3914 // Create empty h0 and h1 substructures that will be overwritten later if not empty
3915 output << modstruct << "pac." << substruct << "h0_param_indices = [];" << endl
3916 << modstruct << "pac." << substruct << "h1_param_indices = [];" << endl;
3917 }
3918
3919 for (auto &it : pac_h0_indices)
3920 {
3921 output << modstruct << "pac." << it.first.first << ".equations." << it.first.second << ".h0_param_indices = [";
3922 for (auto it1 : it.second)
3923 output << symbol_table.getTypeSpecificID(it1) + 1 << " ";
3924 output << "];" << endl;
3925 }
3926
3927 for (auto &it : pac_h1_indices)
3928 {
3929 output << modstruct << "pac." << it.first.first << ".equations." << it.first.second << ".h1_param_indices = [";
3930 for (auto it1 : it.second)
3931 output << symbol_table.getTypeSpecificID(it1) + 1 << " ";
3932 output << "];" << endl;
3933 }
3934 }
3935
3936 map<tuple<int, int, int>, expr_t>
collect_first_order_derivatives_endogenous()3937 DynamicModel::collect_first_order_derivatives_endogenous()
3938 {
3939 map<tuple<int, int, int>, expr_t> endo_derivatives;
3940 for (auto & [indices, d1] : derivatives[1])
3941 if (getTypeByDerivID(indices[1]) == SymbolType::endogenous)
3942 {
3943 int eq = indices[0];
3944 int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(indices[1]));
3945 int lag = getLagByDerivID(indices[1]);
3946 endo_derivatives[{ eq, var, lag }] = d1;
3947 }
3948 return endo_derivatives;
3949 }
3950
3951 void
runTrendTest(const eval_context_t & eval_context)3952 DynamicModel::runTrendTest(const eval_context_t &eval_context)
3953 {
3954 computeDerivIDs();
3955 testTrendDerivativesEqualToZero(eval_context);
3956 }
3957
3958 void
updateVarAndTrendModel() const3959 DynamicModel::updateVarAndTrendModel() const
3960 {
3961 for (int i = 0; i < 2; i++)
3962 {
3963 map<string, vector<int>> eqnums, trend_eqnums;
3964 if (i == 0)
3965 eqnums = var_model_table.getEqNums();
3966 else if (i == 1)
3967 {
3968 eqnums = trend_component_model_table.getEqNums();
3969 trend_eqnums = trend_component_model_table.getTargetEqNums();
3970 }
3971
3972 map<string, vector<int>> trend_varr;
3973 map<string, vector<set<pair<int, int>>>> rhsr;
3974 for (const auto &it : eqnums)
3975 {
3976 vector<int> lhs, trend_var, trend_lhs;
3977 vector<set<pair<int, int>>> rhs;
3978
3979 if (i == 1)
3980 {
3981 lhs = trend_component_model_table.getLhs(it.first);
3982 for (auto teqn : trend_eqnums.at(it.first))
3983 {
3984 int eqnidx = 0;
3985 for (auto eqn : it.second)
3986 {
3987 if (eqn == teqn)
3988 trend_lhs.push_back(lhs[eqnidx]);
3989 eqnidx++;
3990 }
3991 }
3992 }
3993
3994 int lhs_idx = 0;
3995 for (auto eqn : it.second)
3996 {
3997 set<pair<int, int>> rhs_set;
3998 equations[eqn]->arg2->collectDynamicVariables(SymbolType::endogenous, rhs_set);
3999 rhs.push_back(rhs_set);
4000
4001 if (i == 1)
4002 {
4003 int lhs_symb_id = lhs[lhs_idx++];
4004 if (symbol_table.isAuxiliaryVariable(lhs_symb_id))
4005 try
4006 {
4007 lhs_symb_id = symbol_table.getOrigSymbIdForAuxVar(lhs_symb_id);
4008 }
4009 catch (...)
4010 {
4011 }
4012 int trend_var_symb_id = equations[eqn]->arg2->findTargetVariable(lhs_symb_id);
4013 if (trend_var_symb_id >= 0)
4014 {
4015 if (symbol_table.isAuxiliaryVariable(trend_var_symb_id))
4016 try
4017 {
4018 trend_var_symb_id = symbol_table.getOrigSymbIdForAuxVar(trend_var_symb_id);
4019 }
4020 catch (...)
4021 {
4022 }
4023 if (find(trend_lhs.begin(), trend_lhs.end(), trend_var_symb_id) == trend_lhs.end())
4024 {
4025 cerr << "ERROR: trend found in trend_component equation #" << eqn << " ("
4026 << symbol_table.getName(trend_var_symb_id) << ") does not correspond to a trend equation" << endl;
4027 exit(EXIT_FAILURE);
4028 }
4029 }
4030 trend_var.push_back(trend_var_symb_id);
4031 }
4032 }
4033
4034 rhsr[it.first] = rhs;
4035 if (i == 1)
4036 trend_varr[it.first] = trend_var;
4037 }
4038
4039 if (i == 0)
4040 var_model_table.setRhs(rhsr);
4041 else if (i == 1)
4042 {
4043 trend_component_model_table.setRhs(rhsr);
4044 trend_component_model_table.setTargetVar(trend_varr);
4045 }
4046 }
4047 }
4048
4049 void
fillVarModelTable() const4050 DynamicModel::fillVarModelTable() const
4051 {
4052 map<string, vector<int>> eqnums, lhsr;
4053 map<string, vector<expr_t>> lhs_expr_tr;
4054 map<string, vector<set<pair<int, int>>>> rhsr;
4055 map<string, vector<string>> eqtags = var_model_table.getEqTags();
4056
4057 for (const auto &it : eqtags)
4058 {
4059 vector<int> eqnumber, lhs;
4060 vector<expr_t> lhs_expr_t;
4061 vector<set<pair<int, int>>> rhs;
4062
4063 for (const auto &eqtag : it.second)
4064 {
4065 int eqn = -1;
4066 set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
4067 for (const auto &equation_tag : equation_tags)
4068 if (equation_tag.second.first == "name"
4069 && equation_tag.second.second == eqtag)
4070 {
4071 eqn = equation_tag.first;
4072 break;
4073 }
4074
4075 if (eqn == -1)
4076 {
4077 cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
4078 exit(EXIT_FAILURE);
4079 }
4080
4081 equations[eqn]->arg1->collectDynamicVariables(SymbolType::endogenous, lhs_set);
4082 equations[eqn]->arg1->collectDynamicVariables(SymbolType::exogenous, lhs_tmp_set);
4083 equations[eqn]->arg1->collectDynamicVariables(SymbolType::parameter, lhs_tmp_set);
4084
4085 if (lhs_set.size() != 1 || !lhs_tmp_set.empty())
4086 {
4087 cerr << "ERROR: in Equation " << eqtag
4088 << ". A VAR may only have one endogenous variable on the LHS. " << endl;
4089 exit(EXIT_FAILURE);
4090 }
4091
4092 auto itlhs = lhs_set.begin();
4093 if (itlhs->second != 0)
4094 {
4095 cerr << "ERROR: in Equation " << eqtag
4096 << ". The variable on the LHS of a VAR may not appear with a lead or a lag. "
4097 << endl;
4098 exit(EXIT_FAILURE);
4099 }
4100
4101 eqnumber.push_back(eqn);
4102 lhs.push_back(itlhs->first);
4103 lhs_set.clear();
4104 set<expr_t> lhs_expr_t_set;
4105 equations[eqn]->arg1->collectVARLHSVariable(lhs_expr_t_set);
4106 lhs_expr_t.push_back(*(lhs_expr_t_set.begin()));
4107
4108 equations[eqn]->arg2->collectDynamicVariables(SymbolType::endogenous, rhs_set);
4109 for (const auto &itrhs : rhs_set)
4110 if (itrhs.second > 0)
4111 {
4112 cerr << "ERROR: in Equation " << eqtag
4113 << ". A VAR may not have leaded or contemporaneous variables on the RHS. " << endl;
4114 exit(EXIT_FAILURE);
4115 }
4116 rhs.push_back(rhs_set);
4117 }
4118 eqnums[it.first] = eqnumber;
4119 lhsr[it.first] = lhs;
4120 lhs_expr_tr[it.first] = lhs_expr_t;
4121 rhsr[it.first] = rhs;
4122 }
4123 var_model_table.setEqNums(eqnums);
4124 var_model_table.setLhs(lhsr);
4125 var_model_table.setRhs(rhsr);
4126 var_model_table.setLhsExprT(lhs_expr_tr);
4127
4128 // Fill AR Matrix
4129 var_model_table.setAR(fillAutoregressiveMatrix(true));
4130 }
4131
4132 void
fillVarModelTableFromOrigModel() const4133 DynamicModel::fillVarModelTableFromOrigModel() const
4134 {
4135 map<string, vector<int>> lags, orig_diff_var;
4136 map<string, vector<bool>> diff;
4137 for (const auto &it : var_model_table.getEqNums())
4138 {
4139 set<expr_t> lhs;
4140 vector<int> orig_diff_var_vec;
4141 vector<bool> diff_vec;
4142 for (auto eqn : it.second)
4143 {
4144 // ensure no leads in equations
4145 if (equations[eqn]->arg2->VarMinLag() <= 0)
4146 {
4147 cerr << "ERROR in VAR model Equation (#" << eqn << "). "
4148 << "Leaded exogenous variables "
4149 << "and leaded or contemporaneous endogenous variables not allowed in VAR"
4150 << endl;
4151 exit(EXIT_FAILURE);
4152 }
4153
4154 // save lhs variables
4155 equations[eqn]->arg1->collectVARLHSVariable(lhs);
4156
4157 equations[eqn]->arg1->countDiffs() > 0 ?
4158 diff_vec.push_back(true) : diff_vec.push_back(false);
4159 if (diff_vec.back())
4160 {
4161 set<pair<int, int>> diff_set;
4162 equations[eqn]->arg1->collectDynamicVariables(SymbolType::endogenous, diff_set);
4163
4164 if (diff_set.size() != 1)
4165 {
4166 cerr << "ERROR: problem getting variable for LHS diff operator in equation "
4167 << eqn << endl;
4168 exit(EXIT_FAILURE);
4169 }
4170 orig_diff_var_vec.push_back(diff_set.begin()->first);
4171 }
4172 else
4173 orig_diff_var_vec.push_back(-1);
4174
4175 }
4176
4177 if (it.second.size() != lhs.size())
4178 {
4179 cerr << "ERROR: The LHS variables of the VAR model are not unique" << endl;
4180 exit(EXIT_FAILURE);
4181 }
4182
4183 set<expr_t> lhs_lag_equiv;
4184 for (const auto &lh : lhs)
4185 {
4186 auto [lag_equiv_repr, index] = lh->getLagEquivalenceClass();
4187 lhs_lag_equiv.insert(lag_equiv_repr);
4188 }
4189
4190 vector<int> max_lag;
4191 for (auto eqn : it.second)
4192 max_lag.push_back(equations[eqn]->arg2->VarMaxLag(lhs_lag_equiv));
4193 lags[it.first] = max_lag;
4194 diff[it.first] = diff_vec;
4195 orig_diff_var[it.first] = orig_diff_var_vec;
4196 }
4197 var_model_table.setDiff(diff);
4198 var_model_table.setMaxLags(lags);
4199 var_model_table.setOrigDiffVar(orig_diff_var);
4200 }
4201
4202 map<string, map<tuple<int, int, int>, expr_t>>
fillAutoregressiveMatrix(bool is_var) const4203 DynamicModel::fillAutoregressiveMatrix(bool is_var) const
4204 {
4205 map<string, map<tuple<int, int, int>, expr_t>> ARr;
4206 auto eqnums = is_var ?
4207 var_model_table.getEqNums() : trend_component_model_table.getNonTargetEqNums();
4208 for (const auto &it : eqnums)
4209 {
4210 int i = 0;
4211 map<tuple<int, int, int>, expr_t> AR;
4212 vector<int> lhs = is_var ?
4213 var_model_table.getLhsOrigIds(it.first) : trend_component_model_table.getNonTargetLhs(it.first);
4214 for (auto eqn : it.second)
4215 {
4216 auto bopn = dynamic_cast<BinaryOpNode *>(equations[eqn]->arg2);
4217 bopn->fillAutoregressiveRow(i++, lhs, AR);
4218 }
4219 ARr[it.first] = AR;
4220 }
4221 return ARr;
4222 }
4223
4224 void
fillTrendComponentModelTable() const4225 DynamicModel::fillTrendComponentModelTable() const
4226 {
4227 map<string, vector<int>> eqnums, trend_eqnums, lhsr;
4228 map<string, vector<expr_t>> lhs_expr_tr;
4229 map<string, vector<set<pair<int, int>>>> rhsr;
4230 map<string, vector<string>> eqtags = trend_component_model_table.getEqTags();
4231 map<string, vector<string>> trend_eqtags = trend_component_model_table.getTargetEqTags();
4232 for (const auto &it : trend_eqtags)
4233 {
4234 vector<int> trend_eqnumber;
4235 for (const auto &eqtag : it.second)
4236 {
4237 int eqn = -1;
4238 for (const auto &equation_tag : equation_tags)
4239 if (equation_tag.second.first == "name"
4240 && equation_tag.second.second == eqtag)
4241 {
4242 eqn = equation_tag.first;
4243 break;
4244 }
4245
4246 if (eqn == -1)
4247 {
4248 cerr << "ERROR: trend equation tag '" << eqtag << "' not found" << endl;
4249 exit(EXIT_FAILURE);
4250 }
4251 trend_eqnumber.push_back(eqn);
4252 }
4253 trend_eqnums[it.first] = trend_eqnumber;
4254 }
4255
4256 for (const auto &it : eqtags)
4257 {
4258 vector<int> eqnumber, lhs;
4259 vector<expr_t> lhs_expr_t;
4260 vector<set<pair<int, int>>> rhs;
4261
4262 for (const auto &eqtag : it.second)
4263 {
4264 int eqn = -1;
4265 set<pair<int, int>> lhs_set, lhs_tmp_set, rhs_set;
4266 for (const auto &equation_tag : equation_tags)
4267 if (equation_tag.second.first == "name"
4268 && equation_tag.second.second == eqtag)
4269 {
4270 eqn = equation_tag.first;
4271 break;
4272 }
4273
4274 if (eqn == -1)
4275 {
4276 cerr << "ERROR: equation tag '" << eqtag << "' not found" << endl;
4277 exit(EXIT_FAILURE);
4278 }
4279
4280 equations[eqn]->arg1->collectDynamicVariables(SymbolType::endogenous, lhs_set);
4281 equations[eqn]->arg1->collectDynamicVariables(SymbolType::exogenous, lhs_tmp_set);
4282 equations[eqn]->arg1->collectDynamicVariables(SymbolType::parameter, lhs_tmp_set);
4283
4284 if (lhs_set.size() != 1 || !lhs_tmp_set.empty())
4285 {
4286 cerr << "ERROR: in Equation " << eqtag
4287 << ". A trend component model may only have one endogenous variable on the LHS. " << endl;
4288 exit(EXIT_FAILURE);
4289 }
4290
4291 auto itlhs = lhs_set.begin();
4292 if (itlhs->second != 0)
4293 {
4294 cerr << "ERROR: in Equation " << eqtag
4295 << ". The variable on the LHS of a trend component model may not appear with a lead or a lag. "
4296 << endl;
4297 exit(EXIT_FAILURE);
4298 }
4299
4300 eqnumber.push_back(eqn);
4301 lhs.push_back(itlhs->first);
4302 lhs_set.clear();
4303 set<expr_t> lhs_expr_t_set;
4304 equations[eqn]->arg1->collectVARLHSVariable(lhs_expr_t_set);
4305 lhs_expr_t.push_back(*(lhs_expr_t_set.begin()));
4306
4307 equations[eqn]->arg2->collectDynamicVariables(SymbolType::endogenous, rhs_set);
4308 for (const auto &itrhs : rhs_set)
4309 if (itrhs.second > 0)
4310 {
4311 cerr << "ERROR: in Equation " << eqtag
4312 << ". A trend component model may not have leaded or contemporaneous variables on the RHS. " << endl;
4313 exit(EXIT_FAILURE);
4314 }
4315 rhs.push_back(rhs_set);
4316 }
4317 eqnums[it.first] = eqnumber;
4318 lhsr[it.first] = lhs;
4319 lhs_expr_tr[it.first] = lhs_expr_t;
4320 rhsr[it.first] = rhs;
4321 }
4322 trend_component_model_table.setRhs(rhsr);
4323 trend_component_model_table.setVals(eqnums, trend_eqnums, lhsr, lhs_expr_tr);
4324 }
4325
4326 pair<map<string, map<tuple<int, int, int>, expr_t>>, map<string, map<tuple<int, int, int>, expr_t>>>
fillErrorComponentMatrix(const ExprNode::subst_table_t & diff_subst_table) const4327 DynamicModel::fillErrorComponentMatrix(const ExprNode::subst_table_t &diff_subst_table) const
4328 {
4329 map<string, map<tuple<int, int, int>, expr_t>> A0r, A0starr;
4330
4331 for (const auto &it : trend_component_model_table.getEqNums())
4332 {
4333 int i = 0;
4334 map<tuple<int, int, int>, expr_t> A0, A0star;
4335 vector<int> target_lhs = trend_component_model_table.getTargetLhs(it.first);
4336 vector<int> nontarget_eqnums = trend_component_model_table.getNonTargetEqNums(it.first);
4337 vector<int> undiff_nontarget_lhs = getUndiffLHSForPac(it.first, diff_subst_table);
4338 vector<int> parsed_undiff_nontarget_lhs;
4339
4340 for (auto eqn : it.second)
4341 {
4342 if (find(nontarget_eqnums.begin(), nontarget_eqnums.end(), eqn) != nontarget_eqnums.end())
4343 parsed_undiff_nontarget_lhs.push_back(undiff_nontarget_lhs.at(i));
4344 i++;
4345 }
4346
4347 i = 0;
4348 for (auto eqn : it.second)
4349 if (find(nontarget_eqnums.begin(), nontarget_eqnums.end(), eqn) != nontarget_eqnums.end())
4350 equations[eqn]->arg2->fillErrorCorrectionRow(i++, parsed_undiff_nontarget_lhs, target_lhs, A0, A0star);
4351 A0r[it.first] = A0;
4352 A0starr[it.first] = A0star;
4353 }
4354
4355 return { A0r, A0starr };
4356 }
4357
4358 void
fillTrendComponentModelTableFromOrigModel() const4359 DynamicModel::fillTrendComponentModelTableFromOrigModel() const
4360 {
4361 map<string, vector<int>> lags, orig_diff_var;
4362 map<string, vector<bool>> diff;
4363 for (const auto &it : trend_component_model_table.getEqNums())
4364 {
4365 set<expr_t> lhs;
4366 vector<int> orig_diff_var_vec;
4367 vector<bool> diff_vec;
4368 for (auto eqn : it.second)
4369 {
4370 // ensure no leads in equations
4371 if (equations[eqn]->arg2->VarMinLag() <= 0)
4372 {
4373 cerr << "ERROR in trend component model Equation (#" << eqn << "). "
4374 << "Leaded exogenous variables "
4375 << "and leaded or contemporaneous endogenous variables not allowed in VAR"
4376 << endl;
4377 exit(EXIT_FAILURE);
4378 }
4379
4380 // save lhs variables
4381 equations[eqn]->arg1->collectVARLHSVariable(lhs);
4382
4383 if (equations[eqn]->arg1->countDiffs() > 0)
4384 diff_vec.push_back(true);
4385 else
4386 diff_vec.push_back(false);
4387 if (diff_vec.back())
4388 {
4389 set<pair<int, int>> diff_set;
4390 equations[eqn]->arg1->collectDynamicVariables(SymbolType::endogenous, diff_set);
4391
4392 if (diff_set.size() != 1)
4393 {
4394 cerr << "ERROR: problem getting variable for LHS diff operator in equation "
4395 << eqn << endl;
4396 exit(EXIT_FAILURE);
4397 }
4398 orig_diff_var_vec.push_back(diff_set.begin()->first);
4399 }
4400 else
4401 orig_diff_var_vec.push_back(-1);
4402
4403 }
4404
4405 if (it.second.size() != lhs.size())
4406 {
4407 cerr << "ERROR: The LHS variables of the trend component model are not unique" << endl;
4408 exit(EXIT_FAILURE);
4409 }
4410
4411 set<expr_t> lhs_lag_equiv;
4412 for (const auto &lh : lhs)
4413 {
4414 auto [lag_equiv_repr, index] = lh->getLagEquivalenceClass();
4415 lhs_lag_equiv.insert(lag_equiv_repr);
4416 }
4417
4418 vector<int> max_lag;
4419 for (auto eqn : it.second)
4420 max_lag.push_back(equations[eqn]->arg2->VarMaxLag(lhs_lag_equiv));
4421 lags[it.first] = max_lag;
4422 diff[it.first] = diff_vec;
4423 orig_diff_var[it.first] = orig_diff_var_vec;
4424 }
4425 trend_component_model_table.setDiff(diff);
4426 trend_component_model_table.setMaxLags(lags);
4427 trend_component_model_table.setOrigDiffVar(orig_diff_var);
4428 }
4429
4430 void
fillTrendComponentmodelTableAREC(const ExprNode::subst_table_t & diff_subst_table) const4431 DynamicModel::fillTrendComponentmodelTableAREC(const ExprNode::subst_table_t &diff_subst_table) const
4432 {
4433 auto ARr = fillAutoregressiveMatrix(false);
4434 trend_component_model_table.setAR(ARr);
4435 auto [A0r, A0starr] = fillErrorComponentMatrix(diff_subst_table);
4436 trend_component_model_table.setA0(A0r, A0starr);
4437 }
4438
4439 void
addEquationsForVar()4440 DynamicModel::addEquationsForVar()
4441 {
4442 if (var_model_table.empty())
4443 return;
4444 auto var_symbol_list_and_order = var_model_table.getSymbolListAndOrder();
4445
4446 // List of endogenous variables and the minimum lag value that must exist in the model equations
4447 map<string, int> var_endos_and_lags, model_endos_and_lags;
4448 for (const auto &it : var_symbol_list_and_order)
4449 for (auto &equation : equations)
4450 if (equation->isVarModelReferenced(it.first))
4451 {
4452 vector<string> symbol_list = it.second.first.get_symbols();
4453 int order = it.second.second;
4454 for (auto &it1 : symbol_list)
4455 if (order > 2)
4456 if (var_endos_and_lags.find(it1) != var_endos_and_lags.end())
4457 var_endos_and_lags[it1] = min(var_endos_and_lags[it1], -order);
4458 else
4459 var_endos_and_lags[it1] = -order;
4460 break;
4461 }
4462
4463 if (var_endos_and_lags.empty())
4464 return;
4465
4466 // Ensure that the minimum lag value exists in the model equations.
4467 // If not, add an equation for it
4468 for (auto &equation : equations)
4469 equation->getEndosAndMaxLags(model_endos_and_lags);
4470
4471 int count = 0;
4472 for (auto &it : var_endos_and_lags)
4473 if (auto it2 = model_endos_and_lags.find(it.first);
4474 it2 == model_endos_and_lags.end())
4475 cerr << "WARNING: Variable used in VAR that is not used in the model: " << it.first << endl;
4476 else
4477 if (it.second < it2->second)
4478 {
4479 int symb_id = symbol_table.getID(it.first);
4480 expr_t newvar = AddVariable(symb_id, it.second);
4481 expr_t auxvar = AddVariable(symbol_table.addVarModelEndoLagAuxiliaryVar(symb_id, it.second, newvar), 0);
4482 addEquation(AddEqual(newvar, auxvar), -1);
4483 addAuxEquation(AddEqual(newvar, auxvar));
4484 count++;
4485 }
4486
4487 if (count > 0)
4488 cout << "Accounting for var_model lags not in model block: added "
4489 << count << " auxiliary variables and equations." << endl;
4490 }
4491
4492 vector<int>
getUndiffLHSForPac(const string & aux_model_name,const ExprNode::subst_table_t & diff_subst_table) const4493 DynamicModel::getUndiffLHSForPac(const string &aux_model_name,
4494 const ExprNode::subst_table_t &diff_subst_table) const
4495 {
4496 vector<expr_t> lhs_expr_t = trend_component_model_table.getLhsExprT(aux_model_name);
4497 vector<int> lhs = trend_component_model_table.getLhs(aux_model_name);
4498 vector<bool> diff = trend_component_model_table.getDiff(aux_model_name);
4499 vector<int> orig_diff_var = trend_component_model_table.getOrigDiffVar(aux_model_name);
4500 vector<int> eqnumber = trend_component_model_table.getEqNums(aux_model_name);
4501 vector<int> nontrend_eqnums = trend_component_model_table.getNonTargetEqNums(aux_model_name);
4502
4503 for (auto eqn : nontrend_eqnums)
4504 {
4505 int i = 0;
4506 for (auto it1 = eqnumber.begin(); it1 != eqnumber.end(); ++it1, i++)
4507 if (*it1 == eqn)
4508 break;
4509
4510 if (eqnumber[i] != eqn)
4511 {
4512 cerr << "ERROR: equation " << eqn << " not found in VAR" << endl;
4513 exit(EXIT_FAILURE);
4514 }
4515
4516 if (diff.at(i) != true)
4517 {
4518 cerr << "ERROR: the variable on the LHS of equation #" << eqn
4519 << " does not have the diff operator applied to it yet you are trying to undiff it."
4520 << endl;
4521 exit(EXIT_FAILURE);
4522 }
4523
4524 bool printerr = false;
4525 expr_t node = nullptr;
4526 expr_t aux_var = lhs_expr_t.at(i);
4527 for (const auto &it : diff_subst_table)
4528 if (it.second == aux_var)
4529 {
4530 node = const_cast<expr_t>(it.first);
4531 break;
4532 }
4533
4534 if (!node)
4535 {
4536 cerr << "Unexpected error encountered." << endl;
4537 exit(EXIT_FAILURE);
4538 }
4539
4540 node = node->undiff();
4541 auto it1 = diff_subst_table.find(node);
4542 if (it1 == diff_subst_table.end())
4543 printerr = true;
4544
4545 if (printerr)
4546 { // we have undiffed something like diff(x), hence x is not in diff_subst_table
4547 lhs_expr_t.at(i) = node;
4548 lhs.at(i) = dynamic_cast<VariableNode *>(node)->symb_id;
4549 }
4550 else
4551 {
4552 lhs_expr_t.at(i) = const_cast<expr_t>(it1->first);
4553 lhs.at(i) = const_cast<VariableNode *>(it1->second)->symb_id;
4554 }
4555 }
4556 return lhs;
4557 }
4558
4559 map<pair<string, string>, pair<string, int>>
walkPacParameters(const string & name)4560 DynamicModel::walkPacParameters(const string &name)
4561 {
4562 map<pair<string, string>, pair<string, int>> eqtag_and_lag;
4563
4564 int i = 0;
4565 for (auto &equation : equations)
4566 {
4567 pair<int, int> lhs(-1, -1);
4568 pair<int, vector<tuple<int, bool, int>>> ec_params_and_vars;
4569 set<pair<int, pair<int, int>>> ar_params_and_vars;
4570 vector<tuple<int, int, int, double>> non_optim_vars_params_and_constants, optim_additive_vars_params_and_constants, additive_vars_params_and_constants;
4571
4572 if (equation->containsPacExpectation())
4573 {
4574 set<pair<int, int>> lhss;
4575 equation->arg1->collectDynamicVariables(SymbolType::endogenous, lhss);
4576 lhs = *lhss.begin();
4577 int lhs_symb_id = lhs.first;
4578 int lhs_orig_symb_id = lhs_symb_id;
4579 if (symbol_table.isAuxiliaryVariable(lhs_orig_symb_id))
4580 try
4581 {
4582 lhs_orig_symb_id = symbol_table.getOrigSymbIdForAuxVar(lhs_orig_symb_id);
4583 }
4584 catch (...)
4585 {
4586 }
4587
4588 auto arg2 = dynamic_cast<BinaryOpNode *>(equation->arg2);
4589 if (!arg2)
4590 {
4591 cerr << "Pac equation in incorrect format" << endl;
4592 exit(EXIT_FAILURE);
4593 }
4594 auto [optim_share_index, optim_part, non_optim_part, additive_part]
4595 = arg2->getPacOptimizingShareAndExprNodes(lhs_symb_id, lhs_orig_symb_id);
4596
4597 if (!optim_part)
4598 {
4599 auto bopn = dynamic_cast<BinaryOpNode *>(equation->arg2);
4600 if (!bopn)
4601 {
4602 cerr << "Error in PAC equation" << endl;
4603 exit(EXIT_FAILURE);
4604 }
4605 bopn->getPacAREC(lhs_symb_id, lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars, additive_vars_params_and_constants);
4606 }
4607 else
4608 {
4609 auto bopn = dynamic_cast<BinaryOpNode *>(optim_part);
4610 if (!bopn)
4611 {
4612 cerr << "Error in PAC equation" << endl;
4613 exit(EXIT_FAILURE);
4614 }
4615 bopn->getPacAREC(lhs_symb_id, lhs_orig_symb_id, ec_params_and_vars, ar_params_and_vars, optim_additive_vars_params_and_constants);
4616 try
4617 {
4618 non_optim_vars_params_and_constants = non_optim_part->matchLinearCombinationOfVariables();
4619 if (additive_part)
4620 additive_vars_params_and_constants = additive_part->matchLinearCombinationOfVariables();
4621 }
4622 catch (ExprNode::MatchFailureException &e)
4623 {
4624 cerr << "Error in parsing non-optimizing agents or additive part of PAC equation: "
4625 << e.message << endl;
4626 exit(EXIT_FAILURE);
4627 }
4628 }
4629
4630 string eqtag;
4631 for (auto &tag : equation_tags)
4632 if (tag.first == (&equation - &equations[0]))
4633 if (tag.second.first == "name")
4634 {
4635 eqtag = tag.second.second;
4636 break;
4637 }
4638 if (eqtag.empty())
4639 {
4640 cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
4641 exit(EXIT_FAILURE);
4642 }
4643 if (lhs.first == -1)
4644 {
4645 cerr << "walkPacParameters: error obtaining LHS variable." << endl;
4646 exit(EXIT_FAILURE);
4647 }
4648 if (ec_params_and_vars.second.empty() || ar_params_and_vars.empty())
4649 {
4650 cerr << "walkPacParameters: error obtaining RHS parameters." << endl;
4651 exit(EXIT_FAILURE);
4652 }
4653 string eq = "eq" + to_string(i++);
4654 pac_equation_info[{name, eq}] = {lhs, optim_share_index,
4655 ar_params_and_vars, ec_params_and_vars,
4656 non_optim_vars_params_and_constants,
4657 additive_vars_params_and_constants,
4658 optim_additive_vars_params_and_constants};
4659 eqtag_and_lag[{name, eqtag}] = {eq, 0};
4660 }
4661 }
4662 return eqtag_and_lag;
4663 }
4664
4665 void
getPacMaxLag(const string & pac_model_name,map<pair<string,string>,pair<string,int>> & eqtag_and_lag) const4666 DynamicModel::getPacMaxLag(const string &pac_model_name, map<pair<string, string>, pair<string, int>> &eqtag_and_lag) const
4667 {
4668 for (auto &equation : equations)
4669 if (equation->containsPacExpectation(pac_model_name))
4670 {
4671 set<pair<int, int>> endogs;
4672 equation->arg1->collectDynamicVariables(SymbolType::endogenous, endogs);
4673 if (endogs.size() != 1)
4674 {
4675 cerr << "The LHS of the PAC equation may only be comprised of one endogenous variable"
4676 << endl;
4677 exit(EXIT_FAILURE);
4678 }
4679
4680 string eqtag;
4681 for (auto &tag : equation_tags)
4682 if (tag.first == (&equation - &equations[0]))
4683 if (tag.second.first == "name")
4684 {
4685 eqtag = tag.second.second;
4686 break;
4687 }
4688 string eq = eqtag_and_lag[{pac_model_name, eqtag}].first;
4689 eqtag_and_lag[{pac_model_name, eqtag}] = {eq, equation->PacMaxLag(endogs.begin()->first)};
4690 }
4691 }
4692
4693 int
getPacTargetSymbId(const string & pac_model_name) const4694 DynamicModel::getPacTargetSymbId(const string &pac_model_name) const
4695 {
4696 for (auto &equation : equations)
4697 if (equation->containsPacExpectation(pac_model_name))
4698 {
4699 pair<int, int> lhs(-1, -1);
4700 set<pair<int, int>> lhss;
4701 equation->arg1->collectDynamicVariables(SymbolType::endogenous, lhss);
4702 lhs = *lhss.begin();
4703 int lhs_symb_id = lhs.first;
4704 int lhs_orig_symb_id = lhs_symb_id;
4705 if (symbol_table.isAuxiliaryVariable(lhs_symb_id))
4706 try
4707 {
4708 lhs_orig_symb_id = symbol_table.getOrigSymbIdForAuxVar(lhs_symb_id);
4709 }
4710 catch (...)
4711 {
4712 }
4713 return equation->arg2->getPacTargetSymbId(lhs_symb_id, lhs_orig_symb_id);
4714 }
4715 return -1;
4716 }
4717
4718 void
declarePacModelConsistentExpectationEndogs(const string & name)4719 DynamicModel::declarePacModelConsistentExpectationEndogs(const string &name)
4720 {
4721 int i = 0;
4722 for (auto &equation : equations)
4723 if (equation->containsPacExpectation())
4724 {
4725 string eqtag;
4726 for (auto &tag : equation_tags)
4727 if (tag.first == (&equation - &equations[0]))
4728 if (tag.second.first == "name")
4729 {
4730 eqtag = tag.second.second;
4731 break;
4732 }
4733 if (eqtag.empty())
4734 {
4735 cerr << "Every equation with a pac expectation must have been assigned an equation tag name" << endl;
4736 exit(EXIT_FAILURE);
4737 }
4738 string standard_eqtag = "eq" + to_string(i++);
4739 try
4740 {
4741 pac_mce_z1_symb_ids[{name, standard_eqtag}]
4742 = symbol_table.addSymbol("mce_Z1_" + name + "_" + standard_eqtag, SymbolType::endogenous);
4743 }
4744 catch (SymbolTable::AlreadyDeclaredException &e)
4745 {
4746 cerr << "Variable name needed by PAC (mce_Z1_" << name << "_" << standard_eqtag << endl;
4747 exit(EXIT_FAILURE);
4748 }
4749 }
4750 }
4751
4752 void
addPacModelConsistentExpectationEquation(const string & name,int discount_symb_id,const map<pair<string,string>,pair<string,int>> & eqtag_and_lag,ExprNode::subst_table_t & diff_subst_table)4753 DynamicModel::addPacModelConsistentExpectationEquation(const string &name, int discount_symb_id,
4754 const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
4755 ExprNode::subst_table_t &diff_subst_table)
4756 {
4757 int pac_target_symb_id = getPacTargetSymbId(name);
4758 pac_eqtag_and_lag.insert(eqtag_and_lag.begin(), eqtag_and_lag.end());
4759 int neqs = 0;
4760 for (auto &it : eqtag_and_lag)
4761 {
4762 string eqtag = it.first.second;
4763 string standard_eqtag = it.second.first;
4764 int pac_max_lag_m = it.second.second + 1;
4765 string append_to_name = name + "_" + standard_eqtag;
4766 if (pac_mce_z1_symb_ids.find({name, standard_eqtag}) == pac_mce_z1_symb_ids.end())
4767 {
4768 cerr << "Error finding pac MCE Z1 symb id" << endl;
4769 exit(EXIT_FAILURE);
4770 }
4771 int mce_z1_symb_id = pac_mce_z1_symb_ids[{name, standard_eqtag}];
4772
4773 expr_t A = One;
4774 expr_t fp = Zero;
4775 expr_t beta = AddVariable(discount_symb_id);
4776 for (int i = 1; i <= pac_max_lag_m; i++)
4777 try
4778 {
4779 int alpha_i_symb_id = symbol_table.addSymbol("mce_alpha_" + append_to_name + "_" + to_string(i),
4780 SymbolType::parameter);
4781 pac_mce_alpha_symb_ids[{name, standard_eqtag}].push_back(alpha_i_symb_id);
4782 A = AddPlus(A, AddVariable(alpha_i_symb_id));
4783 fp = AddPlus(fp,
4784 AddTimes(AddTimes(AddVariable(alpha_i_symb_id),
4785 AddPower(beta, AddPossiblyNegativeConstant(i))),
4786 AddVariable(mce_z1_symb_id, i)));
4787
4788 }
4789 catch (SymbolTable::AlreadyDeclaredException &e)
4790 {
4791 cerr << "Variable name needed by PAC (mce_alpha_" << append_to_name << "_" << i << ")" << endl;
4792 exit(EXIT_FAILURE);
4793 }
4794
4795 // Add diff nodes and eqs for pac_target_symb_id
4796 const VariableNode *target_base_diff_node;
4797 expr_t diff_node_to_search = AddDiff(AddVariable(pac_target_symb_id));
4798 if (auto sit = diff_subst_table.find(diff_node_to_search);
4799 sit != diff_subst_table.end())
4800 target_base_diff_node = sit->second;
4801 else
4802 {
4803 int symb_id = symbol_table.addDiffAuxiliaryVar(diff_node_to_search->idx, diff_node_to_search);
4804 target_base_diff_node = AddVariable(symb_id);
4805 addEquation(dynamic_cast<BinaryOpNode *>(AddEqual(const_cast<VariableNode *>(target_base_diff_node),
4806 AddMinus(AddVariable(pac_target_symb_id),
4807 AddVariable(pac_target_symb_id, -1)))), -1);
4808 neqs++;
4809 }
4810
4811 map<int, VariableNode *> target_aux_var_to_add;
4812 const VariableNode *last_aux_var = target_base_diff_node;
4813 for (int i = 1; i <= pac_max_lag_m - 1; i++, neqs++)
4814 {
4815 expr_t this_diff_node = AddDiff(AddVariable(pac_target_symb_id, i));
4816 int symb_id = symbol_table.addDiffLeadAuxiliaryVar(this_diff_node->idx, this_diff_node,
4817 last_aux_var->symb_id, last_aux_var->lag);
4818 VariableNode *current_aux_var = AddVariable(symb_id);
4819 addEquation(dynamic_cast<BinaryOpNode *>(AddEqual(current_aux_var,
4820 AddVariable(last_aux_var->symb_id, 1))), -1);
4821 last_aux_var = current_aux_var;
4822 target_aux_var_to_add[i] = current_aux_var;
4823 }
4824
4825 expr_t fs = Zero;
4826 for (int k = 1; k <= pac_max_lag_m - 1; k++)
4827 {
4828 expr_t ssum = Zero;
4829 for (int j = k+1; j <= pac_max_lag_m; j++)
4830 {
4831 int alpha_j_symb_id = -1;
4832 string varname = "mce_alpha_" + append_to_name + "_" + to_string(j);
4833 try
4834 {
4835 alpha_j_symb_id = symbol_table.getID(varname);
4836 }
4837 catch (SymbolTable::UnknownSymbolNameException &e)
4838 {
4839 alpha_j_symb_id = symbol_table.addSymbol(varname, SymbolType::parameter);
4840 }
4841 ssum = AddPlus(ssum,
4842 AddTimes(AddVariable(alpha_j_symb_id), AddPower(beta, AddPossiblyNegativeConstant(j))));
4843 }
4844 fs = AddPlus(fs, AddTimes(ssum, target_aux_var_to_add[k]));
4845 }
4846 addEquation(AddEqual(AddVariable(mce_z1_symb_id),
4847 AddMinus(AddTimes(A, AddMinus(const_cast<VariableNode *>(target_base_diff_node), fs)), fp)), -1);
4848 neqs++;
4849 pac_expectation_substitution[{name, eqtag}] = AddVariable(mce_z1_symb_id);
4850 }
4851 cout << "Pac Model Consistent Expectation: added " << neqs << " auxiliary variables and equations." << endl;
4852 }
4853
4854 void
fillPacModelInfo(const string & pac_model_name,vector<int> lhs,int max_lag,string aux_model_type,const map<pair<string,string>,pair<string,int>> & eqtag_and_lag,const vector<bool> & nonstationary,expr_t growth)4855 DynamicModel::fillPacModelInfo(const string &pac_model_name,
4856 vector<int> lhs,
4857 int max_lag,
4858 string aux_model_type,
4859 const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
4860 const vector<bool> &nonstationary,
4861 expr_t growth)
4862 {
4863 pac_eqtag_and_lag.insert(eqtag_and_lag.begin(), eqtag_and_lag.end());
4864
4865 bool stationary_vars_present = any_of(nonstationary.begin(), nonstationary.end(), logical_not<bool>());
4866 bool nonstationary_vars_present = any_of(nonstationary.begin(), nonstationary.end(), [](bool b) { return b; }); // FIXME: use std::identity instead of an anonymous function when we upgrade to C++20
4867
4868 int growth_param_index = -1;
4869 if (growth)
4870 growth_param_index = symbol_table.addSymbol(pac_model_name
4871 +"_pac_growth_neutrality_correction",
4872 SymbolType::parameter);
4873
4874 for (auto pac_models_and_eqtags : pac_eqtag_and_lag)
4875 {
4876 if (pac_models_and_eqtags.first.first != pac_model_name)
4877 continue;
4878 string eqtag = pac_models_and_eqtags.first.second;
4879 string standard_eqtag = pac_models_and_eqtags.second.first;
4880 expr_t subExpr = Zero;
4881 if (stationary_vars_present)
4882 for (int i = 1; i < max_lag + 1; i++)
4883 for (auto lhsit : lhs)
4884 {
4885 stringstream param_name_h0;
4886 param_name_h0 << "h0_" << pac_model_name
4887 << "_" << standard_eqtag
4888 << "_var_" << symbol_table.getName(lhsit)
4889 << "_lag_" << i;
4890 int new_param_symb_id = symbol_table.addSymbol(param_name_h0.str(), SymbolType::parameter);
4891 pac_h0_indices[{pac_model_name, standard_eqtag}].push_back(new_param_symb_id);
4892 subExpr = AddPlus(subExpr,
4893 AddTimes(AddVariable(new_param_symb_id),
4894 AddVariable(lhsit, -i)));
4895 }
4896
4897 if (nonstationary_vars_present)
4898 for (int i = 1; i < max_lag + 1; i++)
4899 for (auto lhsit : lhs)
4900 {
4901 stringstream param_name_h1;
4902 param_name_h1 << "h1_" << pac_model_name
4903 << "_" << standard_eqtag
4904 << "_var_" << symbol_table.getName(lhsit)
4905 << "_lag_" << i;
4906 int new_param_symb_id = symbol_table.addSymbol(param_name_h1.str(), SymbolType::parameter);
4907 pac_h1_indices[{pac_model_name, standard_eqtag}].push_back(new_param_symb_id);
4908 subExpr = AddPlus(subExpr,
4909 AddTimes(AddVariable(new_param_symb_id),
4910 AddVariable(lhsit, -i)));
4911 }
4912
4913 if (growth)
4914 subExpr = AddPlus(subExpr,
4915 AddTimes(AddVariable(growth_param_index), growth));
4916
4917 pac_expectation_substitution[{pac_model_name, eqtag}] = subExpr;
4918 }
4919 pac_model_info[pac_model_name] = {move(lhs), growth_param_index, move(aux_model_type)};
4920 }
4921
4922 void
substitutePacExpectation(const string & pac_model_name)4923 DynamicModel::substitutePacExpectation(const string &pac_model_name)
4924 {
4925 for (auto &it : pac_expectation_substitution)
4926 if (it.first.first == pac_model_name)
4927 for (auto &equation : equations)
4928 for (auto & [tagged_eq, tag_pair] : equation_tags)
4929 if (tagged_eq == (&equation - &equations[0])
4930 && tag_pair.first == "name" && tag_pair.second == it.first.second)
4931 {
4932 auto substeq = dynamic_cast<BinaryOpNode *>(equation->substitutePacExpectation(pac_model_name, it.second));
4933 assert(substeq);
4934 equation = substeq;
4935 break;
4936 }
4937 }
4938
4939 void
computingPass(bool jacobianExo,int derivsOrder,int paramsDerivsOrder,const eval_context_t & eval_context,bool no_tmp_terms,bool block,bool use_dll,bool bytecode,bool linear_decomposition)4940 DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsOrder,
4941 const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll,
4942 bool bytecode, bool linear_decomposition)
4943 {
4944 assert(jacobianExo || (derivsOrder < 2 && paramsDerivsOrder == 0));
4945
4946 initializeVariablesAndEquations();
4947
4948 // Prepare for derivation
4949 computeDerivIDs();
4950
4951 // Computes dynamic jacobian columns, must be done after computeDerivIDs()
4952 computeDynJacobianCols(jacobianExo);
4953
4954 // Compute derivatives w.r. to all endogenous, and possibly exogenous and exogenous deterministic
4955 set<int> vars;
4956 for (auto &it : deriv_id_table)
4957 {
4958 SymbolType type = symbol_table.getType(it.first.first);
4959 if (type == SymbolType::endogenous || (jacobianExo && (type == SymbolType::exogenous || type == SymbolType::exogenousDet)))
4960 vars.insert(it.second);
4961 }
4962
4963 // Launch computations
4964 cout << "Computing " << (linear_decomposition ? "nonlinear " : "")
4965 << "dynamic model derivatives (order " << derivsOrder << ")." << endl;
4966
4967 computeDerivatives(derivsOrder, vars);
4968
4969 if (derivsOrder > 1)
4970 for (const auto &[indices, d2] : derivatives[2])
4971 nonzero_hessian_eqs.insert(indices[0]);
4972
4973 if (paramsDerivsOrder > 0)
4974 {
4975 cout << "Computing dynamic model derivatives w.r.t. parameters (order " << paramsDerivsOrder << ")." << endl;
4976 computeParamsDerivatives(paramsDerivsOrder);
4977 }
4978
4979 jacob_map_t contemporaneous_jacobian, static_jacobian;
4980 map<tuple<int, int, int>, expr_t> first_order_endo_derivatives;
4981 // for each block contains pair<Size, Feddback_variable>
4982 vector<pair<int, int>> blocks;
4983 vector<unsigned int> n_static, n_forward, n_backward, n_mixed;
4984
4985 if (linear_decomposition)
4986 {
4987 first_order_endo_derivatives = collect_first_order_derivatives_endogenous();
4988 is_equation_linear = equationLinear(first_order_endo_derivatives);
4989
4990 evaluateAndReduceJacobian(eval_context, contemporaneous_jacobian, static_jacobian, dynamic_jacobian, cutoff, false);
4991
4992 if (!computeNaturalNormalization())
4993 computeNonSingularNormalization(contemporaneous_jacobian, cutoff, static_jacobian, dynamic_jacobian);
4994
4995 lag_lead_vector_t equation_lag_lead, variable_lag_lead;
4996
4997 blocks = select_non_linear_equations_and_variables(is_equation_linear, dynamic_jacobian, equation_reordered, variable_reordered,
4998 inv_equation_reordered, inv_variable_reordered,
4999 equation_lag_lead, variable_lag_lead,
5000 n_static, n_forward, n_backward, n_mixed);
5001
5002 equation_type_and_normalized_equation = equationTypeDetermination(first_order_endo_derivatives, variable_reordered, equation_reordered, 0);
5003 prologue = 0;
5004 epilogue = 0;
5005
5006 block_type_firstequation_size_mfs = reduceBlocksAndTypeDetermination(dynamic_jacobian, blocks, equation_type_and_normalized_equation, variable_reordered, equation_reordered, n_static, n_forward, n_backward, n_mixed, block_col_type, linear_decomposition);
5007
5008 computeChainRuleJacobian(blocks_derivatives);
5009
5010 blocks_linear = BlockLinear(blocks_derivatives, variable_reordered);
5011
5012 collect_block_first_order_derivatives();
5013
5014 collectBlockVariables();
5015
5016 global_temporary_terms = true;
5017 if (!no_tmp_terms)
5018 computeTemporaryTermsOrdered();
5019 }
5020
5021 if (block)
5022 {
5023 evaluateAndReduceJacobian(eval_context, contemporaneous_jacobian, static_jacobian, dynamic_jacobian, cutoff, false);
5024
5025 computeNonSingularNormalization(contemporaneous_jacobian, cutoff, static_jacobian, dynamic_jacobian);
5026
5027 computePrologueAndEpilogue(static_jacobian, equation_reordered, variable_reordered);
5028
5029 first_order_endo_derivatives = collect_first_order_derivatives_endogenous();
5030
5031 equation_type_and_normalized_equation = equationTypeDetermination(first_order_endo_derivatives, variable_reordered, equation_reordered, mfs);
5032
5033 cout << "Finding the optimal block decomposition of the model ..." << endl;
5034
5035 lag_lead_vector_t equation_lag_lead, variable_lag_lead;
5036
5037 computeBlockDecompositionAndFeedbackVariablesForEachBlock(static_jacobian, dynamic_jacobian, equation_reordered, variable_reordered, blocks, equation_type_and_normalized_equation, false, true, mfs, inv_equation_reordered, inv_variable_reordered, equation_lag_lead, variable_lag_lead, n_static, n_forward, n_backward, n_mixed);
5038
5039 block_type_firstequation_size_mfs = reduceBlocksAndTypeDetermination(dynamic_jacobian, blocks, equation_type_and_normalized_equation, variable_reordered, equation_reordered, n_static, n_forward, n_backward, n_mixed, block_col_type, linear_decomposition);
5040
5041 printBlockDecomposition(blocks);
5042
5043 computeChainRuleJacobian(blocks_derivatives);
5044
5045 blocks_linear = BlockLinear(blocks_derivatives, variable_reordered);
5046
5047 collect_block_first_order_derivatives();
5048
5049 collectBlockVariables();
5050
5051 global_temporary_terms = true;
5052 if (!no_tmp_terms)
5053 computeTemporaryTermsOrdered();
5054 int k = 0;
5055 equation_block.resize(equations.size());
5056 variable_block_lead_lag = vector<tuple<int, int, int>>(equations.size());
5057 for (unsigned int i = 0; i < getNbBlocks(); i++)
5058 {
5059 for (unsigned int j = 0; j < getBlockSize(i); j++)
5060 {
5061 equation_block[equation_reordered[k]] = i;
5062 int l = variable_reordered[k];
5063 variable_block_lead_lag[l] = { i, variable_lag_lead[l].first, variable_lag_lead[l].second };
5064 k++;
5065 }
5066 }
5067 }
5068 else
5069 {
5070 computeTemporaryTerms(!use_dll, no_tmp_terms);
5071 if (bytecode && !no_tmp_terms)
5072 computeTemporaryTermsMapping();
5073
5074 /* Must be called after computeTemporaryTerms(), because it depends on
5075 temporary_terms_mlv to be filled */
5076 if (paramsDerivsOrder > 0 && !no_tmp_terms)
5077 computeParamsDerivativesTemporaryTerms();
5078 }
5079 }
5080
5081 void
computeXrefs()5082 DynamicModel::computeXrefs()
5083 {
5084 int i = 0;
5085 for (auto &equation : equations)
5086 {
5087 ExprNode::EquationInfo ei;
5088 equation->computeXrefs(ei);
5089 xrefs[i++] = ei;
5090 }
5091
5092 i = 0;
5093 for (auto it = xrefs.begin(); it != xrefs.end(); ++it, i++)
5094 {
5095 computeRevXref(xref_param, it->second.param, i);
5096 computeRevXref(xref_endo, it->second.endo, i);
5097 computeRevXref(xref_exo, it->second.exo, i);
5098 computeRevXref(xref_exo_det, it->second.exo_det, i);
5099 }
5100 }
5101
5102 void
computeRevXref(map<pair<int,int>,set<int>> & xrefset,const set<pair<int,int>> & eiref,int eqn)5103 DynamicModel::computeRevXref(map<pair<int, int>, set<int>> &xrefset, const set<pair<int, int>> &eiref, int eqn)
5104 {
5105 for (const auto &it : eiref)
5106 {
5107 set<int> eq;
5108 if (xrefset.find(it) != xrefset.end())
5109 eq = xrefset[it];
5110 eq.insert(eqn);
5111 xrefset[it] = eq;
5112 }
5113 }
5114
5115 void
writeXrefs(ostream & output) const5116 DynamicModel::writeXrefs(ostream &output) const
5117 {
5118 output << "M_.xref1.param = cell(1, M_.eq_nbr);" << endl
5119 << "M_.xref1.endo = cell(1, M_.eq_nbr);" << endl
5120 << "M_.xref1.exo = cell(1, M_.eq_nbr);" << endl
5121 << "M_.xref1.exo_det = cell(1, M_.eq_nbr);" << endl;
5122 int i = 1;
5123 for (auto it = xrefs.begin(); it != xrefs.end(); ++it, i++)
5124 {
5125 output << "M_.xref1.param{" << i << "} = [ ";
5126 for (const auto &it1 : it->second.param)
5127 output << symbol_table.getTypeSpecificID(it1.first) + 1 << " ";
5128 output << "];" << endl;
5129
5130 output << "M_.xref1.endo{" << i << "} = [ ";
5131 for (const auto &it1 : it->second.endo)
5132 output << "struct('id', " << symbol_table.getTypeSpecificID(it1.first) + 1 << ", 'shift', " << it1.second << ");";
5133 output << "];" << endl;
5134
5135 output << "M_.xref1.exo{" << i << "} = [ ";
5136 for (const auto &it1 : it->second.exo)
5137 output << "struct('id', " << symbol_table.getTypeSpecificID(it1.first) + 1 << ", 'shift', " << it1.second << ");";
5138 output << "];" << endl;
5139
5140 output << "M_.xref1.exo_det{" << i << "} = [ ";
5141 for (const auto &it1 : it->second.exo_det)
5142 output << "struct('id', " << symbol_table.getTypeSpecificID(it1.first) + 1 << ", 'shift', " << it1.second << ");";
5143 output << "];" << endl;
5144 }
5145
5146 output << "M_.xref2.param = cell(1, M_.param_nbr);" << endl
5147 << "M_.xref2.endo = cell(1, M_.endo_nbr);" << endl
5148 << "M_.xref2.exo = cell(1, M_.exo_nbr);" << endl
5149 << "M_.xref2.exo_det = cell(1, M_.exo_det_nbr);" << endl;
5150 writeRevXrefs(output, xref_param, "param");
5151 writeRevXrefs(output, xref_endo, "endo");
5152 writeRevXrefs(output, xref_exo, "exo");
5153 writeRevXrefs(output, xref_exo_det, "exo_det");
5154 }
5155
5156 void
writeRevXrefs(ostream & output,const map<pair<int,int>,set<int>> & xrefmap,const string & type) const5157 DynamicModel::writeRevXrefs(ostream &output, const map<pair<int, int>, set<int>> &xrefmap, const string &type) const
5158 {
5159 int last_tsid = -1;
5160 for (const auto &it : xrefmap)
5161 {
5162 int tsid = symbol_table.getTypeSpecificID(it.first.first) + 1;
5163 output << "M_.xref2." << type << "{" << tsid << "} = [ ";
5164 if (last_tsid == tsid)
5165 output << "M_.xref2." << type << "{" << tsid << "}; ";
5166 else
5167 last_tsid = tsid;
5168
5169 for (const auto &it1 : it.second)
5170 if (type == "param")
5171 output << it1 + 1 << " ";
5172 else
5173 output << "struct('shift', " << it.first.second << ", 'eq', " << it1+1 << ");";
5174 output << "];" << endl;
5175 }
5176 }
5177
5178 map<tuple<int, int, int, int, int>, int>
get_Derivatives(int block)5179 DynamicModel::get_Derivatives(int block)
5180 {
5181 int max_lag, max_lead;
5182 map<tuple<int, int, int, int, int>, int> Derivatives;
5183 BlockSimulationType simulation_type = getBlockSimulationType(block);
5184 if (simulation_type == EVALUATE_BACKWARD || simulation_type == EVALUATE_FORWARD)
5185 {
5186 max_lag = 1;
5187 max_lead = 1;
5188 setBlockLeadLag(block, max_lag, max_lead);
5189 }
5190 else
5191 {
5192 max_lag = getBlockMaxLag(block);
5193 max_lead = getBlockMaxLead(block);
5194 }
5195 int block_size = getBlockSize(block);
5196 int block_nb_recursive = block_size - getBlockMfs(block);
5197 for (int lag = -max_lag; lag <= max_lead; lag++)
5198 {
5199 for (int eq = 0; eq < block_size; eq++)
5200 {
5201 int eqr = getBlockEquationID(block, eq);
5202 for (int var = 0; var < block_size; var++)
5203 {
5204 int varr = getBlockVariableID(block, var);
5205 if (dynamic_jacobian.find({ lag, eqr, varr }) != dynamic_jacobian.end())
5206 {
5207 bool OK = true;
5208 if (auto its = Derivatives.find({ lag, eq, var, eqr, varr });
5209 its != Derivatives.end() && its->second == 2)
5210 OK = false;
5211
5212 if (OK)
5213 {
5214 if (getBlockEquationType(block, eq) == E_EVALUATE_S && eq < block_nb_recursive)
5215 //It's a normalized equation, we have to recompute the derivative using chain rule derivative function
5216 Derivatives[{ lag, eq, var, eqr, varr }] = 1;
5217 else
5218 //It's a feedback equation we can use the derivatives
5219 Derivatives[{ lag, eq, var, eqr, varr }] = 0;
5220 }
5221 if (var < block_nb_recursive)
5222 {
5223 int eqs = getBlockEquationID(block, var);
5224 for (int vars = block_nb_recursive; vars < block_size; vars++)
5225 {
5226 int varrs = getBlockVariableID(block, vars);
5227 //A new derivative needs to be computed using the chain rule derivative function (a feedback variable appears in a recursive equation)
5228 if (Derivatives.find({ lag, var, vars, eqs, varrs }) != Derivatives.end())
5229 Derivatives[{ lag, eq, vars, eqr, varrs }] = 2;
5230 }
5231 }
5232 }
5233 }
5234 }
5235 }
5236 return Derivatives;
5237 }
5238
5239 void
computeChainRuleJacobian(blocks_derivatives_t & blocks_endo_derivatives)5240 DynamicModel::computeChainRuleJacobian(blocks_derivatives_t &blocks_endo_derivatives)
5241 {
5242 map<int, expr_t> recursive_variables;
5243 unsigned int nb_blocks = getNbBlocks();
5244 blocks_endo_derivatives = blocks_derivatives_t(nb_blocks);
5245 for (unsigned int block = 0; block < nb_blocks; block++)
5246 {
5247 block_derivatives_equation_variable_laglead_nodeid_t tmp_derivatives;
5248 recursive_variables.clear();
5249 int block_size = getBlockSize(block);
5250 int block_nb_mfs = getBlockMfs(block);
5251 int block_nb_recursives = block_size - block_nb_mfs;
5252 blocks_endo_derivatives.push_back(block_derivatives_equation_variable_laglead_nodeid_t(0));
5253 for (int i = 0; i < block_nb_recursives; i++)
5254 {
5255 if (getBlockEquationType(block, i) == E_EVALUATE_S)
5256 recursive_variables[getDerivID(symbol_table.getID(SymbolType::endogenous, getBlockVariableID(block, i)), 0)] = getBlockEquationRenormalizedExpr(block, i);
5257 else
5258 recursive_variables[getDerivID(symbol_table.getID(SymbolType::endogenous, getBlockVariableID(block, i)), 0)] = getBlockEquationExpr(block, i);
5259 }
5260 auto Derivatives = get_Derivatives(block);
5261 for (const auto &it : Derivatives)
5262 {
5263 int Deriv_type = it.second;
5264 auto [lag, eq, var, eqr, varr] = it.first;
5265 if (Deriv_type == 0)
5266 first_chain_rule_derivatives[{ eqr, varr, lag }] = derivatives[1][{ eqr, getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag) }];
5267 else if (Deriv_type == 1)
5268 first_chain_rule_derivatives[{ eqr, varr, lag }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables);
5269 else if (Deriv_type == 2)
5270 {
5271 if (getBlockEquationType(block, eq) == E_EVALUATE_S && eq < block_nb_recursives)
5272 first_chain_rule_derivatives[{ eqr, varr, lag }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables);
5273 else
5274 first_chain_rule_derivatives[{ eqr, varr, lag }] = equations[eqr]->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables);
5275 }
5276 tmp_derivatives.emplace_back(eq, var, lag, first_chain_rule_derivatives[{ eqr, varr, lag }]);
5277 }
5278 blocks_endo_derivatives[block] = tmp_derivatives;
5279 }
5280 }
5281
5282 void
collect_block_first_order_derivatives()5283 DynamicModel::collect_block_first_order_derivatives()
5284 {
5285 //! vector for an equation or a variable indicates the block number
5286 vector<int> equation_2_block(equation_reordered.size()), variable_2_block(variable_reordered.size());
5287 unsigned int nb_blocks = getNbBlocks();
5288 for (unsigned int block = 0; block < nb_blocks; block++)
5289 {
5290 unsigned int block_size = getBlockSize(block);
5291 for (unsigned int i = 0; i < block_size; i++)
5292 {
5293 equation_2_block[getBlockEquationID(block, i)] = block;
5294 variable_2_block[getBlockVariableID(block, i)] = block;
5295 }
5296 }
5297 other_endo_block = vector<lag_var_t>(nb_blocks);
5298 exo_block = vector<lag_var_t>(nb_blocks);
5299 exo_det_block = vector<lag_var_t>(nb_blocks);
5300 derivative_endo = vector<derivative_t>(nb_blocks);
5301 derivative_other_endo = vector<derivative_t>(nb_blocks);
5302 derivative_exo = vector<derivative_t>(nb_blocks);
5303 derivative_exo_det = vector<derivative_t>(nb_blocks);
5304 endo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
5305 other_endo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
5306 exo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
5307 exo_det_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
5308 max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
5309 for (auto & [indices, d1] : derivatives[1])
5310 {
5311 int eq = indices[0];
5312 int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(indices[1]));
5313 int lag = getLagByDerivID(indices[1]);
5314 int block_eq = equation_2_block[eq];
5315 int block_var = 0;
5316 derivative_t tmp_derivative;
5317 lag_var_t lag_var;
5318 switch (getTypeByDerivID(indices[1]))
5319 {
5320 case SymbolType::endogenous:
5321 block_var = variable_2_block[var];
5322 if (block_eq == block_var)
5323 {
5324 if (lag < 0 && lag < -endo_max_leadlag_block[block_eq].first)
5325 endo_max_leadlag_block[block_eq] = { -lag, endo_max_leadlag_block[block_eq].second };
5326 if (lag > 0 && lag > endo_max_leadlag_block[block_eq].second)
5327 endo_max_leadlag_block[block_eq] = { endo_max_leadlag_block[block_eq].first, lag };
5328 tmp_derivative = derivative_endo[block_eq];
5329 tmp_derivative[{ lag, eq, var }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }];
5330 derivative_endo[block_eq] = tmp_derivative;
5331 }
5332 else
5333 {
5334 if (lag < 0 && lag < -other_endo_max_leadlag_block[block_eq].first)
5335 other_endo_max_leadlag_block[block_eq] = { -lag, other_endo_max_leadlag_block[block_eq].second };
5336 if (lag > 0 && lag > other_endo_max_leadlag_block[block_eq].second)
5337 other_endo_max_leadlag_block[block_eq] = { other_endo_max_leadlag_block[block_eq].first, lag };
5338 tmp_derivative = derivative_other_endo[block_eq];
5339
5340 if (auto it = block_other_endo_index.find(block_eq);
5341 it == block_other_endo_index.end())
5342 block_other_endo_index[block_eq][var] = 0;
5343 else
5344 if (auto it1 = it->second.find(var);
5345 it1 == it->second.end())
5346 {
5347 int size = block_other_endo_index[block_eq].size();
5348 block_other_endo_index[block_eq][var] = size;
5349 }
5350
5351 tmp_derivative[{ lag, eq, var }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }];
5352 derivative_other_endo[block_eq] = tmp_derivative;
5353 lag_var = other_endo_block[block_eq];
5354 if (lag_var.find(lag) == lag_var.end())
5355 lag_var[lag].clear();
5356 lag_var[lag].insert(var);
5357 other_endo_block[block_eq] = lag_var;
5358 }
5359 break;
5360 case SymbolType::exogenous:
5361 if (lag < 0 && lag < -exo_max_leadlag_block[block_eq].first)
5362 exo_max_leadlag_block[block_eq] = { -lag, exo_max_leadlag_block[block_eq].second };
5363 if (lag > 0 && lag > exo_max_leadlag_block[block_eq].second)
5364 exo_max_leadlag_block[block_eq] = { exo_max_leadlag_block[block_eq].first, lag };
5365 tmp_derivative = derivative_exo[block_eq];
5366
5367 if (auto it = block_exo_index.find(block_eq);
5368 it == block_exo_index.end())
5369 block_exo_index[block_eq][var] = 0;
5370 else
5371 if (auto it1 = it->second.find(var);
5372 it1 == it->second.end())
5373 {
5374 int size = block_exo_index[block_eq].size();
5375 block_exo_index[block_eq][var] = size;
5376 }
5377
5378 tmp_derivative[{ lag, eq, var }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }];
5379 derivative_exo[block_eq] = tmp_derivative;
5380 lag_var = exo_block[block_eq];
5381 if (lag_var.find(lag) == lag_var.end())
5382 lag_var[lag].clear();
5383 lag_var[lag].insert(var);
5384 exo_block[block_eq] = lag_var;
5385 break;
5386 case SymbolType::exogenousDet:
5387 if (lag < 0 && lag < -exo_det_max_leadlag_block[block_eq].first)
5388 exo_det_max_leadlag_block[block_eq] = { -lag, exo_det_max_leadlag_block[block_eq].second };
5389 if (lag > 0 && lag > exo_det_max_leadlag_block[block_eq].second)
5390 exo_det_max_leadlag_block[block_eq] = { exo_det_max_leadlag_block[block_eq].first, lag };
5391 tmp_derivative = derivative_exo_det[block_eq];
5392
5393 if (auto it = block_det_exo_index.find(block_eq);
5394 it == block_det_exo_index.end())
5395 block_det_exo_index[block_eq][var] = 0;
5396 else
5397 if (auto it1 = it->second.find(var);
5398 it1 == it->second.end())
5399 {
5400 int size = block_det_exo_index[block_eq].size();
5401 block_det_exo_index[block_eq][var] = size;
5402 }
5403
5404 tmp_derivative[{ lag, eq, var }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }];
5405 derivative_exo_det[block_eq] = tmp_derivative;
5406 lag_var = exo_det_block[block_eq];
5407 if (lag_var.find(lag) == lag_var.end())
5408 lag_var[lag].clear();
5409 lag_var[lag].insert(var);
5410 exo_det_block[block_eq] = lag_var;
5411 break;
5412 default:
5413 break;
5414 }
5415 if (lag < 0 && lag < -max_leadlag_block[block_eq].first)
5416 max_leadlag_block[block_eq] = { -lag, max_leadlag_block[block_eq].second };
5417 if (lag > 0 && lag > max_leadlag_block[block_eq].second)
5418 max_leadlag_block[block_eq] = { max_leadlag_block[block_eq].first, lag };
5419 }
5420 }
5421
5422 void
collectBlockVariables()5423 DynamicModel::collectBlockVariables()
5424 {
5425 for (unsigned int block = 0; block < getNbBlocks(); block++)
5426 {
5427 int prev_var = -1;
5428 int prev_lag = -999999999;
5429 int count_col_exo = 0;
5430 var_t tmp_var_exo;
5431 for (const auto &it : exo_block[block])
5432 {
5433 int lag = it.first;
5434 for (int var : it.second)
5435 {
5436 tmp_var_exo.insert(var);
5437 if (prev_var != var || prev_lag != lag)
5438 {
5439 prev_var = var;
5440 prev_lag = lag;
5441 count_col_exo++;
5442 }
5443 }
5444 }
5445 block_var_exo.emplace_back(tmp_var_exo, count_col_exo);
5446 }
5447 }
5448
5449 void
writeDynamicFile(const string & basename,bool block,bool linear_decomposition,bool bytecode,bool use_dll,const string & mexext,const filesystem::path & matlabroot,const filesystem::path & dynareroot,bool julia) const5450 DynamicModel::writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, bool julia) const
5451 {
5452 if (block && bytecode)
5453 writeModelEquationsCode_Block(basename, map_idx, linear_decomposition);
5454 else if (!block && bytecode)
5455 {
5456 if (linear_decomposition)
5457 writeModelEquationsCode_Block(basename, map_idx, linear_decomposition);
5458 writeModelEquationsCode(basename, map_idx);
5459 }
5460 else if (block && !bytecode)
5461 writeSparseDynamicMFile(basename);
5462 else if (use_dll)
5463 {
5464 writeDynamicCFile(basename);
5465 compileDll(basename, "dynamic", mexext, matlabroot, dynareroot);
5466 }
5467 else if (julia)
5468 writeDynamicJuliaFile(basename);
5469 else
5470 writeDynamicMFile(basename);
5471 writeSetAuxiliaryVariables(basename, julia);
5472 }
5473
5474 void
writeSetAuxiliaryVariables(const string & basename,bool julia) const5475 DynamicModel::writeSetAuxiliaryVariables(const string &basename, bool julia) const
5476 {
5477 ostringstream output_func_body;
5478 writeAuxVarRecursiveDefinitions(output_func_body, ExprNodeOutputType::matlabDseries);
5479
5480 if (output_func_body.str().empty())
5481 return;
5482
5483 string func_name = julia ? basename + "_dynamic_set_auxiliary_series" : "dynamic_set_auxiliary_series";
5484 string filename = julia ? func_name + ".jl" : packageDir(basename) + "/" + func_name + ".m";
5485 string comment = julia ? "#" : "%";
5486
5487 ofstream output;
5488 output.open(filename, ios::out | ios::binary);
5489 if (!output.is_open())
5490 {
5491 cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
5492 exit(EXIT_FAILURE);
5493 }
5494
5495 output << "function ds = " << func_name + "(ds, params)" << endl
5496 << comment << endl
5497 << comment << " Status : Computes Auxiliary variables of the dynamic model and returns a dseries" << endl
5498 << comment << endl
5499 << comment << " Warning : this file is generated automatically by Dynare" << endl
5500 << comment << " from model file (.mod)" << endl << endl
5501 << output_func_body.str();
5502
5503 output.close();
5504 }
5505
5506 void
writeAuxVarRecursiveDefinitions(ostream & output,ExprNodeOutputType output_type) const5507 DynamicModel::writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputType output_type) const
5508 {
5509 deriv_node_temp_terms_t tef_terms;
5510 temporary_terms_t temporary_terms;
5511 temporary_terms_idxs_t temporary_terms_idxs;
5512 for (auto aux_eq : aux_equations)
5513 if (auto aux_eq2 = dynamic_cast<ExprNode *>(aux_eq);
5514 aux_eq2->containsExternalFunction())
5515 aux_eq2->writeExternalFunctionOutput(output, output_type, temporary_terms,
5516 temporary_terms_idxs, tef_terms);
5517 for (auto aux_eq : aux_equations)
5518 {
5519 dynamic_cast<ExprNode *>(aux_eq)->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
5520 output << ";" << endl;
5521 }
5522 }
5523
5524 void
clearEquations()5525 DynamicModel::clearEquations()
5526 {
5527 equations.clear();
5528 equations_lineno.clear();
5529 equation_tags.clear();
5530 equation_tags_xref.clear();
5531 }
5532
5533 void
replaceMyEquations(DynamicModel & dynamic_model) const5534 DynamicModel::replaceMyEquations(DynamicModel &dynamic_model) const
5535 {
5536 dynamic_model.clearEquations();
5537
5538 for (size_t i = 0; i < equations.size(); i++)
5539 dynamic_model.addEquation(equations[i]->clone(dynamic_model), equations_lineno[i]);
5540
5541 dynamic_model.equation_tags = equation_tags;
5542 dynamic_model.equation_tags_xref = equation_tags_xref;
5543 }
5544
5545 void
computeRamseyPolicyFOCs(const StaticModel & static_model)5546 DynamicModel::computeRamseyPolicyFOCs(const StaticModel &static_model)
5547 {
5548 // Add aux LM to constraints in equations
5549 // equation[i]->lhs = rhs becomes equation[i]->MULT_(i+1)*(lhs-rhs) = 0
5550 int i;
5551 for (i = 0; i < static_cast<int>(equations.size()); i++)
5552 {
5553 auto substeq = dynamic_cast<BinaryOpNode *>(equations[i]->addMultipliersToConstraints(i));
5554 assert(substeq);
5555 equations[i] = substeq;
5556 }
5557 cout << "Ramsey Problem: added " << i << " Multipliers." << endl;
5558
5559 // Add Planner Objective to equations so that it appears in Lagrangian
5560 assert(static_model.equations.size() == 1);
5561 addEquation(static_model.equations[0]->clone(*this), -1);
5562
5563 // Get max endo lead and max endo lag
5564 set<pair<int, int>> dynvars;
5565 int max_eq_lead = 0;
5566 int max_eq_lag = 0;
5567 for (auto &equation : equations)
5568 equation->collectDynamicVariables(SymbolType::endogenous, dynvars);
5569
5570 for (const auto &[symb_id, lag] : dynvars)
5571 {
5572 if (max_eq_lead < lag)
5573 max_eq_lead = lag;
5574 else if (-max_eq_lag > lag)
5575 max_eq_lag = -lag;
5576 }
5577
5578 // Get Discount Factor
5579 assert(symbol_table.exists("optimal_policy_discount_factor"));
5580 int symb_id = symbol_table.getID("optimal_policy_discount_factor");
5581 assert(symbol_table.getType(symb_id) == SymbolType::parameter);
5582 expr_t discount_factor_node = AddVariable(symb_id, 0);
5583
5584 // Create (modified) Lagrangian (so that we can take the derivative once at time t)
5585 expr_t lagrangian = Zero;
5586 for (i = 0; i < static_cast<int>(equations.size()); i++)
5587 for (int lag = -max_eq_lag; lag <= max_eq_lead; lag++)
5588 {
5589 expr_t dfpower = nullptr;
5590 stringstream lagstream;
5591 lagstream << abs(lag);
5592 if (lag < 0)
5593 dfpower = AddNonNegativeConstant(lagstream.str());
5594 else if (lag == 0)
5595 dfpower = Zero;
5596 else
5597 dfpower = AddMinus(Zero, AddNonNegativeConstant(lagstream.str()));
5598
5599 lagrangian = AddPlus(AddTimes(AddPower(discount_factor_node, dfpower),
5600 equations[i]->getNonZeroPartofEquation()->decreaseLeadsLags(lag)), lagrangian);
5601 }
5602
5603 // Save line numbers and tags, see below
5604 auto old_equations_lineno = equations_lineno;
5605 auto old_equation_tags = equation_tags;
5606
5607 // Prepare derivation of the Lagrangian
5608 clearEquations();
5609 addEquation(AddEqual(lagrangian, Zero), -1);
5610 computeDerivIDs();
5611
5612 /* Compute Lagrangian derivatives.
5613 Also restore line numbers and tags for FOCs w.r.t. a Lagrange multiplier
5614 (i.e. a FOC identical to an equation of the original model) */
5615 vector<expr_t> neweqs;
5616 vector<int> neweqs_lineno;
5617 map<int, vector<pair<string, string>>> neweqs_tags;
5618 for (auto &[symb_id_and_lag, deriv_id] : deriv_id_table)
5619 {
5620 auto &[symb_id, lag] = symb_id_and_lag;
5621 if (symbol_table.getType(symb_id) == SymbolType::endogenous && lag == 0)
5622 {
5623 neweqs.push_back(AddEqual(equations[0]->getNonZeroPartofEquation()->getDerivative(deriv_id), Zero));
5624 if (int i = symbol_table.getEquationNumberForMultiplier(symb_id);
5625 i != -1)
5626 {
5627 // This is a derivative w.r.t. a Lagrange multiplier
5628 neweqs_lineno.push_back(old_equations_lineno[i]);
5629 vector<pair<string, string>> tags;
5630 for (auto &[j, tagpair] : old_equation_tags)
5631 if (j == i)
5632 tags.emplace_back(tagpair);
5633 neweqs_tags[neweqs.size()-1] = tags;
5634 }
5635 else
5636 neweqs_lineno.push_back(-1);
5637 }
5638 }
5639
5640 // Overwrite equations with the Lagrangian derivatives
5641 clearEquations();
5642 for (size_t i = 0; i < neweqs.size(); i++)
5643 addEquation(neweqs[i], neweqs_lineno[i], neweqs_tags[i]);
5644 }
5645
5646 void
toNonlinearPart(DynamicModel & non_linear_equations_dynamic_model) const5647 DynamicModel::toNonlinearPart(DynamicModel &non_linear_equations_dynamic_model) const
5648 {
5649 // Convert model local variables (need to be done first)
5650 for (const auto &it : local_variables_table)
5651 non_linear_equations_dynamic_model.AddLocalVariable(it.first, it.second);
5652 }
5653
5654 bool
ParamUsedWithLeadLag() const5655 DynamicModel::ParamUsedWithLeadLag() const
5656 {
5657 return ParamUsedWithLeadLagInternal();
5658 }
5659
5660 void
createVariableMapping(int orig_eq_nbr)5661 DynamicModel::createVariableMapping(int orig_eq_nbr)
5662 {
5663 for (int ii = 0; ii < orig_eq_nbr; ii++)
5664 {
5665 set<int> eqvars;
5666 equations[ii]->collectVariables(SymbolType::endogenous, eqvars);
5667 equations[ii]->collectVariables(SymbolType::exogenous, eqvars);
5668 for (auto eqvar : eqvars)
5669 {
5670 eqvar = symbol_table.getUltimateOrigSymbID(eqvar);
5671 if (eqvar >= 0 && !symbol_table.isAuxiliaryVariable(eqvar))
5672 variableMapping[eqvar].emplace(ii);
5673 }
5674 }
5675 }
5676
5677 void
expandEqTags()5678 DynamicModel::expandEqTags()
5679 {
5680 set<int> existing_tags;
5681 for (const auto &eqn : equation_tags)
5682 if (eqn.second.first == "name")
5683 existing_tags.insert(eqn.first);
5684
5685 for (int eq = 0; eq < static_cast<int>(equations.size()); eq++)
5686 if (existing_tags.find(eq) == existing_tags.end())
5687 if (auto lhs_expr = dynamic_cast<VariableNode *>(equations[eq]->arg1); lhs_expr && equation_tags_xref.find({ "name", symbol_table.getName(lhs_expr->symb_id)}) == equation_tags_xref.end())
5688 {
5689 equation_tags.emplace_back(eq, pair("name", symbol_table.getName(lhs_expr->symb_id)));
5690 equation_tags_xref.emplace(pair("name", symbol_table.getName(lhs_expr->symb_id)), eq);
5691 }
5692 else if (equation_tags_xref.find({ "name", to_string(eq+1) }) == equation_tags_xref.end())
5693 {
5694 equation_tags.emplace_back(eq, pair("name", to_string(eq+1)));
5695 equation_tags_xref.emplace(pair("name", to_string(eq+1)), eq);
5696 }
5697 else
5698 {
5699 cerr << "Error creating default equation tag: cannot assign default tag to equation number " << eq+1 << " because it is already in use" << endl;
5700 exit(EXIT_FAILURE);
5701 }
5702
5703 sort(equation_tags.begin(), equation_tags.end());
5704 }
5705
5706 set<int>
findUnusedEndogenous()5707 DynamicModel::findUnusedEndogenous()
5708 {
5709 set<int> usedEndo, unusedEndo;
5710 for (auto &equation : equations)
5711 equation->collectVariables(SymbolType::endogenous, usedEndo);
5712 set<int> allEndo = symbol_table.getEndogenous();
5713 set_difference(allEndo.begin(), allEndo.end(),
5714 usedEndo.begin(), usedEndo.end(),
5715 inserter(unusedEndo, unusedEndo.begin()));
5716 return unusedEndo;
5717 }
5718
5719 set<int>
findUnusedExogenous()5720 DynamicModel::findUnusedExogenous()
5721 {
5722 set<int> usedExo, unusedExo, unobservedExo;
5723 for (auto &equation : equations)
5724 equation->collectVariables(SymbolType::exogenous, usedExo);
5725 set<int> observedExo = symbol_table.getObservedExogenous();
5726 set<int> allExo = symbol_table.getExogenous();
5727 set_difference(allExo.begin(), allExo.end(),
5728 observedExo.begin(), observedExo.end(),
5729 inserter(unobservedExo, unobservedExo.begin()));
5730 set_difference(unobservedExo.begin(), unobservedExo.end(),
5731 usedExo.begin(), usedExo.end(),
5732 inserter(unusedExo, unusedExo.begin()));
5733 return unusedExo;
5734 }
5735
5736 void
setLeadsLagsOrig()5737 DynamicModel::setLeadsLagsOrig()
5738 {
5739 set<pair<int, int>> dynvars;
5740
5741 for (auto &equation : equations)
5742 {
5743 equation->collectDynamicVariables(SymbolType::endogenous, dynvars);
5744 equation->collectDynamicVariables(SymbolType::exogenous, dynvars);
5745 equation->collectDynamicVariables(SymbolType::exogenousDet, dynvars);
5746
5747 max_lag_with_diffs_expanded_orig = max(equation->maxLagWithDiffsExpanded(),
5748 max_lag_with_diffs_expanded_orig);
5749 }
5750
5751 for (const auto &dynvar : dynvars)
5752 {
5753 int lag = dynvar.second;
5754 SymbolType type = symbol_table.getType(dynvar.first);
5755
5756 max_lead_orig = max(lag, max_lead_orig);
5757 max_lag_orig = max(-lag, max_lag_orig);
5758
5759 switch (type)
5760 {
5761 case SymbolType::endogenous:
5762 max_endo_lead_orig = max(lag, max_endo_lead_orig);
5763 max_endo_lag_orig = max(-lag, max_endo_lag_orig);
5764 break;
5765 case SymbolType::exogenous:
5766 max_exo_lead_orig = max(lag, max_exo_lead_orig);
5767 max_exo_lag_orig = max(-lag, max_exo_lag_orig);
5768 break;
5769 case SymbolType::exogenousDet:
5770 max_exo_det_lead_orig = max(lag, max_exo_det_lead_orig);
5771 max_exo_det_lag_orig = max(-lag, max_exo_det_lag_orig);
5772 break;
5773 default:
5774 break;
5775 }
5776 }
5777 }
5778
5779 void
computeDerivIDs()5780 DynamicModel::computeDerivIDs()
5781 {
5782 set<pair<int, int>> dynvars;
5783
5784 for (auto &equation : equations)
5785 equation->collectDynamicVariables(SymbolType::endogenous, dynvars);
5786
5787 dynJacobianColsNbr = dynvars.size();
5788
5789 for (auto &equation : equations)
5790 {
5791 equation->collectDynamicVariables(SymbolType::exogenous, dynvars);
5792 equation->collectDynamicVariables(SymbolType::exogenousDet, dynvars);
5793 equation->collectDynamicVariables(SymbolType::parameter, dynvars);
5794 equation->collectDynamicVariables(SymbolType::trend, dynvars);
5795 equation->collectDynamicVariables(SymbolType::logTrend, dynvars);
5796 }
5797
5798 for (const auto &dynvar : dynvars)
5799 {
5800 int lag = dynvar.second;
5801 SymbolType type = symbol_table.getType(dynvar.first);
5802
5803 /* Setting maximum and minimum lags.
5804
5805 We don't want these to be affected by lead/lags on parameters: they
5806 are accepted for facilitating variable flipping, but are simply
5807 ignored. */
5808 if (type != SymbolType::parameter)
5809 {
5810 max_lead = max(lag, max_lead);
5811 max_lag = max(-lag, max_lag);
5812 }
5813
5814 switch (type)
5815 {
5816 case SymbolType::endogenous:
5817 max_endo_lead = max(lag, max_endo_lead);
5818 max_endo_lag = max(-lag, max_endo_lag);
5819 break;
5820 case SymbolType::exogenous:
5821 max_exo_lead = max(lag, max_exo_lead);
5822 max_exo_lag = max(-lag, max_exo_lag);
5823 break;
5824 case SymbolType::exogenousDet:
5825 max_exo_det_lead = max(lag, max_exo_det_lead);
5826 max_exo_det_lag = max(-lag, max_exo_det_lag);
5827 break;
5828 default:
5829 break;
5830 }
5831
5832 // Create a new deriv_id
5833 int deriv_id = deriv_id_table.size();
5834
5835 deriv_id_table[dynvar] = deriv_id;
5836 inv_deriv_id_table.push_back(dynvar);
5837 }
5838 }
5839
5840 SymbolType
getTypeByDerivID(int deriv_id) const5841 DynamicModel::getTypeByDerivID(int deriv_id) const noexcept(false)
5842 {
5843 return symbol_table.getType(getSymbIDByDerivID(deriv_id));
5844 }
5845
5846 int
getLagByDerivID(int deriv_id) const5847 DynamicModel::getLagByDerivID(int deriv_id) const noexcept(false)
5848 {
5849 if (deriv_id < 0 || deriv_id >= static_cast<int>(inv_deriv_id_table.size()))
5850 throw UnknownDerivIDException();
5851
5852 return inv_deriv_id_table[deriv_id].second;
5853 }
5854
5855 int
getSymbIDByDerivID(int deriv_id) const5856 DynamicModel::getSymbIDByDerivID(int deriv_id) const noexcept(false)
5857 {
5858 if (deriv_id < 0 || deriv_id >= static_cast<int>(inv_deriv_id_table.size()))
5859 throw UnknownDerivIDException();
5860
5861 return inv_deriv_id_table[deriv_id].first;
5862 }
5863
5864 int
getDerivID(int symb_id,int lag) const5865 DynamicModel::getDerivID(int symb_id, int lag) const noexcept(false)
5866 {
5867 auto it = deriv_id_table.find({ symb_id, lag });
5868 if (it == deriv_id_table.end())
5869 throw UnknownDerivIDException();
5870 else
5871 return it->second;
5872 }
5873
5874 void
addAllParamDerivId(set<int> & deriv_id_set)5875 DynamicModel::addAllParamDerivId(set<int> &deriv_id_set)
5876 {
5877 for (size_t i = 0; i < inv_deriv_id_table.size(); i++)
5878 if (symbol_table.getType(inv_deriv_id_table[i].first) == SymbolType::parameter)
5879 deriv_id_set.insert(i);
5880 }
5881
5882 void
computeDynJacobianCols(bool jacobianExo)5883 DynamicModel::computeDynJacobianCols(bool jacobianExo)
5884 {
5885 /* Sort the dynamic endogenous variables by lexicographic order over (lag, type_specific_symbol_id)
5886 and fill the dynamic columns for exogenous and exogenous deterministic */
5887 map<pair<int, int>, int> ordered_dyn_endo;
5888
5889 for (auto &it : deriv_id_table)
5890 {
5891 int symb_id = it.first.first;
5892 int lag = it.first.second;
5893 int deriv_id = it.second;
5894 SymbolType type = symbol_table.getType(symb_id);
5895 int tsid = symbol_table.getTypeSpecificID(symb_id);
5896
5897 switch (type)
5898 {
5899 case SymbolType::endogenous:
5900 ordered_dyn_endo[{ lag, tsid }] = deriv_id;
5901 break;
5902 case SymbolType::exogenous:
5903 // At this point, dynJacobianColsNbr contains the number of dynamic endogenous
5904 if (jacobianExo)
5905 dyn_jacobian_cols_table[deriv_id] = dynJacobianColsNbr + tsid;
5906 break;
5907 case SymbolType::exogenousDet:
5908 // At this point, dynJacobianColsNbr contains the number of dynamic endogenous
5909 if (jacobianExo)
5910 dyn_jacobian_cols_table[deriv_id] = dynJacobianColsNbr + symbol_table.exo_nbr() + tsid;
5911 break;
5912 case SymbolType::parameter:
5913 case SymbolType::trend:
5914 case SymbolType::logTrend:
5915 // We don't assign a dynamic jacobian column to parameters or trend variables
5916 break;
5917 default:
5918 // Shut up GCC
5919 cerr << "DynamicModel::computeDynJacobianCols: impossible case" << endl;
5920 exit(EXIT_FAILURE);
5921 }
5922 }
5923
5924 // Fill in dynamic jacobian columns for endogenous
5925 int sorted_id = 0;
5926 for (auto &it : ordered_dyn_endo)
5927 dyn_jacobian_cols_table[it.second] = sorted_id++;
5928
5929 // Set final value for dynJacobianColsNbr
5930 if (jacobianExo)
5931 dynJacobianColsNbr += symbol_table.exo_nbr() + symbol_table.exo_det_nbr();
5932 }
5933
5934 int
getDynJacobianCol(int deriv_id) const5935 DynamicModel::getDynJacobianCol(int deriv_id) const noexcept(false)
5936 {
5937 if (auto it = dyn_jacobian_cols_table.find(deriv_id);
5938 it == dyn_jacobian_cols_table.end())
5939 throw UnknownDerivIDException();
5940 else
5941 return it->second;
5942 }
5943
5944 void
testTrendDerivativesEqualToZero(const eval_context_t & eval_context)5945 DynamicModel::testTrendDerivativesEqualToZero(const eval_context_t &eval_context)
5946 {
5947 for (auto &it : deriv_id_table)
5948 if (symbol_table.getType(it.first.first) == SymbolType::trend
5949 || symbol_table.getType(it.first.first) == SymbolType::logTrend)
5950 for (int eq = 0; eq < static_cast<int>(equations.size()); eq++)
5951 {
5952 expr_t homogeneq = AddMinus(equations[eq]->arg1,
5953 equations[eq]->arg2);
5954
5955 // Do not run the test if the term inside the log is zero
5956 if (fabs(homogeneq->eval(eval_context)) > zero_band)
5957 {
5958 expr_t testeq = AddLog(homogeneq); // F = log(lhs-rhs)
5959 testeq = testeq->getDerivative(it.second); // d F / d Trend
5960 for (auto &endogit : deriv_id_table)
5961 if (symbol_table.getType(endogit.first.first) == SymbolType::endogenous)
5962 {
5963 double nearZero = testeq->getDerivative(endogit.second)->eval(eval_context); // eval d F / d Trend d Endog
5964 if (fabs(nearZero) > balanced_growth_test_tol)
5965 {
5966 cerr << "ERROR: trends not compatible with balanced growth path; the second-order cross partial of equation " << eq + 1 << " (line "
5967 << equations_lineno[eq] << ") w.r.t. trend variable "
5968 << symbol_table.getName(it.first.first) << " and endogenous variable "
5969 << symbol_table.getName(endogit.first.first) << " is not null (abs. value = "
5970 << fabs(nearZero) << "). If you are confident that your trends are correctly specified, you can raise the value of option 'balanced_growth_test_tol' in the 'model' block." << endl;
5971 exit(EXIT_FAILURE);
5972 }
5973 }
5974 }
5975 }
5976 }
5977
5978 void
writeParamsDerivativesFile(const string & basename,bool julia) const5979 DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) const
5980 {
5981 if (!params_derivatives.size())
5982 return;
5983
5984 ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaDynamicModel : ExprNodeOutputType::matlabDynamicModel);
5985 ostringstream tt_output; // Used for storing model temp vars and equations
5986 ostringstream rp_output; // 1st deriv. of residuals w.r.t. parameters
5987 ostringstream gp_output; // 1st deriv. of Jacobian w.r.t. parameters
5988 ostringstream rpp_output; // 2nd deriv of residuals w.r.t. parameters
5989 ostringstream gpp_output; // 2nd deriv of Jacobian w.r.t. parameters
5990 ostringstream hp_output; // 1st deriv. of Hessian w.r.t. parameters
5991 ostringstream g3p_output; // 1st deriv. of 3rd deriv. matrix w.r.t. parameters
5992
5993 temporary_terms_t temp_term_union;
5994 deriv_node_temp_terms_t tef_terms;
5995
5996 writeModelLocalVariableTemporaryTerms(temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms);
5997 for (const auto &it : params_derivs_temporary_terms)
5998 writeTemporaryTerms(it.second, temp_term_union, params_derivs_temporary_terms_idxs, tt_output, output_type, tef_terms);
5999
6000 for (const auto & [indices, d1] : params_derivatives.find({ 0, 1 })->second)
6001 {
6002 auto [eq, param] = vectorToTuple<2>(indices);
6003
6004 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
6005
6006 rp_output << "rp" << LEFT_ARRAY_SUBSCRIPT(output_type) << eq+1 << ", " << param_col
6007 << RIGHT_ARRAY_SUBSCRIPT(output_type) << " = ";
6008 d1->writeOutput(rp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6009 rp_output << ";" << endl;
6010 }
6011
6012 for (const auto & [indices, d2] : params_derivatives.find({ 1, 1 })->second)
6013 {
6014 auto [eq, var, param] = vectorToTuple<3>(indices);
6015
6016 int var_col = getDynJacobianCol(var) + 1;
6017 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
6018
6019 gp_output << "gp" << LEFT_ARRAY_SUBSCRIPT(output_type) << eq+1 << ", " << var_col
6020 << ", " << param_col << RIGHT_ARRAY_SUBSCRIPT(output_type) << " = ";
6021 d2->writeOutput(gp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6022 gp_output << ";" << endl;
6023 }
6024
6025 int i = 1;
6026 for (const auto &[indices, d2] : params_derivatives.find({ 0, 2 })->second)
6027 {
6028 auto [eq, param1, param2] = vectorToTuple<3>(indices);
6029
6030 int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
6031 int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
6032
6033 rpp_output << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6034 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6035 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6036 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
6037 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6038 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
6039 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6040 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
6041 d2->writeOutput(rpp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6042 rpp_output << ";" << endl;
6043
6044 i++;
6045
6046 if (param1 != param2)
6047 {
6048 // Treat symmetric elements
6049 rpp_output << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6050 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6051 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6052 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
6053 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6054 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
6055 << "rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6056 << RIGHT_ARRAY_SUBSCRIPT(output_type)
6057 << "=rpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",4"
6058 << RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
6059 i++;
6060 }
6061 }
6062
6063 i = 1;
6064 for (const auto &[indices, d2] : params_derivatives.find({ 1, 2 })->second)
6065 {
6066 auto [eq, var, param1, param2] = vectorToTuple<4>(indices);
6067
6068 int var_col = getDynJacobianCol(var) + 1;
6069 int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
6070 int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
6071
6072 gpp_output << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6073 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6074 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6075 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var_col << ";" << endl
6076 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6077 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
6078 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6079 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
6080 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
6081 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
6082 d2->writeOutput(gpp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6083 gpp_output << ";" << endl;
6084
6085 i++;
6086
6087 if (param1 != param2)
6088 {
6089 // Treat symmetric elements
6090 gpp_output << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6091 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6092 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6093 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var_col << ";" << endl
6094 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6095 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param2_col << ";" << endl
6096 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6097 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param1_col << ";" << endl
6098 << "gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
6099 << RIGHT_ARRAY_SUBSCRIPT(output_type)
6100 << "=gpp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",5"
6101 << RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
6102 i++;
6103 }
6104 }
6105
6106 i = 1;
6107 for (const auto &[indices, d2] : params_derivatives.find({ 2, 1 })->second)
6108 {
6109 auto [eq, var1, var2, param] = vectorToTuple<4>(indices);
6110
6111 int var1_col = getDynJacobianCol(var1) + 1;
6112 int var2_col = getDynJacobianCol(var2) + 1;
6113 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
6114
6115 hp_output << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6116 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6117 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6118 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
6119 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6120 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
6121 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6122 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
6123 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
6124 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
6125 d2->writeOutput(hp_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6126 hp_output << ";" << endl;
6127
6128 i++;
6129
6130 if (var1 != var2)
6131 {
6132 // Treat symmetric elements
6133 hp_output << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6134 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6135 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6136 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
6137 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6138 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
6139 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6140 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
6141 << "hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
6142 << RIGHT_ARRAY_SUBSCRIPT(output_type)
6143 << "=hp" << LEFT_ARRAY_SUBSCRIPT(output_type) << i-1 << ",5"
6144 << RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
6145 i++;
6146 }
6147 }
6148
6149 i = 1;
6150 for (const auto &[indices, d2] : params_derivatives.find({ 3, 1 })->second)
6151 {
6152 auto [eq, var1, var2, var3, param] = vectorToTuple<5>(indices);
6153
6154 int var1_col = getDynJacobianCol(var1) + 1;
6155 int var2_col = getDynJacobianCol(var2) + 1;
6156 int var3_col = getDynJacobianCol(var3) + 1;
6157 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
6158
6159 g3p_output << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",1"
6160 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << eq+1 << ";" << endl
6161 << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",2"
6162 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var1_col << ";" << endl
6163 << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",3"
6164 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var2_col << ";" << endl
6165 << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",4"
6166 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << var3_col << ";" << endl
6167 << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",5"
6168 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=" << param_col << ";" << endl
6169 << "g3p" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << ",6"
6170 << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
6171 d2->writeOutput(g3p_output, output_type, temp_term_union, params_derivs_temporary_terms_idxs, tef_terms);
6172 g3p_output << ";" << endl;
6173
6174 i++;
6175 }
6176
6177 string filename = julia ? basename + "DynamicParamsDerivs.jl" : packageDir(basename) + "/dynamic_params_derivs.m";
6178 ofstream paramsDerivsFile;
6179 paramsDerivsFile.open(filename, ios::out | ios::binary);
6180 if (!paramsDerivsFile.is_open())
6181 {
6182 cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
6183 exit(EXIT_FAILURE);
6184 }
6185
6186 if (!julia)
6187 {
6188 // Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
6189 map<string, string> tmp_paren_vars;
6190 bool message_printed = false;
6191 fixNestedParenthesis(tt_output, tmp_paren_vars, message_printed);
6192 fixNestedParenthesis(rp_output, tmp_paren_vars, message_printed);
6193 fixNestedParenthesis(gp_output, tmp_paren_vars, message_printed);
6194 fixNestedParenthesis(rpp_output, tmp_paren_vars, message_printed);
6195 fixNestedParenthesis(gpp_output, tmp_paren_vars, message_printed);
6196 fixNestedParenthesis(hp_output, tmp_paren_vars, message_printed);
6197 fixNestedParenthesis(g3p_output, tmp_paren_vars, message_printed);
6198 paramsDerivsFile << "function [rp, gp, rpp, gpp, hp, g3p] = dynamic_params_derivs(y, x, params, steady_state, it_, ss_param_deriv, ss_param_2nd_deriv)" << endl
6199 << "%" << endl
6200 << "% Compute the derivatives of the dynamic model with respect to the parameters" << endl
6201 << "% Inputs :" << endl
6202 << "% y [#dynamic variables by 1] double vector of endogenous variables in the order stored" << endl
6203 << "% in M_.lead_lag_incidence; see the Manual" << endl
6204 << "% x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in declaration order)" << endl
6205 << "% for all simulation periods" << endl
6206 << "% params [M_.param_nbr by 1] double vector of parameter values in declaration order" << endl
6207 << "% steady_state [M_.endo_nbr by 1] double vector of steady state values" << endl
6208 << "% it_ scalar double time period for exogenous variables for which to evaluate the model" << endl
6209 << "% ss_param_deriv [M_.eq_nbr by #params] Jacobian matrix of the steady states values with respect to the parameters" << endl
6210 << "% ss_param_2nd_deriv [M_.eq_nbr by #params by #params] Hessian matrix of the steady states values with respect to the parameters" << endl
6211 << "%" << endl
6212 << "% Outputs:" << endl
6213 << "% rp [M_.eq_nbr by #params] double Jacobian matrix of dynamic model equations with respect to parameters " << endl
6214 << "% Dynare may prepend or append auxiliary equations, see M_.aux_vars" << endl
6215 << "% gp [M_.endo_nbr by #dynamic variables by #params] double Derivative of the Jacobian matrix of the dynamic model equations with respect to the parameters" << endl
6216 << "% rows: equations in order of declaration" << endl
6217 << "% columns: variables in order stored in M_.lead_lag_incidence" << endl
6218 << "% rpp [#second_order_residual_terms by 4] double Hessian matrix of second derivatives of residuals with respect to parameters;" << endl
6219 << "% rows: respective derivative term" << endl
6220 << "% 1st column: equation number of the term appearing" << endl
6221 << "% 2nd column: number of the first parameter in derivative" << endl
6222 << "% 3rd column: number of the second parameter in derivative" << endl
6223 << "% 4th column: value of the Hessian term" << endl
6224 << "% gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second derivatives of the Jacobian with respect to the parameters;" << endl
6225 << "% rows: respective derivative term" << endl
6226 << "% 1st column: equation number of the term appearing" << endl
6227 << "% 2nd column: column number of variable in Jacobian of the dynamic model" << endl
6228 << "% 3rd column: number of the first parameter in derivative" << endl
6229 << "% 4th column: number of the second parameter in derivative" << endl
6230 << "% 5th column: value of the Hessian term" << endl
6231 << "% hp [#first_order_Hessian_terms by 5] double Jacobian matrix of derivatives of the dynamic Hessian with respect to the parameters;" << endl
6232 << "% rows: respective derivative term" << endl
6233 << "% 1st column: equation number of the term appearing" << endl
6234 << "% 2nd column: column number of first variable in Hessian of the dynamic model" << endl
6235 << "% 3rd column: column number of second variable in Hessian of the dynamic model" << endl
6236 << "% 4th column: number of the parameter in derivative" << endl
6237 << "% 5th column: value of the Hessian term" << endl
6238 << "% g3p [#first_order_g3_terms by 6] double Jacobian matrix of derivatives of g3 (dynamic 3rd derivs) with respect to the parameters;" << endl
6239 << "% rows: respective derivative term" << endl
6240 << "% 1st column: equation number of the term appearing" << endl
6241 << "% 2nd column: column number of first variable in g3 of the dynamic model" << endl
6242 << "% 3rd column: column number of second variable in g3 of the dynamic model" << endl
6243 << "% 4th column: column number of third variable in g3 of the dynamic model" << endl
6244 << "% 5th column: number of the parameter in derivative" << endl
6245 << "% 6th column: value of the Hessian term" << endl
6246 << "%" << endl
6247 << "%" << endl
6248 << "% Warning : this file is generated automatically by Dynare" << endl
6249 << "% from model file (.mod)" << endl << endl
6250 << "T = NaN(" << params_derivs_temporary_terms_idxs.size() << ",1);" << endl
6251 << tt_output.str()
6252 << "rp = zeros(" << equations.size() << ", "
6253 << symbol_table.param_nbr() << ");" << endl
6254 << rp_output.str()
6255 << "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl
6256 << gp_output.str()
6257 << "if nargout >= 3" << endl
6258 << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
6259 << rpp_output.str()
6260 << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
6261 << gpp_output.str()
6262 << "end" << endl
6263 << "if nargout >= 5" << endl
6264 << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
6265 << hp_output.str()
6266 << "end" << endl
6267 << "if nargout >= 6" << endl
6268 << "g3p = zeros(" << params_derivatives.find({ 3, 1 })->second.size() << ",6);" << endl
6269 << g3p_output.str()
6270 << "end" << endl
6271 << "end" << endl;
6272 }
6273 else
6274 paramsDerivsFile << "module " << basename << "DynamicParamsDerivs" << endl
6275 << "#" << endl
6276 << "# NB: this file was automatically generated by Dynare" << endl
6277 << "# from " << basename << ".mod" << endl
6278 << "#" << endl
6279 << "export params_derivs" << endl << endl
6280 << "function params_derivs(y, x, paramssteady_state, it_, "
6281 << "ss_param_deriv, ss_param_2nd_deriv)" << endl
6282 << tt_output.str()
6283 << "rp = zeros(" << equations.size() << ", "
6284 << symbol_table.param_nbr() << ");" << endl
6285 << rp_output.str()
6286 << "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl
6287 << gp_output.str()
6288 << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
6289 << rpp_output.str()
6290 << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
6291 << gpp_output.str()
6292 << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
6293 << hp_output.str()
6294 << "g3p = zeros(" << params_derivatives.find({ 3, 1 })->second.size() << ",6);" << endl
6295 << g3p_output.str()
6296 << "(rp, gp, rpp, gpp, hp, g3p)" << endl
6297 << "end" << endl
6298 << "end" << endl;
6299
6300 paramsDerivsFile.close();
6301 }
6302
6303 void
writeLatexFile(const string & basename,bool write_equation_tags) const6304 DynamicModel::writeLatexFile(const string &basename, bool write_equation_tags) const
6305 {
6306 writeLatexModelFile(basename, "dynamic", ExprNodeOutputType::latexDynamicModel, write_equation_tags);
6307 }
6308
6309 void
writeLatexOriginalFile(const string & basename,bool write_equation_tags) const6310 DynamicModel::writeLatexOriginalFile(const string &basename, bool write_equation_tags) const
6311 {
6312 writeLatexModelFile(basename, "original", ExprNodeOutputType::latexDynamicModel, write_equation_tags);
6313 }
6314
6315 void
substituteEndoLeadGreaterThanTwo(bool deterministic_model)6316 DynamicModel::substituteEndoLeadGreaterThanTwo(bool deterministic_model)
6317 {
6318 substituteLeadLagInternal(AuxVarType::endoLead, deterministic_model, {});
6319 }
6320
6321 void
substituteEndoLagGreaterThanTwo(bool deterministic_model)6322 DynamicModel::substituteEndoLagGreaterThanTwo(bool deterministic_model)
6323 {
6324 substituteLeadLagInternal(AuxVarType::endoLag, deterministic_model, {});
6325 }
6326
6327 void
substituteExoLead(bool deterministic_model)6328 DynamicModel::substituteExoLead(bool deterministic_model)
6329 {
6330 substituteLeadLagInternal(AuxVarType::exoLead, deterministic_model, {});
6331 }
6332
6333 void
substituteExoLag(bool deterministic_model)6334 DynamicModel::substituteExoLag(bool deterministic_model)
6335 {
6336 substituteLeadLagInternal(AuxVarType::exoLag, deterministic_model, {});
6337 }
6338
6339 void
substituteLeadLagInternal(AuxVarType type,bool deterministic_model,const vector<string> & subset)6340 DynamicModel::substituteLeadLagInternal(AuxVarType type, bool deterministic_model, const vector<string> &subset)
6341 {
6342 ExprNode::subst_table_t subst_table;
6343 vector<BinaryOpNode *> neweqs;
6344
6345 // Substitute in used model local variables
6346 set<int> used_local_vars;
6347 for (auto &equation : equations)
6348 equation->collectVariables(SymbolType::modelLocalVariable, used_local_vars);
6349
6350 for (int used_local_var : used_local_vars)
6351 {
6352 const expr_t value = local_variables_table.find(used_local_var)->second;
6353 expr_t subst;
6354 switch (type)
6355 {
6356 case AuxVarType::endoLead:
6357 subst = value->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model);
6358 break;
6359 case AuxVarType::endoLag:
6360 subst = value->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
6361 break;
6362 case AuxVarType::exoLead:
6363 subst = value->substituteExoLead(subst_table, neweqs, deterministic_model);
6364 break;
6365 case AuxVarType::exoLag:
6366 subst = value->substituteExoLag(subst_table, neweqs);
6367 break;
6368 case AuxVarType::diffForward:
6369 subst = value->differentiateForwardVars(subset, subst_table, neweqs);
6370 break;
6371 default:
6372 cerr << "DynamicModel::substituteLeadLagInternal: impossible case" << endl;
6373 exit(EXIT_FAILURE);
6374 }
6375 local_variables_table[used_local_var] = subst;
6376 }
6377
6378 // Substitute in equations
6379 for (auto &equation : equations)
6380 {
6381 expr_t subst;
6382 switch (type)
6383 {
6384 case AuxVarType::endoLead:
6385 subst = equation->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model);
6386 break;
6387 case AuxVarType::endoLag:
6388 subst = equation->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
6389 break;
6390 case AuxVarType::exoLead:
6391 subst = equation->substituteExoLead(subst_table, neweqs, deterministic_model);
6392 break;
6393 case AuxVarType::exoLag:
6394 subst = equation->substituteExoLag(subst_table, neweqs);
6395 break;
6396 case AuxVarType::diffForward:
6397 subst = equation->differentiateForwardVars(subset, subst_table, neweqs);
6398 break;
6399 default:
6400 cerr << "DynamicModel::substituteLeadLagInternal: impossible case" << endl;
6401 exit(EXIT_FAILURE);
6402 }
6403 auto substeq = dynamic_cast<BinaryOpNode *>(subst);
6404 assert(substeq);
6405 equation = substeq;
6406 }
6407
6408 // Add new equations
6409 for (auto &neweq : neweqs)
6410 {
6411 addEquation(neweq, -1);
6412 aux_equations.push_back(neweq);
6413 }
6414
6415 if (neweqs.size() > 0)
6416 {
6417 cout << "Substitution of ";
6418 switch (type)
6419 {
6420 case AuxVarType::endoLead:
6421 cout << "endo leads >= 2";
6422 break;
6423 case AuxVarType::endoLag:
6424 cout << "endo lags >= 2";
6425 break;
6426 case AuxVarType::exoLead:
6427 cout << "exo leads";
6428 break;
6429 case AuxVarType::exoLag:
6430 cout << "exo lags";
6431 break;
6432 case AuxVarType::expectation:
6433 cout << "expectation";
6434 break;
6435 case AuxVarType::diffForward:
6436 cout << "forward vars";
6437 break;
6438 default:
6439 cerr << "DynamicModel::substituteLeadLagInternal: impossible case" << endl;
6440 exit(EXIT_FAILURE);
6441 }
6442 cout << ": added " << neweqs.size() << " auxiliary variables and equations." << endl;
6443 }
6444 }
6445
6446 void
substituteAdl()6447 DynamicModel::substituteAdl()
6448 {
6449 /* Contrary to other substitution methods, we do the substitution in MLV
6450 definitions here, instead of doing it at the ExprNode method level,
6451 because otherwise this would substitute MLV in the original model (see
6452 #65). */
6453 for (auto &[id, definition] : local_variables_table)
6454 definition = definition->substituteAdl();
6455
6456 for (auto &equation : equations)
6457 equation = dynamic_cast<BinaryOpNode *>(equation->substituteAdl());
6458 }
6459
6460 vector<int>
getEquationNumbersFromTags(const set<string> & eqtags) const6461 DynamicModel::getEquationNumbersFromTags(const set<string> &eqtags) const
6462 {
6463 vector<int> eqnumbers;
6464 for (auto &eqtag : eqtags)
6465 {
6466 bool found = false;
6467 for (const auto &equation_tag : equation_tags)
6468 if (equation_tag.second.first == "name"
6469 && equation_tag.second.second == eqtag)
6470 {
6471 found = true;
6472 eqnumbers.push_back(equation_tag.first);
6473 break;
6474 }
6475 if (!found)
6476 {
6477 cerr << "ERROR: looking for equation tag " << eqtag << " failed." << endl;
6478 exit(EXIT_FAILURE);
6479 }
6480 }
6481 return eqnumbers;
6482 }
6483
6484 void
findPacExpectationEquationNumbers(vector<int> & eqnumbers) const6485 DynamicModel::findPacExpectationEquationNumbers(vector<int> &eqnumbers) const
6486 {
6487 int i = 0;
6488 for (auto &equation : equations)
6489 {
6490 if (equation->containsPacExpectation()
6491 && find(eqnumbers.begin(), eqnumbers.end(), i) == eqnumbers.end())
6492 eqnumbers.push_back(i);
6493 i++;
6494 }
6495 }
6496
6497 pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteUnaryOps()6498 DynamicModel::substituteUnaryOps()
6499 {
6500 vector<int> eqnumbers(equations.size());
6501 iota(eqnumbers.begin(), eqnumbers.end(), 0);
6502 return substituteUnaryOps(eqnumbers);
6503 }
6504
6505 pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteUnaryOps(const set<string> & var_model_eqtags)6506 DynamicModel::substituteUnaryOps(const set<string> &var_model_eqtags)
6507 {
6508 vector<int> eqnumbers = getEquationNumbersFromTags(var_model_eqtags);
6509 findPacExpectationEquationNumbers(eqnumbers);
6510 return substituteUnaryOps(eqnumbers);
6511 }
6512
6513 pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteUnaryOps(const vector<int> & eqnumbers)6514 DynamicModel::substituteUnaryOps(const vector<int> &eqnumbers)
6515 {
6516 lag_equivalence_table_t nodes;
6517 ExprNode::subst_table_t subst_table;
6518
6519 // Mark unary ops to be substituted in model local variables that appear in selected equations
6520 set<int> used_local_vars;
6521 for (int eqnumber : eqnumbers)
6522 equations[eqnumber]->collectVariables(SymbolType::modelLocalVariable, used_local_vars);
6523 for (auto &it : local_variables_table)
6524 if (used_local_vars.find(it.first) != used_local_vars.end())
6525 it.second->findUnaryOpNodesForAuxVarCreation(nodes);
6526
6527 // Mark unary ops to be substituted in selected equations
6528 for (int eqnumber : eqnumbers)
6529 equations[eqnumber]->findUnaryOpNodesForAuxVarCreation(nodes);
6530
6531 // Substitute in model local variables
6532 vector<BinaryOpNode *> neweqs;
6533 for (auto &it : local_variables_table)
6534 it.second = it.second->substituteUnaryOpNodes(nodes, subst_table, neweqs);
6535
6536 // Substitute in equations
6537 for (auto &equation : equations)
6538 {
6539 auto substeq = dynamic_cast<BinaryOpNode *>(equation->
6540 substituteUnaryOpNodes(nodes, subst_table, neweqs));
6541 assert(substeq);
6542 equation = substeq;
6543 }
6544
6545 // Add new equations
6546 for (auto &neweq : neweqs)
6547 {
6548 addEquation(neweq, -1);
6549 aux_equations.push_back(neweq);
6550 }
6551
6552 if (subst_table.size() > 0)
6553 cout << "Substitution of Unary Ops: added " << neweqs.size() << " auxiliary variables and equations." << endl;
6554
6555 return { nodes, subst_table };
6556 }
6557
6558 pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteDiff(vector<expr_t> & pac_growth)6559 DynamicModel::substituteDiff(vector<expr_t> &pac_growth)
6560 {
6561 /* Note: at this point, we know that there is no diff operator with a lead,
6562 because they have been expanded by DataTree::AddDiff().
6563 Hence we can go forward with the substitution without worrying about the
6564 expectation operator. */
6565
6566 lag_equivalence_table_t diff_nodes;
6567 ExprNode::subst_table_t diff_subst_table;
6568
6569 // Mark diff operators to be substituted in model local variables
6570 set<int> used_local_vars;
6571 for (const auto &equation : equations)
6572 equation->collectVariables(SymbolType::modelLocalVariable, used_local_vars);
6573 for (auto &it : local_variables_table)
6574 if (used_local_vars.find(it.first) != used_local_vars.end())
6575 it.second->findDiffNodes(diff_nodes);
6576
6577 // Mark diff operators to be substituted in equations
6578 for (const auto &equation : equations)
6579 equation->findDiffNodes(diff_nodes);
6580
6581 for (const auto &gv : pac_growth)
6582 if (gv)
6583 gv->findDiffNodes(diff_nodes);
6584
6585 // Substitute in model local variables
6586 vector<BinaryOpNode *> neweqs;
6587 for (auto &it : local_variables_table)
6588 it.second = it.second->substituteDiff(diff_nodes, diff_subst_table, neweqs);
6589
6590 // Substitute in equations
6591 for (auto &equation : equations)
6592 {
6593 auto substeq = dynamic_cast<BinaryOpNode *>(equation->
6594 substituteDiff(diff_nodes, diff_subst_table, neweqs));
6595 assert(substeq);
6596 equation = substeq;
6597 }
6598
6599 for (auto &it : pac_growth)
6600 if (it)
6601 it = it->substituteDiff(diff_nodes, diff_subst_table, neweqs);
6602
6603 // Add new equations
6604 for (auto &neweq : neweqs)
6605 {
6606 addEquation(neweq, -1);
6607 aux_equations.push_back(neweq);
6608 }
6609
6610 if (diff_subst_table.size() > 0)
6611 cout << "Substitution of Diff operator: added " << neweqs.size() << " auxiliary variables and equations." << endl;
6612
6613 return { diff_nodes, diff_subst_table };
6614 }
6615
6616 void
substituteExpectation(bool partial_information_model)6617 DynamicModel::substituteExpectation(bool partial_information_model)
6618 {
6619 ExprNode::subst_table_t subst_table;
6620 vector<BinaryOpNode *> neweqs;
6621
6622 // Substitute in model local variables
6623 for (auto &it : local_variables_table)
6624 it.second = it.second->substituteExpectation(subst_table, neweqs, partial_information_model);
6625
6626 // Substitute in equations
6627 for (auto &equation : equations)
6628 {
6629 auto substeq = dynamic_cast<BinaryOpNode *>(equation->substituteExpectation(subst_table, neweqs, partial_information_model));
6630 assert(substeq);
6631 equation = substeq;
6632 }
6633
6634 // Add new equations
6635 for (auto &neweq : neweqs)
6636 {
6637 addEquation(neweq, -1);
6638 aux_equations.push_back(neweq);
6639 }
6640
6641 if (subst_table.size() > 0)
6642 {
6643 if (partial_information_model)
6644 cout << "Substitution of Expectation operator: added " << subst_table.size() << " auxiliary variables and " << neweqs.size() << " auxiliary equations." << endl;
6645 else
6646 cout << "Substitution of Expectation operator: added " << neweqs.size() << " auxiliary variables and equations." << endl;
6647 }
6648 }
6649
6650 void
transformPredeterminedVariables()6651 DynamicModel::transformPredeterminedVariables()
6652 {
6653 for (auto &it : local_variables_table)
6654 it.second = it.second->decreaseLeadsLagsPredeterminedVariables();
6655
6656 for (auto &equation : equations)
6657 {
6658 auto substeq = dynamic_cast<BinaryOpNode *>(equation->decreaseLeadsLagsPredeterminedVariables());
6659 assert(substeq);
6660 equation = substeq;
6661 }
6662 }
6663
6664 void
detrendEquations()6665 DynamicModel::detrendEquations()
6666 {
6667 // We go backwards in the list of trend_vars, to deal correctly with I(2) processes
6668 for (auto it = nonstationary_symbols_map.crbegin();
6669 it != nonstationary_symbols_map.crend(); ++it)
6670 for (auto &equation : equations)
6671 {
6672 auto substeq = dynamic_cast<BinaryOpNode *>(equation->detrend(it->first, it->second.first, it->second.second));
6673 assert(substeq);
6674 equation = dynamic_cast<BinaryOpNode *>(substeq);
6675 }
6676
6677 for (auto &equation : equations)
6678 {
6679 auto substeq = dynamic_cast<BinaryOpNode *>(equation->removeTrendLeadLag(trend_symbols_map));
6680 assert(substeq);
6681 equation = dynamic_cast<BinaryOpNode *>(substeq);
6682 }
6683 }
6684
6685 void
removeTrendVariableFromEquations()6686 DynamicModel::removeTrendVariableFromEquations()
6687 {
6688 for (auto &equation : equations)
6689 {
6690 auto substeq = dynamic_cast<BinaryOpNode *>(equation->replaceTrendVar());
6691 assert(substeq);
6692 equation = dynamic_cast<BinaryOpNode *>(substeq);
6693 }
6694 }
6695
6696 void
differentiateForwardVars(const vector<string> & subset)6697 DynamicModel::differentiateForwardVars(const vector<string> &subset)
6698 {
6699 substituteLeadLagInternal(AuxVarType::diffForward, true, subset);
6700 }
6701
6702 void
fillEvalContext(eval_context_t & eval_context) const6703 DynamicModel::fillEvalContext(eval_context_t &eval_context) const
6704 {
6705 // First, auxiliary variables
6706 for (auto aux_equation : aux_equations)
6707 {
6708 assert(aux_equation->op_code == BinaryOpcode::equal);
6709 auto auxvar = dynamic_cast<VariableNode *>(aux_equation->arg1);
6710 assert(auxvar);
6711 try
6712 {
6713 double val = aux_equation->arg2->eval(eval_context);
6714 eval_context[auxvar->symb_id] = val;
6715 }
6716 catch (ExprNode::EvalException &e)
6717 {
6718 // Do nothing
6719 }
6720 }
6721
6722 // Second, model local variables
6723 for (auto it : local_variables_table)
6724 {
6725 try
6726 {
6727 const expr_t expression = it.second;
6728 double val = expression->eval(eval_context);
6729 eval_context[it.first] = val;
6730 }
6731 catch (ExprNode::EvalException &e)
6732 {
6733 // Do nothing
6734 }
6735 }
6736
6737 //Third, trend variables
6738 vector <int> trendVars = symbol_table.getTrendVarIds();
6739 for (int &trendVar : trendVars)
6740 eval_context[trendVar] = 2; //not <= 0 bc of log, not 1 bc of powers
6741 }
6742
6743 bool
isModelLocalVariableUsed() const6744 DynamicModel::isModelLocalVariableUsed() const
6745 {
6746 set<int> used_local_vars;
6747 size_t i = 0;
6748 while (i < equations.size() && used_local_vars.size() == 0)
6749 {
6750 equations[i]->collectVariables(SymbolType::modelLocalVariable, used_local_vars);
6751 i++;
6752 }
6753 return used_local_vars.size() > 0;
6754 }
6755
6756 void
addStaticOnlyEquation(expr_t eq,int lineno,const vector<pair<string,string>> & eq_tags)6757 DynamicModel::addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags)
6758 {
6759 auto beq = dynamic_cast<BinaryOpNode *>(eq);
6760 assert(beq && beq->op_code == BinaryOpcode::equal);
6761
6762 vector<pair<string, string>> soe_eq_tags;
6763 for (const auto &eq_tag : eq_tags)
6764 soe_eq_tags.push_back(eq_tag);
6765
6766 int n = static_only_equations.size();
6767 static_only_equations.push_back(beq);
6768 static_only_equations_lineno.push_back(lineno);
6769 static_only_equations_equation_tags.push_back(soe_eq_tags);
6770 for (auto &it : soe_eq_tags)
6771 static_only_equation_tags_xref.emplace(it, n);
6772 }
6773
6774 size_t
staticOnlyEquationsNbr() const6775 DynamicModel::staticOnlyEquationsNbr() const
6776 {
6777 return static_only_equations.size();
6778 }
6779
6780 size_t
dynamicOnlyEquationsNbr() const6781 DynamicModel::dynamicOnlyEquationsNbr() const
6782 {
6783 set<int> eqs;
6784
6785 for (const auto &equation_tag : equation_tags)
6786 if (equation_tag.second.first == "dynamic")
6787 eqs.insert(equation_tag.first);
6788
6789 return eqs.size();
6790 }
6791
6792 bool
isChecksumMatching(const string & basename,bool block) const6793 DynamicModel::isChecksumMatching(const string &basename, bool block) const
6794 {
6795 stringstream buffer;
6796
6797 // Write equation tags
6798 for (const auto &equation_tag : equation_tags)
6799 buffer << " " << equation_tag.first + 1
6800 << equation_tag.second.first
6801 << equation_tag.second.second << endl;
6802
6803 ExprNodeOutputType buffer_type = block ? ExprNodeOutputType::matlabDynamicModelSparse : ExprNodeOutputType::CDynamicModel;
6804
6805 deriv_node_temp_terms_t tef_terms;
6806 temporary_terms_t temp_term_union;
6807 writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs,
6808 buffer, buffer_type, tef_terms);
6809
6810 writeTemporaryTerms(temporary_terms_derivatives[0],
6811 temp_term_union, temporary_terms_idxs,
6812 buffer, buffer_type, tef_terms);
6813
6814 writeModelEquations(buffer, buffer_type, temp_term_union);
6815
6816 size_t result = hash<string>{}(buffer.str());
6817
6818 // check whether basename directory exist. If not, create it.
6819 // If it does, read old checksum if it exists, return if equal to result
6820 fstream checksum_file;
6821 auto filename = filesystem::path{basename} / "checksum";
6822 if (!filesystem::create_directory(basename))
6823 {
6824 checksum_file.open(filename, ios::in | ios::binary);
6825 if (checksum_file.is_open())
6826 {
6827 size_t old_checksum;
6828 checksum_file >> old_checksum;
6829 checksum_file.close();
6830 if (old_checksum == result)
6831 return true;
6832 }
6833 }
6834
6835 // write new checksum file if none or different from old checksum
6836 checksum_file.open(filename, ios::out | ios::binary);
6837 if (!checksum_file.is_open())
6838 {
6839 cerr << "ERROR: Can't open file " << filename << endl;
6840 exit(EXIT_FAILURE);
6841 }
6842 checksum_file << result;
6843 checksum_file.close();
6844 return false;
6845 }
6846
6847 void
writeJsonOutput(ostream & output) const6848 DynamicModel::writeJsonOutput(ostream &output) const
6849 {
6850 deriv_node_temp_terms_t tef_terms;
6851 writeJsonModelLocalVariables(output, false, tef_terms);
6852 output << ", ";
6853 writeJsonModelEquations(output, false);
6854 output << ", ";
6855 writeJsonXrefs(output);
6856 output << ", ";
6857 writeJsonAST(output);
6858 output << ", ";
6859 writeJsonVariableMapping(output);
6860 }
6861
6862 void
writeJsonAST(ostream & output) const6863 DynamicModel::writeJsonAST(ostream &output) const
6864 {
6865 vector<pair<string, string>> eqtags;
6866 output << R"("abstract_syntax_tree":[)" << endl;
6867 for (int eq = 0; eq < static_cast<int>(equations.size()); eq++)
6868 {
6869 if (eq != 0)
6870 output << ", ";
6871
6872 output << R"({ "number":)" << eq
6873 << R"(, "line":)" << equations_lineno[eq];
6874
6875 for (const auto &equation_tag : equation_tags)
6876 if (equation_tag.first == eq)
6877 eqtags.push_back(equation_tag.second);
6878
6879 if (!eqtags.empty())
6880 {
6881 output << R"(, "tags": {)";
6882 int i = 0;
6883 for (const auto &[name, value] : eqtags)
6884 {
6885 if (i != 0)
6886 output << ", ";
6887 output << R"(")" << name << R"(": ")" << value << R"(")";
6888 i++;
6889 }
6890 output << "}";
6891 eqtags.clear();
6892 }
6893
6894 output << R"(, "AST": )";
6895 equations[eq]->writeJsonAST(output);
6896 output << "}";
6897 }
6898 output << "]";
6899 }
6900
6901 void
writeJsonVariableMapping(ostream & output) const6902 DynamicModel::writeJsonVariableMapping(ostream &output) const
6903 {
6904 output << R"("variable_mapping":[)" << endl;
6905 for (auto it = variableMapping.begin(); it != variableMapping.end(); ++it)
6906 {
6907 if (it != variableMapping.begin())
6908 output << ", ";
6909 auto [var, eqs] = *it;
6910 output << R"({"name": ")" << symbol_table.getName(var) << R"(", "equations":[)";
6911 bool first_eq = true;
6912 for (auto it2 = eqs.begin(); it2 != eqs.end(); ++it2)
6913 for (const auto &equation_tag : equation_tags)
6914 if (equation_tag.first == *it2 && equation_tag.second.first == "name")
6915 {
6916 if (first_eq)
6917 first_eq = false;
6918 else
6919 output << ", ";
6920 output << '"' << equation_tag.second.second << '"';
6921 }
6922 output << "]}" << endl;
6923 }
6924 output << "]";
6925 }
6926
6927 void
writeJsonXrefsHelper(ostream & output,const map<pair<int,int>,set<int>> & xrefs) const6928 DynamicModel::writeJsonXrefsHelper(ostream &output, const map<pair<int, int>, set<int>> &xrefs) const
6929 {
6930 for (auto it = xrefs.begin(); it != xrefs.end(); ++it)
6931 {
6932 if (it != xrefs.begin())
6933 output << ", ";
6934 output << R"({"name": ")" << symbol_table.getName(it->first.first) << R"(")"
6935 << R"(, "shift": )" << it->first.second
6936 << R"(, "equations": [)";
6937 for (auto it1 = it->second.begin(); it1 != it->second.end(); ++it1)
6938 {
6939 if (it1 != it->second.begin())
6940 output << ", ";
6941 output << *it1 + 1;
6942 }
6943 output << "]}";
6944 }
6945 }
6946
6947 void
writeJsonXrefs(ostream & output) const6948 DynamicModel::writeJsonXrefs(ostream &output) const
6949 {
6950 output << R"("xrefs": {)"
6951 << R"("parameters": [)";
6952 writeJsonXrefsHelper(output, xref_param);
6953 output << "]"
6954 << R"(, "endogenous": [)";
6955 writeJsonXrefsHelper(output, xref_endo);
6956 output << "]"
6957 << R"(, "exogenous": [)";
6958 writeJsonXrefsHelper(output, xref_exo);
6959 output << "]"
6960 << R"(, "exogenous_deterministic": [)";
6961 writeJsonXrefsHelper(output, xref_exo_det);
6962 output << "]}" << endl;
6963 }
6964
6965 void
writeJsonOriginalModelOutput(ostream & output) const6966 DynamicModel::writeJsonOriginalModelOutput(ostream &output) const
6967 {
6968 writeJsonModelEquations(output, false);
6969 output << ", ";
6970 writeJsonAST(output);
6971 }
6972
6973 void
writeJsonDynamicModelInfo(ostream & output) const6974 DynamicModel::writeJsonDynamicModelInfo(ostream &output) const
6975 {
6976 output << R"("model_info": {)"
6977 << R"("lead_lag_incidence": [)";
6978 // Loop on endogenous variables
6979 int nstatic = 0,
6980 nfwrd = 0,
6981 npred = 0,
6982 nboth = 0;
6983 for (int endoID = 0; endoID < symbol_table.endo_nbr(); endoID++)
6984 {
6985 if (endoID != 0)
6986 output << ",";
6987 output << "[";
6988 int sstatic = 1,
6989 sfwrd = 0,
6990 spred = 0,
6991 sboth = 0;
6992 // Loop on periods
6993 for (int lag = -max_endo_lag; lag <= max_endo_lead; lag++)
6994 {
6995 // Print variableID if exists with current period, otherwise print 0
6996 try
6997 {
6998 if (lag != -max_endo_lag)
6999 output << ",";
7000 int varID = getDerivID(symbol_table.getID(SymbolType::endogenous, endoID), lag);
7001 output << " " << getDynJacobianCol(varID) + 1;
7002 if (lag == -1)
7003 {
7004 sstatic = 0;
7005 spred = 1;
7006 }
7007 else if (lag == 1)
7008 {
7009 if (spred == 1)
7010 {
7011 sboth = 1;
7012 spred = 0;
7013 }
7014 else
7015 {
7016 sstatic = 0;
7017 sfwrd = 1;
7018 }
7019 }
7020 }
7021 catch (UnknownDerivIDException &e)
7022 {
7023 output << " 0";
7024 }
7025 }
7026 nstatic += sstatic;
7027 nfwrd += sfwrd;
7028 npred += spred;
7029 nboth += sboth;
7030 output << "]";
7031 }
7032 output << "], "
7033 << R"("nstatic": )" << nstatic << ", "
7034 << R"("nfwrd": )" << nfwrd << ", "
7035 << R"("npred": )" << npred << ", "
7036 << R"("nboth": )" << nboth << ", "
7037 << R"("nsfwrd": )" << nfwrd+nboth << ", "
7038 << R"("nspred": )" << npred+nboth << ", "
7039 << R"("ndynamic": )" << npred+nboth+nfwrd << endl;
7040 output << "}";
7041 }
7042
7043 void
writeJsonComputingPassOutput(ostream & output,bool writeDetails) const7044 DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) const
7045 {
7046 ostringstream model_local_vars_output; // Used for storing model local vars
7047 vector<ostringstream> d_output(derivatives.size()); // Derivatives output (at all orders, including 0=residual)
7048
7049 deriv_node_temp_terms_t tef_terms;
7050 temporary_terms_t temp_term_union;
7051
7052 writeJsonModelLocalVariables(model_local_vars_output, true, tef_terms);
7053
7054 writeJsonTemporaryTerms(temporary_terms_derivatives[0], temp_term_union, d_output[0], tef_terms, "");
7055 d_output[0] << ", ";
7056 writeJsonModelEquations(d_output[0], true);
7057
7058 int ncols = dynJacobianColsNbr;
7059 for (size_t i = 1; i < derivatives.size(); i++)
7060 {
7061 string matrix_name = i == 1 ? "jacobian" : i == 2 ? "hessian" : i == 3 ? "third_derivative" : to_string(i) + "th_derivative";
7062 writeJsonTemporaryTerms(temporary_terms_derivatives[i], temp_term_union, d_output[i], tef_terms, matrix_name);
7063 temp_term_union.insert(temporary_terms_derivatives[i].begin(), temporary_terms_derivatives[i].end());
7064 d_output[i] << R"(, ")" << matrix_name << R"(": {)"
7065 << R"( "nrows": )" << equations.size()
7066 << R"(, "ncols": )" << ncols
7067 << R"(, "entries": [)";
7068
7069 for (auto it = derivatives[i].begin(); it != derivatives[i].end(); ++it)
7070 {
7071 if (it != derivatives[i].begin())
7072 d_output[i] << ", ";
7073
7074 const vector<int> &vidx = it->first;
7075 expr_t d = it->second;
7076 int eq = vidx[0];
7077
7078 int col_idx = 0;
7079 for (size_t j = 1; j < vidx.size(); j++)
7080 {
7081 col_idx *= dynJacobianColsNbr;
7082 col_idx += getDynJacobianCol(vidx[j]);
7083 }
7084
7085 if (writeDetails)
7086 d_output[i] << R"({"eq": )" << eq + 1;
7087 else
7088 d_output[i] << R"({"row": )" << eq + 1;
7089
7090 d_output[i] << R"(, "col": )" << (i > 1 ? "[" : "") << col_idx + 1;
7091
7092 if (i == 2 && vidx[1] != vidx[2]) // Symmetric elements in hessian
7093 {
7094 int col_idx_sym = getDynJacobianCol(vidx[2]) * dynJacobianColsNbr + getDynJacobianCol(vidx[1]);
7095 d_output[i] << ", " << col_idx_sym + 1;
7096 }
7097 if (i > 1)
7098 d_output[i] << "]";
7099
7100 if (writeDetails)
7101 for (size_t j = 1; j < vidx.size(); j++)
7102 d_output[i] << R"(, "var)" << (i > 1 ? to_string(j) : "") << R"(": ")" << symbol_table.getName(getSymbIDByDerivID(vidx[j])) << R"(")"
7103 << R"(, "shift)" << (i > 1 ? to_string(j) : "") << R"(": )" << getLagByDerivID(vidx[j]);
7104
7105 d_output[i] << R"(, "val": ")";
7106 d->writeJsonOutput(d_output[i], temp_term_union, tef_terms);
7107 d_output[i] << R"("})" << endl;
7108 }
7109 d_output[i] << "]}";
7110
7111 ncols *= dynJacobianColsNbr;
7112 }
7113
7114 if (writeDetails)
7115 output << R"("dynamic_model": {)";
7116 else
7117 output << R"("dynamic_model_simple": {)";
7118 output << model_local_vars_output.str();
7119 for (const auto &it : d_output)
7120 output << ", " << it.str();
7121 output << "}";
7122 }
7123
7124 void
writeJsonParamsDerivativesFile(ostream & output,bool writeDetails) const7125 DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const
7126 {
7127 if (!params_derivatives.size())
7128 return;
7129
7130 ostringstream model_local_vars_output; // Used for storing model local vars
7131 ostringstream model_output; // Used for storing model temp vars and equations
7132 ostringstream rp_output; // 1st deriv. of residuals w.r.t. parameters
7133 ostringstream gp_output; // 1st deriv. of Jacobian w.r.t. parameters
7134 ostringstream rpp_output; // 2nd deriv of residuals w.r.t. parameters
7135 ostringstream gpp_output; // 2nd deriv of Jacobian w.r.t. parameters
7136 ostringstream hp_output; // 1st deriv. of Hessian w.r.t. parameters
7137 ostringstream g3p_output; // 1st deriv. of 3rd deriv. matrix w.r.t. parameters
7138
7139 deriv_node_temp_terms_t tef_terms;
7140 writeJsonModelLocalVariables(model_local_vars_output, true, tef_terms);
7141
7142 temporary_terms_t temp_term_union;
7143 for (const auto &it : params_derivs_temporary_terms)
7144 writeJsonTemporaryTerms(it.second, temp_term_union, model_output, tef_terms, "all");
7145
7146 rp_output << R"("deriv_wrt_params": {)"
7147 << R"( "neqs": )" << equations.size()
7148 << R"(, "nparamcols": )" << symbol_table.param_nbr()
7149 << R"(, "entries": [)";
7150 auto &rp = params_derivatives.find({ 0, 1 })->second;
7151 for (auto it = rp.begin(); it != rp.end(); ++it)
7152 {
7153 if (it != rp.begin())
7154 rp_output << ", ";
7155
7156 auto [eq, param] = vectorToTuple<2>(it->first);
7157 expr_t d1 = it->second;
7158
7159 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
7160
7161 if (writeDetails)
7162 rp_output << R"({"eq": )" << eq + 1;
7163 else
7164 rp_output << R"({"row": )" << eq + 1;
7165
7166 rp_output << R"(, "param_col": )" << param_col + 1;
7167
7168 if (writeDetails)
7169 rp_output << R"(, "param": ")" << symbol_table.getName(getSymbIDByDerivID(param)) << R"(")";
7170
7171 rp_output << R"(, "val": ")";
7172 d1->writeJsonOutput(rp_output, temp_term_union, tef_terms);
7173 rp_output << R"("})" << endl;
7174 }
7175 rp_output << "]}";
7176
7177 gp_output << R"("deriv_jacobian_wrt_params": {)"
7178 << R"( "neqs": )" << equations.size()
7179 << R"(, "nvarcols": )" << dynJacobianColsNbr
7180 << R"(, "nparamcols": )" << symbol_table.param_nbr()
7181 << R"(, "entries": [)";
7182 auto &gp = params_derivatives.find({ 1, 1 })->second;
7183 for (auto it = gp.begin(); it != gp.end(); ++it)
7184 {
7185 if (it != gp.begin())
7186 gp_output << ", ";
7187
7188 auto [eq, var, param] = vectorToTuple<3>(it->first);
7189 expr_t d2 = it->second;
7190
7191 int var_col = getDynJacobianCol(var) + 1;
7192 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
7193
7194 if (writeDetails)
7195 gp_output << R"({"eq": )" << eq + 1;
7196 else
7197 gp_output << R"({"row": )" << eq + 1;
7198
7199 gp_output << R"(, "var_col": )" << var_col + 1
7200 << R"(, "param_col": )" << param_col + 1;
7201
7202 if (writeDetails)
7203 gp_output << R"(, "var": ")" << symbol_table.getName(getSymbIDByDerivID(var)) << R"(")"
7204 << R"(, "lag": )" << getLagByDerivID(var)
7205 << R"(, "param": ")" << symbol_table.getName(getSymbIDByDerivID(param)) << R"(")";
7206
7207 gp_output << R"(, "val": ")";
7208 d2->writeJsonOutput(gp_output, temp_term_union, tef_terms);
7209 gp_output << R"("})" << endl;
7210 }
7211 gp_output << "]}";
7212
7213 rpp_output << R"("second_deriv_residuals_wrt_params": {)"
7214 << R"( "nrows": )" << equations.size()
7215 << R"(, "nparam1cols": )" << symbol_table.param_nbr()
7216 << R"(, "nparam2cols": )" << symbol_table.param_nbr()
7217 << R"(, "entries": [)";
7218 auto &rpp = params_derivatives.find({ 0, 2 })->second;
7219 for (auto it = rpp.begin(); it != rpp.end(); ++it)
7220 {
7221 if (it != rpp.begin())
7222 rpp_output << ", ";
7223
7224 auto [eq, param1, param2] = vectorToTuple<3>(it->first);
7225 expr_t d2 = it->second;
7226
7227 int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
7228 int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
7229
7230 if (writeDetails)
7231 rpp_output << R"({"eq": )" << eq + 1;
7232 else
7233 rpp_output << R"({"row": )" << eq + 1;
7234 rpp_output << R"(, "param1_col": )" << param1_col + 1
7235 << R"(, "param2_col": )" << param2_col + 1;
7236
7237 if (writeDetails)
7238 rpp_output << R"(, "param1": ")" << symbol_table.getName(getSymbIDByDerivID(param1)) << R"(")"
7239 << R"(, "param2": ")" << symbol_table.getName(getSymbIDByDerivID(param2)) << R"(")";
7240
7241 rpp_output << R"(, "val": ")";
7242 d2->writeJsonOutput(rpp_output, temp_term_union, tef_terms);
7243 rpp_output << R"("})" << endl;
7244 }
7245 rpp_output << "]}";
7246
7247 gpp_output << R"("second_deriv_jacobian_wrt_params": {)"
7248 << R"( "neqs": )" << equations.size()
7249 << R"(, "nvarcols": )" << dynJacobianColsNbr
7250 << R"(, "nparam1cols": )" << symbol_table.param_nbr()
7251 << R"(, "nparam2cols": )" << symbol_table.param_nbr()
7252 << R"(, "entries": [)";
7253 auto &gpp = params_derivatives.find({ 1, 2 })->second;
7254 for (auto it = gpp.begin(); it != gpp.end(); ++it)
7255 {
7256 if (it != gpp.begin())
7257 gpp_output << ", ";
7258
7259 auto [eq, var, param1, param2] = vectorToTuple<4>(it->first);
7260 expr_t d2 = it->second;
7261
7262 int var_col = getDynJacobianCol(var) + 1;
7263 int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
7264 int param2_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param2)) + 1;
7265
7266 if (writeDetails)
7267 gpp_output << R"({"eq": )" << eq + 1;
7268 else
7269 gpp_output << R"({"row": )" << eq + 1;
7270
7271 gpp_output << R"(, "var_col": )" << var_col + 1
7272 << R"(, "param1_col": )" << param1_col + 1
7273 << R"(, "param2_col": )" << param2_col + 1;
7274
7275 if (writeDetails)
7276 gpp_output << R"(, "var": ")" << symbol_table.getName(var) << R"(")"
7277 << R"(, "lag": )" << getLagByDerivID(var)
7278 << R"(, "param1": ")" << symbol_table.getName(getSymbIDByDerivID(param1)) << R"(")"
7279 << R"(, "param2": ")" << symbol_table.getName(getSymbIDByDerivID(param2)) << R"(")";
7280
7281 gpp_output << R"(, "val": ")";
7282 d2->writeJsonOutput(gpp_output, temp_term_union, tef_terms);
7283 gpp_output << R"("})" << endl;
7284 }
7285 gpp_output << "]}" << endl;
7286
7287 hp_output << R"("derivative_hessian_wrt_params": {)"
7288 << R"( "neqs": )" << equations.size()
7289 << R"(, "nvar1cols": )" << dynJacobianColsNbr
7290 << R"(, "nvar2cols": )" << dynJacobianColsNbr
7291 << R"(, "nparamcols": )" << symbol_table.param_nbr()
7292 << R"(, "entries": [)";
7293 auto &hp = params_derivatives.find({ 2, 1 })->second;
7294 for (auto it = hp.begin(); it != hp.end(); ++it)
7295 {
7296 if (it != hp.begin())
7297 hp_output << ", ";
7298
7299 auto [eq, var1, var2, param] = vectorToTuple<4>(it->first);
7300 expr_t d2 = it->second;
7301
7302 int var1_col = getDynJacobianCol(var1) + 1;
7303 int var2_col = getDynJacobianCol(var2) + 1;
7304 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
7305
7306 if (writeDetails)
7307 hp_output << R"({"eq": )" << eq + 1;
7308 else
7309 hp_output << R"({"row": )" << eq + 1;
7310
7311 hp_output << R"(, "var1_col": )" << var1_col + 1
7312 << R"(, "var2_col": )" << var2_col + 1
7313 << R"(, "param_col": )" << param_col + 1;
7314
7315 if (writeDetails)
7316 hp_output << R"(, "var1": ")" << symbol_table.getName(getSymbIDByDerivID(var1)) << R"(")"
7317 << R"(, "lag1": )" << getLagByDerivID(var1)
7318 << R"(, "var2": ")" << symbol_table.getName(getSymbIDByDerivID(var2)) << R"(")"
7319 << R"(, "lag2": )" << getLagByDerivID(var2)
7320 << R"(, "param": ")" << symbol_table.getName(getSymbIDByDerivID(param)) << R"(")";
7321
7322 hp_output << R"(, "val": ")";
7323 d2->writeJsonOutput(hp_output, temp_term_union, tef_terms);
7324 hp_output << R"("})" << endl;
7325 }
7326 hp_output << "]}" << endl;
7327
7328 g3p_output << R"("derivative_g3_wrt_params": {)"
7329 << R"( "neqs": )" << equations.size()
7330 << R"(, "nvar1cols": )" << dynJacobianColsNbr
7331 << R"(, "nvar2cols": )" << dynJacobianColsNbr
7332 << R"(, "nvar3cols": )" << dynJacobianColsNbr
7333 << R"(, "nparamcols": )" << symbol_table.param_nbr()
7334 << R"(, "entries": [)";
7335 auto &g3p = params_derivatives.find({ 3, 1 })->second;
7336 for (auto it = g3p.begin(); it != g3p.end(); ++it)
7337 {
7338 if (it != g3p.begin())
7339 g3p_output << ", ";
7340
7341 auto [eq, var1, var2, var3, param] = vectorToTuple<5>(it->first);
7342 expr_t d2 = it->second;
7343
7344 int var1_col = getDynJacobianCol(var1) + 1;
7345 int var2_col = getDynJacobianCol(var2) + 1;
7346 int var3_col = getDynJacobianCol(var3) + 1;
7347 int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
7348
7349 if (writeDetails)
7350 g3p_output << R"({"eq": )" << eq + 1;
7351 else
7352 g3p_output << R"({"row": )" << eq + 1;
7353
7354 g3p_output << R"(, "var1_col": )" << var1_col + 1
7355 << R"(, "var2_col": )" << var2_col + 1
7356 << R"(, "var3_col": )" << var3_col + 1
7357 << R"(, "param_col": )" << param_col + 1;
7358
7359 if (writeDetails)
7360 g3p_output << R"(, "var1": ")" << symbol_table.getName(getSymbIDByDerivID(var1)) << R"(")"
7361 << R"(, "lag1": )" << getLagByDerivID(var1)
7362 << R"(, "var2": ")" << symbol_table.getName(getSymbIDByDerivID(var2)) << R"(")"
7363 << R"(, "lag2": )" << getLagByDerivID(var2)
7364 << R"(, "var3": ")" << symbol_table.getName(getSymbIDByDerivID(var3)) << R"(")"
7365 << R"(, "lag3": )" << getLagByDerivID(var3)
7366 << R"(, "param": ")" << symbol_table.getName(getSymbIDByDerivID(param)) << R"(")";
7367
7368 g3p_output << R"(, "val": ")";
7369 d2->writeJsonOutput(g3p_output, temp_term_union, tef_terms);
7370 g3p_output << R"("})" << endl;
7371 }
7372 g3p_output << "]}" << endl;
7373
7374 if (writeDetails)
7375 output << R"("dynamic_model_params_derivative": {)";
7376 else
7377 output << R"("dynamic_model_params_derivatives_simple": {)";
7378 output << model_local_vars_output.str()
7379 << ", " << model_output.str()
7380 << ", " << rp_output.str()
7381 << ", " << gp_output.str()
7382 << ", " << rpp_output.str()
7383 << ", " << gpp_output.str()
7384 << ", " << hp_output.str()
7385 << ", " << g3p_output.str()
7386 << "}";
7387 }
7388
7389 void
substituteVarExpectation(const map<string,expr_t> & subst_table)7390 DynamicModel::substituteVarExpectation(const map<string, expr_t> &subst_table)
7391 {
7392 for (auto &equation : equations)
7393 equation = dynamic_cast<BinaryOpNode *>(equation->substituteVarExpectation(subst_table));
7394 }
7395