464 lines
16 KiB
C++
464 lines
16 KiB
C++
/*
|
||
* Copyright © 2005-2011 Ondra Kamenik
|
||
* Copyright © 2019 Dynare Team
|
||
*
|
||
* This file is part of Dynare.
|
||
*
|
||
* Dynare is free software: you can redistribute it and/or modify
|
||
* it under the terms of the GNU General Public License as published by
|
||
* the Free Software Foundation, either version 3 of the License, or
|
||
* (at your option) any later version.
|
||
*
|
||
* Dynare is distributed in the hope that it will be useful,
|
||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
* GNU General Public License for more details.
|
||
*
|
||
* You should have received a copy of the GNU General Public License
|
||
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
||
*/
|
||
|
||
#ifndef OGDYN_DYNARE_MODEL
|
||
#define OGDYN_DYNARE_MODEL
|
||
|
||
#include "parser/cc/matrix_parser.hh"
|
||
#include "parser/cc/atom_assignings.hh"
|
||
|
||
#include "dynare_atoms.hh"
|
||
#include "twod_matrix.hh"
|
||
#include "planner_builder.hh"
|
||
#include "forw_subst_builder.hh"
|
||
|
||
#include "Vector.hh"
|
||
#include "GeneralMatrix.hh"
|
||
|
||
#include <map>
|
||
#include <unordered_set>
|
||
#include <ostream>
|
||
#include <memory>
|
||
#include <iostream>
|
||
|
||
namespace ogdyn
|
||
{
|
||
using std::unordered_set;
|
||
using std::map;
|
||
|
||
/* This represents an interval in a string by the pair of positions
|
||
(including the first, excluding the second). A position is given by the
|
||
line and the column within the line (both starting from 1). */
|
||
struct PosInterval
|
||
{
|
||
int fl;
|
||
int fc;
|
||
int ll;
|
||
int lc;
|
||
PosInterval() = default;
|
||
PosInterval(int ifl, int ifc, int ill, int ilc)
|
||
: fl(ifl), fc(ifc), ll(ill), lc(ilc)
|
||
{
|
||
}
|
||
PosInterval &operator=(const PosInterval &pi) = default;
|
||
/* Debug print. */
|
||
void
|
||
print() const
|
||
{
|
||
std::cout << "fl=" << fl << " fc=" << fc << " ll=" << ll << " lc=" << lc << '\n';
|
||
}
|
||
};
|
||
|
||
/* This class is basically a GeneralMatrix but is created from parsed matrix
|
||
data. */
|
||
class ParsedMatrix : public TwoDMatrix
|
||
{
|
||
public:
|
||
/* Construct the object from the parsed data of ogp::MatrixParser. */
|
||
ParsedMatrix(const ogp::MatrixParser &mp);
|
||
};
|
||
|
||
class PlannerBuilder;
|
||
class PlannerInfo;
|
||
class ForwSubstBuilder;
|
||
class ForwSubstInfo;
|
||
class MultInitSS;
|
||
class ModelSSWriter;
|
||
|
||
/* A subclass is responsible for creating param_vals, init_vals, and
|
||
vcov_mat. */
|
||
class DynareModel
|
||
{
|
||
friend class PlannerBuilder;
|
||
friend class ForwSubstBuilder;
|
||
friend class MultInitSS;
|
||
friend class ModelSSWriter;
|
||
protected:
|
||
/* All atoms for whole model. */
|
||
DynareDynamicAtoms atoms;
|
||
/* Parsed model equations. */
|
||
ogp::FormulaParser eqs;
|
||
/* Order of approximation. */
|
||
int order{-1};
|
||
/* A vector of parameters values created by a subclass. It is stored with
|
||
natural ordering (outer) of the parameters given by atoms. */
|
||
std::unique_ptr<Vector> param_vals;
|
||
/* A vector of initial values created by a subclass. It is stored with
|
||
internal ordering given by atoms. */
|
||
std::unique_ptr<Vector> init_vals;
|
||
/* A matrix for vcov. It is created by a subclass. */
|
||
std::unique_ptr<TwoDMatrix> vcov_mat;
|
||
/* Tree index of the planner objective. If there was no planner objective
|
||
keyword, the value is set to −1. */
|
||
int t_plobjective{-1};
|
||
/* Tree index of the planner discount. If there was no planner discount
|
||
keyword, the value is set to −1. */
|
||
int t_pldiscount{-1};
|
||
/* Pointer to PlannerBuilder, which is created only if the planner's FOC
|
||
are added to the model. */
|
||
std::unique_ptr<PlannerBuilder> pbuilder;
|
||
/* Pointer to an object which builds auxiliary variables and equations to
|
||
rewrite a model containing multiple leads to an equivalent model having
|
||
only +1 leads. */
|
||
std::unique_ptr<ForwSubstBuilder> fbuilder;
|
||
/* Pointer to AtomSubstitutions which are created when the atoms are being
|
||
substituted because of multiple lags etc. It uses also an old copy of
|
||
atoms, which is created. */
|
||
std::unique_ptr<ogp::AtomSubstitutions> atom_substs;
|
||
/* Pointer to a copy of original atoms before substitutions took place. */
|
||
std::unique_ptr<ogp::SAtoms> old_atoms;
|
||
public:
|
||
/* Initializes the object to an empty state. */
|
||
DynareModel();
|
||
/* Construct a new deep copy. */
|
||
DynareModel(const DynareModel &dm);
|
||
virtual ~DynareModel() = default;
|
||
virtual std::unique_ptr<DynareModel> clone() const = 0;
|
||
const DynareDynamicAtoms &
|
||
getAtoms() const
|
||
{
|
||
return atoms;
|
||
}
|
||
const ogp::FormulaParser &
|
||
getParser() const
|
||
{
|
||
return eqs;
|
||
}
|
||
int
|
||
getOrder() const
|
||
{
|
||
return order;
|
||
}
|
||
/* Return the vector of parameter values. */
|
||
const Vector &
|
||
getParams() const
|
||
{
|
||
return *param_vals;
|
||
}
|
||
Vector &
|
||
getParams()
|
||
{
|
||
return *param_vals;
|
||
}
|
||
/* Return the vector of initial values of endo variables. */
|
||
const Vector &
|
||
getInit() const
|
||
{
|
||
return *init_vals;
|
||
}
|
||
Vector &
|
||
getInit()
|
||
{
|
||
return *init_vals;
|
||
}
|
||
/* Return the vcov matrix. */
|
||
const TwoDMatrix &
|
||
getVcov() const
|
||
{
|
||
return *vcov_mat;
|
||
}
|
||
TwoDMatrix &
|
||
getVcov()
|
||
{
|
||
return *vcov_mat;
|
||
}
|
||
/* Return planner info. */
|
||
const PlannerInfo *get_planner_info() const;
|
||
/* Return forward substitutions info. */
|
||
const ForwSubstInfo *get_forw_subst_info() const;
|
||
/* Return substitutions info. */
|
||
const ogp::SubstInfo *get_subst_info() const;
|
||
/* This sets initial values given in outer ordering. */
|
||
void setInitOuter(const Vector &x);
|
||
/* This returns true if the given term is a function of hardwired
|
||
constants, numerical constants and parameters. */
|
||
bool is_constant_term(int t) const;
|
||
/* Debug print. */
|
||
void print() const;
|
||
/* Dump the model to the output stream. This includes variable
|
||
declarations, parameter values, model code, initval, vcov and order. */
|
||
void dump_model(std::ostream &os) const;
|
||
protected:
|
||
/* Adds a name of endogenous, exogenous or a parameter. The sort is
|
||
governed by the flag. See dynglob.yy for values of the flag. This is
|
||
used by a subclass when declaring the names. */
|
||
void add_name(std::string name, int flag);
|
||
/* This checks the model consistency. Thus includes: number of endo
|
||
variables and number of equations, min and max lag of endogenous
|
||
variables and occurrrences of exogenous variables. It throws an
|
||
exception, if there is a problem. */
|
||
void check_model() const;
|
||
/* This shifts the given variable identified by the tree index in time. So
|
||
if the given tree index represents a(+3) and the tshift is −4, the
|
||
method returns tree index of the a(-1). If a(-1) doesn't exist, it is
|
||
added to the tree. If it exists, its tree index is returned. If the tree
|
||
index doesn't correspond to an endogenous nor exogenous variable, an
|
||
exception is thrown. */
|
||
int variable_shift(int t, int tshift);
|
||
/* For the given set of atoms identified by tree indices and given time
|
||
shift, this method returns a map mapping each variable in the given set
|
||
to its time shifted variable. The map is passed through the reference
|
||
and is cleared in the beginning. */
|
||
void variable_shift_map(const unordered_set<int> &a_set, int tshift,
|
||
map<int, int> &s_map);
|
||
/* This returns maximum lead and minimum lag of an endogenous or exogenous
|
||
variable in the given term. If there are no endo or exo variables, than
|
||
it returns the least integer as max lead and the greatest integer as min
|
||
lag. */
|
||
void termspan(int t, int &mlead, int &mlag) const;
|
||
/* This function returns a set of non-linear subterms of the given term,
|
||
these are terms whose linear combination constitutes the given term. */
|
||
unordered_set<int> get_nonlinear_subterms(int t) const;
|
||
/* This method assigns already used tree index of some term to the not-yet
|
||
used atom name with the given lead/lag. In this way, all occurrences of
|
||
term t are substituted with the atom name(ll). The method handles also
|
||
rewriting operation tree including derivatives of the term t. */
|
||
void substitute_atom_for_term(const string &name, int ll, int t);
|
||
/* This performs a final job after the model is parsed. It creates the
|
||
PlannerBuilder object if the planner's FOC are needed, then it creates
|
||
ForwSubstBuilder handling multiple leads and finally it creates the
|
||
substitution object saving old atoms and performs the substitutions. */
|
||
void final_job();
|
||
};
|
||
|
||
/* This class constructs DynareModel from dynare++ model file. It parses
|
||
variable declarations, model equations, parameter assignments, initval
|
||
assignments, vcov matrix and order of approximation. */
|
||
class DynareParser : public DynareModel
|
||
{
|
||
protected:
|
||
/* Static atoms for parameter assignments. */
|
||
DynareStaticAtoms pa_atoms;
|
||
/* Assignments for the parameters. */
|
||
ogp::AtomAssignings paramset;
|
||
/* Static atoms for initval assignments. */
|
||
DynareStaticAtoms ia_atoms;
|
||
/* Assignments for the initval. */
|
||
ogp::AtomAssignings initval;
|
||
/* Matrix parser for vcov. */
|
||
ogp::MatrixParser vcov;
|
||
public:
|
||
/* This, in fact, creates DynareModel from the given string of the given
|
||
length corresponding to the Dynare++ model file. If the given ord is not
|
||
−1, then it overrides setting in the model file. */
|
||
DynareParser(const string &str, int ord);
|
||
DynareParser(const DynareParser &dp);
|
||
std::unique_ptr<DynareModel>
|
||
clone() const override
|
||
{
|
||
return std::make_unique<DynareParser>(*this);
|
||
}
|
||
/* Adds a name of endogenous, exogenous or a parameter. This addss the name
|
||
to the parent class DynareModel and also registers the name to either
|
||
paramset, or initval. */
|
||
void add_name(string name, int flag);
|
||
/* Sets position of the model section. Called from dynglob.yy. */
|
||
void
|
||
set_model_pos(int off1, int off2)
|
||
{
|
||
model_beg = off1;
|
||
model_end = off2;
|
||
}
|
||
/* Sets position of the section setting parameters. Called from
|
||
dynglob.yy. */
|
||
void
|
||
set_paramset_pos(int off1, int off2)
|
||
{
|
||
paramset_beg = off1;
|
||
paramset_end = off2;
|
||
}
|
||
/* Sets position of the initval section. Called from dynglob.yy. */
|
||
void
|
||
set_initval_pos(int off1, int off2)
|
||
{
|
||
initval_beg = off1;
|
||
initval_end = off2;
|
||
}
|
||
/* Sets position of the vcov section. Called from dynglob.yy. */
|
||
void
|
||
set_vcov_pos(int off1, int off2)
|
||
{
|
||
vcov_beg = off1;
|
||
vcov_end = off2;
|
||
}
|
||
/* Parser the given string as integer and set to as the order. */
|
||
void
|
||
set_order_pos(int off1, int off2)
|
||
{
|
||
order_beg = off1;
|
||
order_end = off2;
|
||
}
|
||
/* Sets position of the planner_objective section. Called from
|
||
dynglob.yy. */
|
||
void
|
||
set_pl_objective_pos(int off1, int off2)
|
||
{
|
||
plobjective_beg = off1;
|
||
plobjective_end = off2;
|
||
}
|
||
/* Sets position of the planner_discount section. Called from
|
||
dynglob.yy. */
|
||
void
|
||
set_pl_discount_pos(int off1, int off2)
|
||
{
|
||
pldiscount_beg = off1;
|
||
pldiscount_end = off2;
|
||
}
|
||
/* Processes a syntax error from bison. */
|
||
void error(string mes);
|
||
/* Debug print. */
|
||
void print() const;
|
||
protected:
|
||
void parse_glob(const string &stream);
|
||
int parse_order(const string &stream);
|
||
int parse_pldiscount(const string &stream);
|
||
/* Evaluate paramset assignings and set param_vals. */
|
||
void calc_params();
|
||
/* Evaluate initval assignings and set init_vals. */
|
||
void calc_init();
|
||
/* Do the final job. This includes building the planner problem (if any)
|
||
and substituting for multiple lags, and one period leads of exogenous
|
||
variables, and calculating initial guess of lagrange multipliers in the
|
||
social planner problem. Precondtion: everything parsed and calculated
|
||
parameters, postcondition: calculated initvals vector and
|
||
parsing_finished for expanded vectors. */
|
||
void final_job();
|
||
private:
|
||
int model_beg, model_end;
|
||
int paramset_beg, paramset_end;
|
||
int initval_beg, initval_end;
|
||
int vcov_beg, vcov_end;
|
||
int order_beg, order_end;
|
||
int plobjective_beg, plobjective_end;
|
||
int pldiscount_beg, pldiscount_end;
|
||
};
|
||
|
||
/* Semiparsed model. The equations are given by a string, everything other by
|
||
C++ objects. The initial values are set manually after the creation of
|
||
this object. This implies that no automatic substitutions cannot be done
|
||
here, which in turn implies that we cannot do here a social planner nor
|
||
substitutions of multiple lags. */
|
||
class DynareSPModel : public DynareModel
|
||
{
|
||
public:
|
||
DynareSPModel(const std::vector<std::string> &endo,
|
||
const std::vector<std::string> &exo,
|
||
const std::vector<std::string> &par,
|
||
const string &equations, int ord);
|
||
DynareSPModel(const DynareSPModel &dm) = default;
|
||
~DynareSPModel() override = default;
|
||
std::unique_ptr<DynareModel>
|
||
clone() const override
|
||
{
|
||
return std::make_unique<DynareSPModel>(*this);
|
||
}
|
||
};
|
||
|
||
/* This class implements a selector of operations which correspond to
|
||
non-linear functions. This inherits from ogp::opselector and is used to
|
||
calculate non-linear subterms in DynareModel::get_nonlinear_subterms(). */
|
||
class NLSelector : public ogp::opselector
|
||
{
|
||
private:
|
||
const DynareModel &model;
|
||
public:
|
||
NLSelector(const DynareModel &m) : model(m)
|
||
{
|
||
}
|
||
bool operator()(int t) const override;
|
||
};
|
||
|
||
/* This class writes a mathematical code evaluating the system of equations
|
||
and the first derivatives at zero shocks and at the given (static) state.
|
||
Static means that lags and leads are ignored. */
|
||
class ModelSSWriter : public ogp::DefaultOperationFormatter
|
||
{
|
||
protected:
|
||
const DynareModel &model;
|
||
public:
|
||
ModelSSWriter(const DynareModel &m)
|
||
: DefaultOperationFormatter(m.eqs.getTree()),
|
||
model(m)
|
||
{
|
||
}
|
||
/* This writes the evaluation of the system. It calls pure virtual methods
|
||
for writing a preamble, then assignment of atoms, and then assignment
|
||
for resulting object. These are language dependent and are implemented
|
||
in the subclass. */
|
||
void write_der0(std::ostream &os);
|
||
/* This writes the evaluation of the first order derivative of the system.
|
||
It calls pure virtual methods for writing a preamble, assignment, and
|
||
assignemnt of the resulting objects. */
|
||
void write_der1(std::ostream &os);
|
||
protected:
|
||
virtual void write_der0_preamble(std::ostream &os) const = 0;
|
||
virtual void write_der1_preamble(std::ostream &os) const = 0;
|
||
virtual void write_atom_assignment(std::ostream &os) const = 0;
|
||
virtual void write_der0_assignment(std::ostream &os) const = 0;
|
||
virtual void write_der1_assignment(std::ostream &os) const = 0;
|
||
};
|
||
|
||
class MatlabSSWriter : public ModelSSWriter
|
||
{
|
||
protected:
|
||
/* Identifier used in function names. */
|
||
std::string id;
|
||
public:
|
||
MatlabSSWriter(const DynareModel &dm, std::string id_arg);
|
||
protected:
|
||
// from ModelSSWriter
|
||
void write_der0_preamble(std::ostream &os) const override;
|
||
void write_der1_preamble(std::ostream &os) const override;
|
||
/* This writes atom assignments. We have four kinds of atoms set here:
|
||
endogenous vars coming from one parameter, parameter values given by the
|
||
second parameter, constants, and the OperationTree::num_constants
|
||
hardwired constants in ogp::OperationTree. */
|
||
void write_atom_assignment(std::ostream &os) const override;
|
||
void write_der0_assignment(std::ostream &os) const override;
|
||
void write_der1_assignment(std::ostream &os) const override;
|
||
/* This prints t10 for t=10. */
|
||
void format_term(int t, std::ostream &os) const override;
|
||
/* This prints a10 for t=10. The atoms a10 are supposed to be set by
|
||
write_atom_assignments(). */
|
||
void format_nulary(int t, std::ostream &os) const override;
|
||
private:
|
||
void write_common1_preamble(std::ostream &os) const;
|
||
void write_common2_preamble(std::ostream &os) const;
|
||
};
|
||
|
||
/* This class implements OperationFormatter for debugging purposes. It
|
||
renders atoms in a more friendly way than the
|
||
ogp::DefaulOperationFormatter. */
|
||
class DebugOperationFormatter : public ogp::DefaultOperationFormatter
|
||
{
|
||
protected:
|
||
const DynareModel &model;
|
||
public:
|
||
DebugOperationFormatter(const DynareModel &m)
|
||
: DefaultOperationFormatter(m.getParser().getTree()),
|
||
model(m)
|
||
{
|
||
}
|
||
void format_nulary(int t, std::ostream &os) const override;
|
||
};
|
||
};
|
||
|
||
#endif
|