dynare/dynare++/src/dynare_model.hh

471 lines
16 KiB
C++
Raw Normal View History

// Copyright © 2005-2011, Ondra Kamenik
#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"
2019-04-23 18:57:52 +02:00
#include "planner_builder.hh"
#include "forw_subst_builder.hh"
#include "Vector.hh"
#include "GeneralMatrix.hh"
#include <map>
#include <unordered_set>
#include <ostream>
2019-04-23 18:57:52 +02:00
#include <memory>
2017-05-16 16:30:27 +02:00
namespace ogdyn
{
using std::unordered_set;
2017-05-16 16:30:27 +02:00
using std::map;
2017-05-16 16:30:27 +02:00
/** 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;
2019-04-23 18:57:52 +02:00
PosInterval() = default;
2017-05-16 16:30:27 +02:00
PosInterval(int ifl, int ifc, int ill, int ilc)
: fl(ifl), fc(ifc), ll(ill), lc(ilc)
{
}
2019-04-23 18:57:52 +02:00
PosInterval &operator=(const PosInterval &pi) = default;
2017-05-16 16:30:27 +02:00
/** This returns the interval beginning and interval length
* within the given string. */
void translate(const char *beg, int len, const char * &ibeg, int &ilen) const;
/** Debug print. */
void
print() const
{
printf("fl=%d fc=%d ll=%d lc=%d\n", fl, fc, ll, lc);
}
};
2017-05-16 16:30:27 +02:00
/** 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);
};
2017-05-16 16:30:27 +02:00
class PlannerBuilder;
class PlannerInfo;
class ForwSubstBuilder;
class ForwSubstInfo;
class MultInitSS;
class ModelSSWriter;
2017-05-16 16:30:27 +02:00
/** 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};
2017-05-16 16:30:27 +02:00
/** A vector of parameters values created by a subclass. It
* is stored with natural ordering (outer) of the parameters
* given by atoms. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<Vector> param_vals;
2017-05-16 16:30:27 +02:00
/** A vector of initial values created by a subclass. It is
* stored with internal ordering given by atoms. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<Vector> init_vals;
2017-05-16 16:30:27 +02:00
/** A matrix for vcov. It is created by a subclass. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<TwoDMatrix> vcov_mat;
2017-05-16 16:30:27 +02:00
/** Tree index of the planner objective. If there was no
* planner objective keyword, the value is set to -1. */
int t_plobjective{-1};
2017-05-16 16:30:27 +02:00
/** Tree index of the planner discount. If there was no
* planner discount keyword, the value is set to -1. */
int t_pldiscount{-1};
2017-05-16 16:30:27 +02:00
/** Pointer to PlannerBuilder, which is created only if the
* planner's FOC are added to the model. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<PlannerBuilder> pbuilder;
2017-05-16 16:30:27 +02:00
/** 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. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<ForwSubstBuilder> fbuilder;
2017-05-16 16:30:27 +02:00
/** 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. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<ogp::AtomSubstitutions> atom_substs;
2017-05-16 16:30:27 +02:00
/** Pointer to a copy of original atoms before substitutions
* took place. */
2019-04-23 18:57:52 +02:00
std::unique_ptr<ogp::SAtoms> old_atoms;
2017-05-16 16:30:27 +02:00
public:
/** Initializes the object to an empty state. */
DynareModel();
/** Construct a new deep copy. */
DynareModel(const DynareModel &dm);
2019-04-23 18:57:52 +02:00
virtual ~DynareModel() = default;
virtual std::unique_ptr<DynareModel> clone() const = 0;
2017-05-16 16:30:27 +02:00
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.y for values of
* the flag. This is used by a subclass when declaring the
* names. */
2019-04-23 18:57:52 +02:00
void add_name(const std::string &name, int flag);
2017-05-16 16:30:27 +02:00
/** 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 char *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();
};
2017-05-16 16:30:27 +02:00
/** 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 char *str, int len, int ord);
2019-04-23 18:57:52 +02:00
DynareParser(const DynareParser &dp);
std::unique_ptr<DynareModel>
clone() const override
2017-05-16 16:30:27 +02:00
{
2019-04-23 18:57:52 +02:00
return std::make_unique<DynareParser>(*this);
2017-05-16 16:30:27 +02:00
}
/** 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(const char *name, int flag);
/** Sets position of the model section. Called from
* dynglob.y. */
void
set_model_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
model_beg = off1;
model_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Sets position of the section setting parameters. Called
* from dynglob.y. */
void
set_paramset_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
paramset_beg = off1;
paramset_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Sets position of the initval section. Called from
* dynglob.y. */
void
set_initval_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
initval_beg = off1;
initval_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Sets position of the vcov section. Called from
* dynglob.y. */
void
set_vcov_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
vcov_beg = off1;
vcov_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Parser the given string as integer and set to as the
* order. */
void
set_order_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
order_beg = off1;
order_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Sets position of the planner_objective section. Called
* from dynglob.y. */
void
set_pl_objective_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
plobjective_beg = off1;
plobjective_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Sets position of the planner_discount section. Called from
* dynglob.y. */
void
set_pl_discount_pos(int off1, int off2)
{
2019-04-23 18:57:52 +02:00
pldiscount_beg = off1;
pldiscount_end = off2;
2017-05-16 16:30:27 +02:00
}
/** Processes a syntax error from bison. */
void error(const char *mes);
/** Debug print. */
void print() const;
protected:
void parse_glob(int length, const char *stream);
int parse_order(int length, const char *stream);
int parse_pldiscount(int length, const char *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;
};
2017-05-16 16:30:27 +02:00
/** Semiparsed model. The equations are given by a string,
* everything other by C/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:
2019-04-23 18:57:52 +02:00
DynareSPModel(const std::vector<std::string> &endo,
const std::vector<std::string> &exo,
const std::vector<std::string> &par,
2017-05-16 16:30:27 +02:00
const char *equations, int len, int ord);
2019-04-23 18:57:52 +02:00
DynareSPModel(const DynareSPModel &dm) = default;
~DynareSPModel() override = default;
std::unique_ptr<DynareModel>
clone() const override
2017-05-16 16:30:27 +02:00
{
2019-04-23 18:57:52 +02:00
return std::make_unique<DynareSPModel>(*this);
2017-05-16 16:30:27 +02:00
}
};
2017-05-16 16:30:27 +02:00
/** 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;
2017-05-16 16:30:27 +02:00
};
2017-05-16 16:30:27 +02:00
/** 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);
2017-05-16 16:30:27 +02:00
/** 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);
2017-05-16 16:30:27 +02:00
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;
2017-05-16 16:30:27 +02:00
};
2017-05-16 16:30:27 +02:00
class MatlabSSWriter : public ModelSSWriter
{
protected:
/** Identifier used in function names. */
2019-04-23 18:57:52 +02:00
std::string id;
2017-05-16 16:30:27 +02:00
public:
2019-04-23 18:57:52 +02:00
MatlabSSWriter(const DynareModel &dm, std::string id_arg);
2017-05-16 16:30:27 +02:00
protected:
// from ModelSSWriter
void write_der0_preamble(std::ostream &os) const override;
void write_der1_preamble(std::ostream &os) const override;
2017-05-16 16:30:27 +02:00
/** 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;
2017-05-16 16:30:27 +02:00
/** This prints t10 for t=10. */
void format_term(int t, std::ostream &os) const override;
2017-05-16 16:30:27 +02:00
/** 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;
2017-05-16 16:30:27 +02:00
private:
void write_common1_preamble(std::ostream &os) const;
void write_common2_preamble(std::ostream &os) const;
2017-05-16 16:30:27 +02:00
};
2017-05-16 16:30:27 +02:00
/** 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;
2017-05-16 16:30:27 +02:00
};
};
#endif