dynare/dynare++/src/dynare_model.hh

464 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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