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