1 /*
2  * Copyright © 2005-2011 Ondra Kamenik
3  * Copyright © 2019 Dynare Team
4  *
5  * This file is part of Dynare.
6  *
7  * Dynare is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dynare is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #ifndef OGDYN_DYNARE_MODEL
22 #define OGDYN_DYNARE_MODEL
23 
24 #include "parser/cc/matrix_parser.hh"
25 #include "parser/cc/atom_assignings.hh"
26 
27 #include "dynare_atoms.hh"
28 #include "twod_matrix.hh"
29 #include "planner_builder.hh"
30 #include "forw_subst_builder.hh"
31 
32 #include "Vector.hh"
33 #include "GeneralMatrix.hh"
34 
35 #include <map>
36 #include <unordered_set>
37 #include <ostream>
38 #include <memory>
39 #include <iostream>
40 
41 namespace ogdyn
42 {
43   using std::unordered_set;
44   using std::map;
45 
46   /* This represents an interval in a string by the pair of positions
47      (including the first, excluding the second). A position is given by the
48      line and the column within the line (both starting from 1). */
49   struct PosInterval
50   {
51     int fl;
52     int fc;
53     int ll;
54     int lc;
55     PosInterval() = default;
PosIntervalogdyn::PosInterval56     PosInterval(int ifl, int ifc, int ill, int ilc)
57       : fl(ifl), fc(ifc), ll(ill), lc(ilc)
58     {
59     }
60     PosInterval &operator=(const PosInterval &pi) = default;
61     /* Debug print. */
62     void
printogdyn::PosInterval63     print() const
64     {
65       std::cout << "fl=" << fl << " fc=" << fc << " ll=" << ll << " lc=" << lc << '\n';
66     }
67   };
68 
69   /* This class is basically a GeneralMatrix but is created from parsed matrix
70      data. */
71   class ParsedMatrix : public TwoDMatrix
72   {
73   public:
74     /* Construct the object from the parsed data of ogp::MatrixParser. */
75     ParsedMatrix(const ogp::MatrixParser &mp);
76   };
77 
78   class PlannerBuilder;
79   class PlannerInfo;
80   class ForwSubstBuilder;
81   class ForwSubstInfo;
82   class MultInitSS;
83   class ModelSSWriter;
84 
85   /* A subclass is responsible for creating param_vals, init_vals, and
86      vcov_mat. */
87   class DynareModel
88   {
89     friend class PlannerBuilder;
90     friend class ForwSubstBuilder;
91     friend class MultInitSS;
92     friend class ModelSSWriter;
93   protected:
94     /* All atoms for whole model. */
95     DynareDynamicAtoms atoms;
96     /* Parsed model equations. */
97     ogp::FormulaParser eqs;
98     /* Order of approximation. */
99     int order{-1};
100     /* A vector of parameters values created by a subclass. It is stored with
101        natural ordering (outer) of the parameters given by atoms. */
102     std::unique_ptr<Vector> param_vals;
103     /* A vector of initial values created by a subclass. It is stored with
104        internal ordering given by atoms. */
105     std::unique_ptr<Vector> init_vals;
106     /* A matrix for vcov. It is created by a subclass. */
107     std::unique_ptr<TwoDMatrix> vcov_mat;
108     /* Tree index of the planner objective. If there was no planner objective
109        keyword, the value is set to −1. */
110     int t_plobjective{-1};
111     /* Tree index of the planner discount. If there was no planner discount
112        keyword, the value is set to −1. */
113     int t_pldiscount{-1};
114     /* Pointer to PlannerBuilder, which is created only if the planner's FOC
115        are added to the model. */
116     std::unique_ptr<PlannerBuilder> pbuilder;
117     /* Pointer to an object which builds auxiliary variables and equations to
118        rewrite a model containing multiple leads to an equivalent model having
119        only +1 leads. */
120     std::unique_ptr<ForwSubstBuilder> fbuilder;
121     /* Pointer to AtomSubstitutions which are created when the atoms are being
122        substituted because of multiple lags etc. It uses also an old copy of
123        atoms, which is created. */
124     std::unique_ptr<ogp::AtomSubstitutions> atom_substs;
125     /* Pointer to a copy of original atoms before substitutions took place. */
126     std::unique_ptr<ogp::SAtoms> old_atoms;
127   public:
128     /* Initializes the object to an empty state. */
129     DynareModel();
130     /* Construct a new deep copy. */
131     DynareModel(const DynareModel &dm);
132     virtual ~DynareModel() = default;
133     virtual std::unique_ptr<DynareModel> clone() const = 0;
134     const DynareDynamicAtoms &
getAtoms() const135     getAtoms() const
136     {
137       return atoms;
138     }
139     const ogp::FormulaParser &
getParser() const140     getParser() const
141     {
142       return eqs;
143     }
144     int
getOrder() const145     getOrder() const
146     {
147       return order;
148     }
149     /* Return the vector of parameter values. */
150     const Vector &
getParams() const151     getParams() const
152     {
153       return *param_vals;
154     }
155     Vector &
getParams()156     getParams()
157     {
158       return *param_vals;
159     }
160     /* Return the vector of initial values of endo variables. */
161     const Vector &
getInit() const162     getInit() const
163     {
164       return *init_vals;
165     }
166     Vector &
getInit()167     getInit()
168     {
169       return *init_vals;
170     }
171     /* Return the vcov matrix. */
172     const TwoDMatrix &
getVcov() const173     getVcov() const
174     {
175       return *vcov_mat;
176     }
177     TwoDMatrix &
getVcov()178     getVcov()
179     {
180       return *vcov_mat;
181     }
182     /* Return planner info. */
183     const PlannerInfo *get_planner_info() const;
184     /* Return forward substitutions info. */
185     const ForwSubstInfo *get_forw_subst_info() const;
186     /* Return substitutions info. */
187     const ogp::SubstInfo *get_subst_info() const;
188     /* This sets initial values given in outer ordering. */
189     void setInitOuter(const Vector &x);
190     /* This returns true if the given term is a function of hardwired
191        constants, numerical constants and parameters. */
192     bool is_constant_term(int t) const;
193     /* Debug print. */
194     void print() const;
195     /* Dump the model to the output stream. This includes variable
196        declarations, parameter values, model code, initval, vcov and order. */
197     void dump_model(std::ostream &os) const;
198   protected:
199     /* Adds a name of endogenous, exogenous or a parameter. The sort is
200        governed by the flag. See dynglob.yy for values of the flag. This is
201        used by a subclass when declaring the names. */
202     void add_name(std::string name, int flag);
203     /* This checks the model consistency. Thus includes: number of endo
204        variables and number of equations, min and max lag of endogenous
205        variables and occurrrences of exogenous variables. It throws an
206        exception, if there is a problem. */
207     void check_model() const;
208     /* This shifts the given variable identified by the tree index in time. So
209        if the given tree index represents a(+3) and the tshift is −4, the
210        method returns tree index of the a(-1). If a(-1) doesn't exist, it is
211        added to the tree. If it exists, its tree index is returned. If the tree
212        index doesn't correspond to an endogenous nor exogenous variable, an
213        exception is thrown. */
214     int variable_shift(int t, int tshift);
215     /* For the given set of atoms identified by tree indices and given time
216        shift, this method returns a map mapping each variable in the given set
217        to its time shifted variable. The map is passed through the reference
218        and is cleared in the beginning. */
219     void variable_shift_map(const unordered_set<int> &a_set, int tshift,
220                             map<int, int> &s_map);
221     /* This returns maximum lead and minimum lag of an endogenous or exogenous
222        variable in the given term. If there are no endo or exo variables, than
223        it returns the least integer as max lead and the greatest integer as min
224        lag. */
225     void termspan(int t, int &mlead, int &mlag) const;
226     /* This function returns a set of non-linear subterms of the given term,
227        these are terms whose linear combination constitutes the given term. */
228     unordered_set<int> get_nonlinear_subterms(int t) const;
229     /* This method assigns already used tree index of some term to the not-yet
230        used atom name with the given lead/lag. In this way, all occurrences of
231        term t are substituted with the atom name(ll). The method handles also
232        rewriting operation tree including derivatives of the term t. */
233     void substitute_atom_for_term(const string &name, int ll, int t);
234     /* This performs a final job after the model is parsed. It creates the
235        PlannerBuilder object if the planner's FOC are needed, then it creates
236        ForwSubstBuilder handling multiple leads and finally it creates the
237        substitution object saving old atoms and performs the substitutions. */
238     void final_job();
239   };
240 
241   /* This class constructs DynareModel from dynare++ model file. It parses
242      variable declarations, model equations, parameter assignments, initval
243      assignments, vcov matrix and order of approximation. */
244   class DynareParser : public DynareModel
245   {
246   protected:
247     /* Static atoms for parameter assignments. */
248     DynareStaticAtoms pa_atoms;
249     /* Assignments for the parameters. */
250     ogp::AtomAssignings paramset;
251     /* Static atoms for initval assignments. */
252     DynareStaticAtoms ia_atoms;
253     /* Assignments for the initval. */
254     ogp::AtomAssignings initval;
255     /* Matrix parser for vcov. */
256     ogp::MatrixParser vcov;
257   public:
258     /* This, in fact, creates DynareModel from the given string of the given
259        length corresponding to the Dynare++ model file. If the given ord is not
260        −1, then it overrides setting in the model file. */
261     DynareParser(const string &str, int ord);
262     DynareParser(const DynareParser &dp);
263     std::unique_ptr<DynareModel>
clone() const264     clone() const override
265     {
266       return std::make_unique<DynareParser>(*this);
267     }
268     /* Adds a name of endogenous, exogenous or a parameter. This addss the name
269        to the parent class DynareModel and also registers the name to either
270        paramset, or initval. */
271     void add_name(string name, int flag);
272     /* Sets position of the model section. Called from dynglob.yy. */
273     void
set_model_pos(int off1,int off2)274     set_model_pos(int off1, int off2)
275     {
276       model_beg = off1;
277       model_end = off2;
278     }
279     /* Sets position of the section setting parameters. Called from
280        dynglob.yy. */
281     void
set_paramset_pos(int off1,int off2)282     set_paramset_pos(int off1, int off2)
283     {
284       paramset_beg = off1;
285       paramset_end = off2;
286     }
287     /* Sets position of the initval section. Called from dynglob.yy. */
288     void
set_initval_pos(int off1,int off2)289     set_initval_pos(int off1, int off2)
290     {
291       initval_beg = off1;
292       initval_end = off2;
293     }
294     /* Sets position of the vcov section. Called from dynglob.yy. */
295     void
set_vcov_pos(int off1,int off2)296     set_vcov_pos(int off1, int off2)
297     {
298       vcov_beg = off1;
299       vcov_end = off2;
300     }
301     /* Parser the given string as integer and set to as the order. */
302     void
set_order_pos(int off1,int off2)303     set_order_pos(int off1, int off2)
304     {
305       order_beg = off1;
306       order_end = off2;
307     }
308     /* Sets position of the planner_objective section. Called from
309        dynglob.yy. */
310     void
set_pl_objective_pos(int off1,int off2)311     set_pl_objective_pos(int off1, int off2)
312     {
313       plobjective_beg = off1;
314       plobjective_end = off2;
315     }
316     /* Sets position of the planner_discount section. Called from
317        dynglob.yy. */
318     void
set_pl_discount_pos(int off1,int off2)319     set_pl_discount_pos(int off1, int off2)
320     {
321       pldiscount_beg = off1;
322       pldiscount_end = off2;
323     }
324     /* Processes a syntax error from bison. */
325     void error(string mes);
326     /* Debug print. */
327     void print() const;
328   protected:
329     void parse_glob(const string &stream);
330     int parse_order(const string &stream);
331     int parse_pldiscount(const string &stream);
332     /* Evaluate paramset assignings and set param_vals. */
333     void calc_params();
334     /* Evaluate initval assignings and set init_vals. */
335     void calc_init();
336     /* Do the final job. This includes building the planner problem (if any)
337        and substituting for multiple lags, and one period leads of exogenous
338        variables, and calculating initial guess of lagrange multipliers in the
339        social planner problem. Precondtion: everything parsed and calculated
340        parameters, postcondition: calculated initvals vector and
341        parsing_finished for expanded vectors. */
342     void final_job();
343   private:
344     int model_beg, model_end;
345     int paramset_beg, paramset_end;
346     int initval_beg, initval_end;
347     int vcov_beg, vcov_end;
348     int order_beg, order_end;
349     int plobjective_beg, plobjective_end;
350     int pldiscount_beg, pldiscount_end;
351   };
352 
353   /* Semiparsed model. The equations are given by a string, everything other by
354      C++ objects. The initial values are set manually after the creation of
355      this object. This implies that no automatic substitutions cannot be done
356      here, which in turn implies that we cannot do here a social planner nor
357      substitutions of multiple lags. */
358   class DynareSPModel : public DynareModel
359   {
360   public:
361     DynareSPModel(const std::vector<std::string> &endo,
362                   const std::vector<std::string> &exo,
363                   const std::vector<std::string> &par,
364                   const string &equations, int ord);
365     DynareSPModel(const DynareSPModel &dm) = default;
366     ~DynareSPModel() override = default;
367     std::unique_ptr<DynareModel>
clone() const368     clone() const override
369     {
370       return std::make_unique<DynareSPModel>(*this);
371     }
372   };
373 
374   /* This class implements a selector of operations which correspond to
375      non-linear functions. This inherits from ogp::opselector and is used to
376      calculate non-linear subterms in DynareModel::get_nonlinear_subterms(). */
377   class NLSelector : public ogp::opselector
378   {
379   private:
380     const DynareModel &model;
381   public:
NLSelector(const DynareModel & m)382     NLSelector(const DynareModel &m) : model(m)
383     {
384     }
385     bool operator()(int t) const override;
386   };
387 
388   /* This class writes a mathematical code evaluating the system of equations
389      and the first derivatives at zero shocks and at the given (static) state.
390      Static means that lags and leads are ignored. */
391   class ModelSSWriter : public ogp::DefaultOperationFormatter
392   {
393   protected:
394     const DynareModel &model;
395   public:
ModelSSWriter(const DynareModel & m)396     ModelSSWriter(const DynareModel &m)
397       : DefaultOperationFormatter(m.eqs.getTree()),
398         model(m)
399     {
400     }
401     /* This writes the evaluation of the system. It calls pure virtual methods
402        for writing a preamble, then assignment of atoms, and then assignment
403        for resulting object. These are language dependent and are implemented
404        in the subclass. */
405     void write_der0(std::ostream &os);
406     /* This writes the evaluation of the first order derivative of the system.
407        It calls pure virtual methods for writing a preamble, assignment, and
408        assignemnt of the resulting objects. */
409     void write_der1(std::ostream &os);
410   protected:
411     virtual void write_der0_preamble(std::ostream &os) const = 0;
412     virtual void write_der1_preamble(std::ostream &os) const = 0;
413     virtual void write_atom_assignment(std::ostream &os) const = 0;
414     virtual void write_der0_assignment(std::ostream &os) const = 0;
415     virtual void write_der1_assignment(std::ostream &os) const = 0;
416   };
417 
418   class MatlabSSWriter : public ModelSSWriter
419   {
420   protected:
421     /* Identifier used in function names. */
422     std::string id;
423   public:
424     MatlabSSWriter(const DynareModel &dm, std::string id_arg);
425   protected:
426     // from ModelSSWriter
427     void write_der0_preamble(std::ostream &os) const override;
428     void write_der1_preamble(std::ostream &os) const override;
429     /* This writes atom assignments. We have four kinds of atoms set here:
430        endogenous vars coming from one parameter, parameter values given by the
431        second parameter, constants, and the OperationTree::num_constants
432        hardwired constants in ogp::OperationTree. */
433     void write_atom_assignment(std::ostream &os) const override;
434     void write_der0_assignment(std::ostream &os) const override;
435     void write_der1_assignment(std::ostream &os) const override;
436     /* This prints t10 for t=10. */
437     void format_term(int t, std::ostream &os) const override;
438     /* This prints a10 for t=10. The atoms a10 are supposed to be set by
439        write_atom_assignments(). */
440     void format_nulary(int t, std::ostream &os) const override;
441   private:
442     void write_common1_preamble(std::ostream &os) const;
443     void write_common2_preamble(std::ostream &os) const;
444   };
445 
446   /* This class implements OperationFormatter for debugging purposes. It
447      renders atoms in a more friendly way than the
448      ogp::DefaulOperationFormatter. */
449   class DebugOperationFormatter : public ogp::DefaultOperationFormatter
450   {
451   protected:
452     const DynareModel &model;
453   public:
DebugOperationFormatter(const DynareModel & m)454     DebugOperationFormatter(const DynareModel &m)
455       : DefaultOperationFormatter(m.getParser().getTree()),
456         model(m)
457     {
458     }
459     void format_nulary(int t, std::ostream &os) const override;
460   };
461 };
462 
463 #endif
464