1 /*
2 * Copyright © 2003-2020 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 #ifndef _MODELTREE_HH
21 #define _MODELTREE_HH
22
23 using namespace std;
24
25 #include <string>
26 #include <vector>
27 #include <deque>
28 #include <map>
29 #include <ostream>
30 #include <array>
31 #include <filesystem>
32
33 #include "DataTree.hh"
34 #include "ExtendedPreprocessorTypes.hh"
35
36 // Helper to convert a vector into a tuple
37 template<typename T, size_t... Indices>
38 auto
vectorToTupleHelper(const vector<T> & v,index_sequence<Indices...>)39 vectorToTupleHelper(const vector<T> &v, index_sequence<Indices...>)
40 {
41 return tuple(v[Indices] ...);
42 }
43 template<size_t N, typename T>
44 auto
vectorToTuple(const vector<T> & v)45 vectorToTuple(const vector<T> &v)
46 {
47 assert(v.size() >= N);
48 return vectorToTupleHelper(v, make_index_sequence<N>());
49 }
50
51 //! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
52 using equation_type_and_normalized_equation_t = vector<pair<EquationType, expr_t>>;
53
54 //! Vector describing variables: max_lag in the block, max_lead in the block
55 using lag_lead_vector_t = vector<pair< int, int>>;
56
57 //! for each block contains tuple<Simulation_Type, first_equation, Block_Size, Recursive_part_Size>
58 using block_type_firstequation_size_mfs_t = vector<tuple<BlockSimulationType, int, int, int>>;
59
60 //! for a block contains derivatives tuple<block_equation_number, block_variable_number, lead_lag, expr_t>
61 using block_derivatives_equation_variable_laglead_nodeid_t = vector<tuple<int, int, int, expr_t>>;
62
63 //! for all blocks derivatives description
64 using blocks_derivatives_t = vector<block_derivatives_equation_variable_laglead_nodeid_t>;
65
66 //! Shared code for static and dynamic models
67 class ModelTree : public DataTree
68 {
69 friend class DynamicModel;
70 friend class StaticModel;
71 public:
72 // Set via the `compiler` command
73 string user_set_add_flags, user_set_subst_flags, user_set_add_libs, user_set_subst_libs, user_set_compiler;
74 protected:
75 /*
76 * ************** BEGIN **************
77 * The following structures keep track of the model equations and must all be updated
78 * when adding or removing an equation. Hence, if a new parallel structure is added
79 * in the future, it must be maintained whereever these structures are updated
80 * See in particular methods clearEquations(), replaceMyEquations() and
81 * computeRamseyPolicyFOCs() of DynamicModel class.
82 * NB: This message added with the introduction of the `exclude_eqs` option, hence
83 * that's a place to update future structures.
84 */
85 //! Stores declared and generated auxiliary equations
86 vector<BinaryOpNode *> equations;
87 //! Stores line numbers of declared equations; -1 means undefined
88 vector<int> equations_lineno;
89 //! Stores equation tags
90 vector<pair<int, pair<string, string>>> equation_tags;
91 //! Stores mapping from equation tags to equation number
92 multimap<pair<string, string>, int> equation_tags_xref;
93 /*
94 * ************** END **************
95 */
96
97 //! Only stores generated auxiliary equations, in an order meaningful for evaluation
98 /*! These equations only contain the definition of auxiliary variables, and
99 may diverge from those in the main model (equations), if other model
100 transformations applied subsequently. This is not a problem, since
101 aux_equations is only used for regenerating the values of auxiliaries
102 given the others.
103
104 For example, such a divergence appears when there is an expectation
105 operator in a ramsey model, see
106 tests/optimal_policy/nk_ramsey_expectation.mod */
107 vector<BinaryOpNode *> aux_equations;
108
109 //! Maximum order at which (endogenous) derivatives have been computed
110 int computed_derivs_order{0};
111
112 //! Stores derivatives
113 /*! Index 0 is not used, index 1 contains first derivatives, ...
114 For each derivation order, stores a map whose key is a vector of integer: the
115 first integer is the equation index, the remaining ones are the derivation
116 IDs of variables (in non-decreasing order, to avoid storing symmetric
117 elements several times) */
118 vector<map<vector<int>, expr_t>> derivatives;
119
120 //! Number of non-zero derivatives
121 /*! Index 0 is not used, index 1 contains number of non-zero first
122 derivatives, ... */
123 vector<int> NNZDerivatives;
124
125 //! Derivatives with respect to parameters
126 /*! The key of the outer map is a pair (derivation order w.r.t. endogenous,
127 derivation order w.r.t. parameters). For e.g., { 1, 2 } corresponds to the jacobian
128 differentiated twice w.r.t. to parameters.
129 In inner maps, the vector of integers consists of: the equation index, then
130 the derivation IDs of endogenous (in non-decreasing order),
131 then the IDs of parameters (in non-decreasing order)*/
132 map<pair<int,int>, map<vector<int>, expr_t>> params_derivatives;
133
134 //! Storage for temporary terms in block/bytecode mode
135 temporary_terms_t temporary_terms;
136
137 //! Used model local variables, that will be treated as temporary terms
138 /*! See the comments in ModelTree::computeTemporaryTerms() */
139 map<VariableNode *, expr_t, ExprNodeLess> temporary_terms_mlv;
140
141 //! Temporary terms for residuals and derivatives
142 /*! Index 0 is temp. terms of residuals, index 1 for first derivatives, ... */
143 vector<temporary_terms_t> temporary_terms_derivatives;
144
145 //! Stores, for each temporary term, its index in the MATLAB/Julia vector
146 temporary_terms_idxs_t temporary_terms_idxs;
147
148 //! Temporary terms for parameter derivatives, under a disaggregated form
149 /*! The pair of integers is to be interpreted as in param_derivatives */
150 map<pair<int, int>, temporary_terms_t> params_derivs_temporary_terms;
151
152 //! Stores, for each temporary term in param. derivs, its index in the MATLAB/Julia vector
153 temporary_terms_idxs_t params_derivs_temporary_terms_idxs;
154
155 //! Trend variables and their growth factors
156 map<int, expr_t> trend_symbols_map;
157
158 //! for all trends; the boolean is true if this is a log-trend, false otherwise
159 using nonstationary_symbols_map_t = map<int, pair<bool, expr_t>>;
160
161 //! Nonstationary variables and their deflators
162 nonstationary_symbols_map_t nonstationary_symbols_map;
163
164 //! vector of block reordered variables and equations
165 vector<int> equation_reordered, variable_reordered, inv_equation_reordered, inv_variable_reordered;
166
167 //! the file containing the model and the derivatives code
168 ofstream code_file;
169
170 //! Vector indicating if the equation is linear in endogenous variable (true) or not (false)
171 vector<bool> is_equation_linear;
172
173 //! Computes derivatives
174 /*! \param order the derivation order
175 \param vars the derivation IDs w.r.t. which compute the derivatives */
176 void computeDerivatives(int order, const set<int> &vars);
177 //! Computes derivatives of the Jacobian and Hessian w.r. to parameters
178 void computeParamsDerivatives(int paramsDerivsOrder);
179 //! Write derivative of an equation w.r. to a variable
180 void writeDerivative(ostream &output, int eq, int symb_id, int lag, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const;
181 //! Computes temporary terms (for all equations and derivatives)
182 void computeTemporaryTerms(bool is_matlab, bool no_tmp_terms);
183 //! Computes temporary terms for the file containing parameters derivatives
184 void computeParamsDerivativesTemporaryTerms();
185 //! Writes temporary terms
186 void writeTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, const temporary_terms_idxs_t &tt_idxs, ostream &output, ExprNodeOutputType output_type, deriv_node_temp_terms_t &tef_terms) const;
187 void writeJsonTemporaryTerms(const temporary_terms_t &tt, temporary_terms_t &temp_term_union, ostream &output, deriv_node_temp_terms_t &tef_terms, const string &concat) const;
188 //! Compiles temporary terms
189 void compileTemporaryTerms(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, map_idx_t map_idx, bool dynamic, bool steady_dynamic) const;
190 //! Adds informations for simulation in a binary file
191 void Write_Inf_To_Bin_File(const string &filename, int &u_count_int, bool &file_open, bool is_two_boundaries, int block_mfs) const;
192 //! Fixes output when there are more than 32 nested parens, Issue #1201
193 void fixNestedParenthesis(ostringstream &output, map<string, string> &tmp_paren_vars, bool &message_printed) const;
194 //! Tests if string contains more than 32 nested parens, Issue #1201
195 bool testNestedParenthesis(const string &str) const;
196 void writeModelLocalVariableTemporaryTerms(temporary_terms_t &temp_term_union,
197 const temporary_terms_idxs_t &tt_idxs,
198 ostream &output, ExprNodeOutputType output_type,
199 deriv_node_temp_terms_t &tef_terms) const;
200 //! Writes model equations
201 void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
202 void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
203 const temporary_terms_t &temporary_terms) const;
204 //! Writes JSON model equations
205 //! if residuals = true, we are writing the dynamic/static model.
206 //! Otherwise, just the model equations (with line numbers, no tmp terms)
207 void writeJsonModelEquations(ostream &output, bool residuals) const;
208 /* Writes JSON model local variables.
209 Optionally put the external function variable calls into TEF terms */
210 void writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, deriv_node_temp_terms_t &tef_terms) const;
211 //! Compiles model equations
212 void compileModelEquations(ostream &code_file, unsigned int &instruction_number, const temporary_terms_t &tt, const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const;
213
214 //! Writes LaTeX model file
215 void writeLatexModelFile(const string &mod_basename, const string &latex_basename, ExprNodeOutputType output_type, bool write_equation_tags) const;
216
217 //! Sparse matrix of double to store the values of the Jacobian
218 /*! First index is equation number, second index is endogenous type specific ID */
219 using jacob_map_t = map<pair<int, int>, double>;
220
221 //! Sparse matrix of double to store the values of the Jacobian
222 /*! First index is lag, second index is equation number, third index is endogenous type specific ID */
223 using dynamic_jacob_map_t = map<tuple<int, int, int>, expr_t>;
224
225 //! Normalization of equations
226 /*! Maps endogenous type specific IDs to equation numbers */
227 vector<int> endo2eq;
228
229 //! number of equation in the prologue and in the epilogue
230 unsigned int epilogue, prologue;
231
232 //! for each block contains pair< max_lag, max_lead>
233 lag_lead_vector_t block_lag_lead;
234
235 //! Compute the matching between endogenous and variable using the jacobian contemporaneous_jacobian
236 /*!
237 \param contemporaneous_jacobian Jacobian used as an incidence matrix: all elements declared in the map (even if they are zero), are used as vertices of the incidence matrix
238 \return True if a complete normalization has been achieved
239 */
240 bool computeNormalization(const jacob_map_t &contemporaneous_jacobian, bool verbose);
241
242 //! Try to compute the matching between endogenous and variable using a decreasing cutoff
243 /*!
244 Applied to the jacobian contemporaneous_jacobian and stop when a matching is found.
245 If no matching is found using a strictly positive cutoff, then a zero cutoff is applied (i.e. use a symbolic normalization); in that case, the method adds zeros in the jacobian matrices to reflect all the edges in the symbolic incidence matrix.
246 If no matching is found with a zero cutoff close to zero an error message is printout.
247 */
248 void computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian, double cutoff, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian);
249 //! Try to find a natural normalization if all equations are matched to an endogenous variable on the LHS
250 bool computeNaturalNormalization();
251 //! Try to normalized each unnormalized equation (matched endogenous variable only on the LHS)
252 multimap<int, int> computeNormalizedEquations() const;
253 //! Evaluate the jacobian and suppress all the elements below the cutoff
254 void evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_map_t &contemporaneous_jacobian, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian, double cutoff, bool verbose);
255 //! Select and reorder the non linear equations of the model
256 vector<pair<int, int>> select_non_linear_equations_and_variables(vector<bool> is_equation_linear, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered,
257 vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered,
258 lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead,
259 vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed);
260 //! Search the equations and variables belonging to the prologue and the epilogue of the model
261 void computePrologueAndEpilogue(const jacob_map_t &static_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered);
262 //! Determine the type of each equation of model and try to normalized the unnormalized equation using computeNormalizedEquations
263 equation_type_and_normalized_equation_t equationTypeDetermination(const map<tuple<int, int, int>, expr_t> &first_order_endo_derivatives, const vector<int> &Index_Var_IM, const vector<int> &Index_Equ_IM, int mfs) const;
264 //! Compute the block decomposition and for a non-recusive block find the minimum feedback set
265 void computeBlockDecompositionAndFeedbackVariablesForEachBlock(const jacob_map_t &static_jacobian, const dynamic_jacob_map_t &dynamic_jacobian, vector<int> &equation_reordered, vector<int> &variable_reordered, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, bool verbose_, bool select_feedback_variable, int mfs, vector<int> &inv_equation_reordered, vector<int> &inv_variable_reordered, lag_lead_vector_t &equation_lag_lead, lag_lead_vector_t &variable_lag_lead_t, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed) const;
266 //! Reduce the number of block merging the same type equation in the prologue and the epilogue and determine the type of each block
267 block_type_firstequation_size_mfs_t reduceBlocksAndTypeDetermination(const dynamic_jacob_map_t &dynamic_jacobian, vector<pair<int, int>> &blocks, const equation_type_and_normalized_equation_t &Equation_Type, const vector<int> &variable_reordered, const vector<int> &equation_reordered, vector<unsigned int> &n_static, vector<unsigned int> &n_forward, vector<unsigned int> &n_backward, vector<unsigned int> &n_mixed, vector<tuple<int, int, int, int>> &block_col_type, bool linear_decomposition);
268 //! Determine the maximum number of lead and lag for the endogenous variable in a bloc
269 void getVariableLeadLagByBlock(const dynamic_jacob_map_t &dynamic_jacobian, const vector<int> &components_set, int nb_blck_sim, lag_lead_vector_t &equation_lead_lag, lag_lead_vector_t &variable_lead_lag, const vector<int> &equation_reordered, const vector<int> &variable_reordered) const;
270 //! For each equation determine if it is linear or not
271 vector<bool> equationLinear(map<tuple<int, int, int>, expr_t> first_order_endo_derivatives) const;
272 //! Print an abstract of the block structure of the model
273 void printBlockDecomposition(const vector<pair<int, int>> &blocks) const;
274 //! Determine for each block if it is linear or not
275 vector<bool> BlockLinear(const blocks_derivatives_t &blocks_derivatives, const vector<int> &variable_reordered) const;
276 //! Remove equations specified by exclude_eqs
277 vector<int> includeExcludeEquations(set<pair<string, string>> &eqs, bool exclude_eqs,
278 vector<BinaryOpNode *> &equations, vector<int> &equations_lineno,
279 vector<pair<int, pair<string, string>>> &equation_tags,
280 multimap<pair<string, string>, int> &equation_tags_xref, bool static_equations) const;
281
282 //! Determine the simulation type of each block
283 virtual BlockSimulationType getBlockSimulationType(int block_number) const = 0;
284 //! Return the number of blocks
285 virtual unsigned int getNbBlocks() const = 0;
286 //! Return the first equation number of a block
287 virtual unsigned int getBlockFirstEquation(int block_number) const = 0;
288 //! Return the size of the block block_number
289 virtual unsigned int getBlockSize(int block_number) const = 0;
290 //! Return the number of exogenous variable in the block block_number
291 virtual unsigned int getBlockExoSize(int block_number) const = 0;
292 //! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number
293 virtual unsigned int getBlockExoColSize(int block_number) const = 0;
294 //! Return the number of feedback variable of the block block_number
295 virtual unsigned int getBlockMfs(int block_number) const = 0;
296 //! Return the maximum lag in a block
297 virtual unsigned int getBlockMaxLag(int block_number) const = 0;
298 //! Return the maximum lead in a block
299 virtual unsigned int getBlockMaxLead(int block_number) const = 0;
300 inline void
setBlockLeadLag(int block,int max_lag,int max_lead)301 setBlockLeadLag(int block, int max_lag, int max_lead)
302 {
303 block_lag_lead[block] = { max_lag, max_lead };
304 };
305
306 //! Return the type of equation (equation_number) belonging to the block block_number
307 virtual EquationType getBlockEquationType(int block_number, int equation_number) const = 0;
308 //! Return true if the equation has been normalized
309 virtual bool isBlockEquationRenormalized(int block_number, int equation_number) const = 0;
310 //! Return the expr_t of the equation equation_number belonging to the block block_number
311 virtual expr_t getBlockEquationExpr(int block_number, int equation_number) const = 0;
312 //! Return the expr_t of the renormalized equation equation_number belonging to the block block_number
313 virtual expr_t getBlockEquationRenormalizedExpr(int block_number, int equation_number) const = 0;
314 //! Return the original number of equation equation_number belonging to the block block_number
315 virtual int getBlockEquationID(int block_number, int equation_number) const = 0;
316 //! Return the original number of variable variable_number belonging to the block block_number
317 virtual int getBlockVariableID(int block_number, int variable_number) const = 0;
318 //! Return the original number of the exogenous variable varexo_number belonging to the block block_number
319 virtual int getBlockVariableExoID(int block_number, int variable_number) const = 0;
320 //! Return the position of equation_number in the block number belonging to the block block_number
321 virtual int getBlockInitialEquationID(int block_number, int equation_number) const = 0;
322 //! Return the position of variable_number in the block number belonging to the block block_number
323 virtual int getBlockInitialVariableID(int block_number, int variable_number) const = 0;
324 //! Return the position of variable_number in the block number belonging to the block block_number
325 virtual int getBlockInitialExogenousID(int block_number, int variable_number) const = 0;
326 //! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number
327 virtual int getBlockInitialDetExogenousID(int block_number, int variable_number) const = 0;
328 //! Return the position of the other endogenous variable_number in the block number belonging to the block block_number
329 virtual int getBlockInitialOtherEndogenousID(int block_number, int variable_number) const = 0;
330 //! Initialize equation_reordered & variable_reordered
331 void initializeVariablesAndEquations();
332
333 private:
334 //! Internal helper for the copy constructor and assignment operator
335 /*! Copies all the structures that contain ExprNode*, by the converting the
336 pointers into their equivalent in the new tree */
337 void copyHelper(const ModelTree &m);
338 //! Returns the name of the MATLAB architecture given the extension used for MEX files
339 static string matlab_arch(const string &mexext);
340 //! Compiles the MEX file
341 void compileDll(const string &basename, const string &static_or_dynamic, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot) const;
342
343 public:
344 ModelTree(SymbolTable &symbol_table_arg,
345 NumericalConstants &num_constants_arg,
346 ExternalFunctionsTable &external_functions_table_arg,
347 bool is_dynamic_arg = false);
348
349 ModelTree(const ModelTree &m);
350 ModelTree(ModelTree &&) = delete;
351 ModelTree &operator=(const ModelTree &m);
352 ModelTree &operator=(ModelTree &&) = delete;
353
354 //! Absolute value under which a number is considered to be zero
355 double cutoff{1e-15};
356 //! Compute the minimum feedback set
357 /*! 0 : all endogenous variables are considered as feedback variables
358 1 : the variables belonging to non normalized equation are considered as feedback variables
359 2 : the variables belonging to a non linear equation are considered as feedback variables
360 3 : the variables belonging to a non normalizable non linear equation are considered as feedback variables
361 default value = 0 */
362 int mfs{0};
363 //! Declare a node as an equation of the model; also give its line number
364 void addEquation(expr_t eq, int lineno);
365 //! Declare a node as an equation of the model, also giving its tags
366 void addEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
367 //! Declare a node as an auxiliary equation of the model, adding it at the end of the list of auxiliary equations
368 void addAuxEquation(expr_t eq);
369 //! Returns the number of equations in the model
370 int equation_number() const;
371 //! Adds a trend variable with its growth factor
372 void addTrendVariables(const vector<int> &trend_vars, expr_t growth_factor) noexcept(false);
373 //! Adds a nonstationary variables with their (common) deflator
374 void addNonstationaryVariables(const vector<int> &nonstationary_vars, bool log_deflator, expr_t deflator) noexcept(false);
375 //! Is a given variable non-stationary?
376 bool isNonstationary(int symb_id) const;
377 void set_cutoff_to_zero();
378 //! Simplify model equations: if a variable is equal to a constant, replace that variable elsewhere in the model
379 /*! Equations with tags are excluded, in particular because of MCPs, see
380 dynare#1697 */
381 void simplifyEquations();
382 /*! Reorder auxiliary variables so that they appear in recursive order in
383 set_auxiliary_variables.m and dynamic_set_auxiliary_series.m */
384 void reorderAuxiliaryEquations();
385 //! Find equations of the form “variable=constant”, excluding equations with tags
386 void findConstantEquationsWithoutTags(map<VariableNode *, NumConstNode *> &subst_table) const;
387 //! Helper for writing the Jacobian elements in MATLAB and C
388 /*! Writes either (i+1,j+1) or [i+j*no_eq] */
389 void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
390 //! Helper for writing the sparse Hessian or third derivatives in MATLAB and C
391 /*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[2]]
392 If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[3]] */
393 void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const;
394
395 //! Returns all the equation tags associated to an equation
396 inline map<string, string>
getEquationTags(int eq) const397 getEquationTags(int eq) const
398 {
399 map<string, string> r;
400 for (auto &[eq2, tagpair] : equation_tags)
401 if (eq2 == eq)
402 r[tagpair.first] = tagpair.second;
403 return r;
404 }
405
406 inline static string
c_Equation_Type(int type)407 c_Equation_Type(int type)
408 {
409 vector<string> c_Equation_Type =
410 {
411 "E_UNKNOWN ",
412 "E_EVALUATE ",
413 "E_EVALUATE_S",
414 "E_SOLVE "
415 };
416 return c_Equation_Type[type];
417 };
418
419 inline static string
BlockType0(BlockType type)420 BlockType0(BlockType type)
421 {
422 switch (type)
423 {
424 case SIMULTANS:
425 return "SIMULTANEOUS TIME SEPARABLE ";
426 case PROLOGUE:
427 return "PROLOGUE ";
428 case EPILOGUE:
429 return "EPILOGUE ";
430 case SIMULTAN:
431 return "SIMULTANEOUS TIME UNSEPARABLE";
432 default:
433 return "UNKNOWN ";
434 }
435 };
436
437 inline static string
BlockSim(int type)438 BlockSim(int type)
439 {
440 switch (type)
441 {
442 case EVALUATE_FORWARD:
443 return "EVALUATE FORWARD ";
444 case EVALUATE_BACKWARD:
445 return "EVALUATE BACKWARD ";
446 case SOLVE_FORWARD_SIMPLE:
447 return "SOLVE FORWARD SIMPLE ";
448 case SOLVE_BACKWARD_SIMPLE:
449 return "SOLVE BACKWARD SIMPLE ";
450 case SOLVE_TWO_BOUNDARIES_SIMPLE:
451 return "SOLVE TWO BOUNDARIES SIMPLE ";
452 case SOLVE_FORWARD_COMPLETE:
453 return "SOLVE FORWARD COMPLETE ";
454 case SOLVE_BACKWARD_COMPLETE:
455 return "SOLVE BACKWARD COMPLETE ";
456 case SOLVE_TWO_BOUNDARIES_COMPLETE:
457 return "SOLVE TWO BOUNDARIES COMPLETE";
458 default:
459 return "UNKNOWN ";
460 }
461 };
462 };
463
464 #endif
465