2019-01-10 17:52:02 +01:00
|
|
|
#include <sstream>
|
|
|
|
#include <fstream>
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
#include "dynare3.hh"
|
|
|
|
#include "dynare_exception.hh"
|
|
|
|
#include "planner_builder.hh"
|
|
|
|
#include "forw_subst_builder.hh"
|
|
|
|
|
|
|
|
#include "utils/cc/exception.hh"
|
|
|
|
#include "parser/cc/parser_exception.hh"
|
|
|
|
#include "parser/cc/atom_substitutions.hh"
|
|
|
|
#include "../tl/cc/tl_exception.hh"
|
|
|
|
#include "../kord/kord_exception.hh"
|
|
|
|
|
|
|
|
#ifndef DYNVERSION
|
|
|
|
# define DYNVERSION "unknown"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/**************************************************************************************/
|
|
|
|
/* DynareNameList class */
|
|
|
|
/**************************************************************************************/
|
2019-02-06 15:50:01 +01:00
|
|
|
std::vector<int>
|
2019-03-06 18:40:19 +01:00
|
|
|
DynareNameList::selectIndices(const std::vector<std::string> &ns) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-02-06 15:50:01 +01:00
|
|
|
std::vector<int> res;
|
2019-03-06 18:40:19 +01:00
|
|
|
for (const auto &n : ns)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
int j = 0;
|
2019-03-06 18:40:19 +01:00
|
|
|
while (j < getNum() && n != getName(j))
|
2019-01-08 17:12:05 +01:00
|
|
|
j++;
|
|
|
|
if (j == getNum())
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
2019-02-06 15:50:01 +01:00
|
|
|
std::string("Couldn't find name for ") + n
|
2019-01-08 17:12:05 +01:00
|
|
|
+" in DynareNameList::selectIndices");
|
|
|
|
res.push_back(j);
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**************************************************************************************/
|
|
|
|
/* Dynare class */
|
|
|
|
/**************************************************************************************/
|
|
|
|
|
|
|
|
Dynare::Dynare(const char *modname, int ord, double sstol, Journal &jr)
|
2019-01-09 16:25:31 +01:00
|
|
|
: journal(jr), model(nullptr), ysteady(nullptr), md(1), dnl(nullptr), denl(nullptr), dsnl(nullptr),
|
|
|
|
fe(nullptr), fde(nullptr), ss_tol(sstol)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-10 17:52:02 +01:00
|
|
|
std::ifstream f{modname};
|
|
|
|
if (f.fail())
|
2019-02-06 15:50:01 +01:00
|
|
|
throw DynareException(__FILE__, __LINE__, std::string{"Could not open model file "}+modname);
|
2019-01-10 17:52:02 +01:00
|
|
|
|
|
|
|
std::ostringstream buffer;
|
|
|
|
buffer << f.rdbuf();
|
|
|
|
std::string contents{buffer.str()};
|
|
|
|
|
|
|
|
try
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-10 17:52:02 +01:00
|
|
|
model = new ogdyn::DynareParser(contents.c_str(), contents.length(), ord);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
2019-01-10 17:52:02 +01:00
|
|
|
catch (const ogp::ParserException &pe)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-10 17:52:02 +01:00
|
|
|
// Compute line and column, given the offset in the file
|
|
|
|
int line = 1;
|
|
|
|
int col = 0;
|
|
|
|
size_t i = 0;
|
|
|
|
while (i < contents.length() && i < (size_t) pe.offset())
|
|
|
|
{
|
|
|
|
if (contents[i] == '\n')
|
|
|
|
{
|
|
|
|
line++;
|
|
|
|
col = 0;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
col++;
|
|
|
|
}
|
|
|
|
throw DynareException(pe.message(), modname, line, col);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
2019-01-10 17:52:02 +01:00
|
|
|
ysteady = new Vector(model->getAtoms().ny());
|
|
|
|
dnl = new DynareNameList(*this);
|
|
|
|
denl = new DynareExogNameList(*this);
|
|
|
|
dsnl = new DynareStateNameList(*this, *dnl, *denl);
|
|
|
|
fe = new ogp::FormulaEvaluator(model->getParser());
|
|
|
|
fde = new ogp::FormulaDerEvaluator(model->getParser());
|
|
|
|
writeModelInfo(journal);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
Dynare::Dynare(const char **endo, int num_endo,
|
|
|
|
const char **exo, int num_exo,
|
|
|
|
const char **par, int num_par,
|
|
|
|
const char *equations, int len, int ord,
|
|
|
|
double sstol, Journal &jr)
|
2019-01-09 16:25:31 +01:00
|
|
|
: journal(jr), model(nullptr), ysteady(nullptr), md(1), dnl(nullptr), denl(nullptr), dsnl(nullptr),
|
|
|
|
fe(nullptr), fde(nullptr), ss_tol(sstol)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
model = new ogdyn::DynareSPModel(endo, num_endo, exo, num_exo, par, num_par,
|
|
|
|
equations, len, ord);
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &pe)
|
|
|
|
{
|
|
|
|
throw DynareException(pe.message(), pe.offset());
|
|
|
|
}
|
|
|
|
ysteady = new Vector(model->getAtoms().ny());
|
|
|
|
dnl = new DynareNameList(*this);
|
|
|
|
denl = new DynareExogNameList(*this);
|
|
|
|
dsnl = new DynareStateNameList(*this, *dnl, *denl);
|
|
|
|
fe = new ogp::FormulaEvaluator(model->getParser());
|
|
|
|
fde = new ogp::FormulaDerEvaluator(model->getParser());
|
|
|
|
writeModelInfo(journal);
|
|
|
|
}
|
|
|
|
|
|
|
|
Dynare::Dynare(const Dynare &dynare)
|
2019-01-09 16:25:31 +01:00
|
|
|
: journal(dynare.journal), model(nullptr),
|
|
|
|
ysteady(nullptr), md(dynare.md),
|
|
|
|
dnl(nullptr), denl(nullptr), dsnl(nullptr), fe(nullptr), fde(nullptr),
|
2019-01-08 17:12:05 +01:00
|
|
|
ss_tol(dynare.ss_tol)
|
|
|
|
{
|
|
|
|
model = dynare.model->clone();
|
|
|
|
ysteady = new Vector(*(dynare.ysteady));
|
|
|
|
dnl = new DynareNameList(*this);
|
|
|
|
denl = new DynareExogNameList(*this);
|
|
|
|
dsnl = new DynareStateNameList(*this, *dnl, *denl);
|
|
|
|
fe = new ogp::FormulaEvaluator(model->getParser());
|
|
|
|
fde = new ogp::FormulaDerEvaluator(model->getParser());
|
|
|
|
}
|
|
|
|
|
|
|
|
Dynare::~Dynare()
|
|
|
|
{
|
|
|
|
if (model)
|
|
|
|
delete model;
|
|
|
|
if (ysteady)
|
|
|
|
delete ysteady;
|
|
|
|
if (dnl)
|
|
|
|
delete dnl;
|
|
|
|
if (dsnl)
|
|
|
|
delete dsnl;
|
|
|
|
if (denl)
|
|
|
|
delete denl;
|
|
|
|
if (fe)
|
|
|
|
delete fe;
|
|
|
|
if (fde)
|
|
|
|
delete fde;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::writeMat(mat_t *fd, const char *prefix) const
|
|
|
|
{
|
|
|
|
char tmp[100];
|
|
|
|
sprintf(tmp, "%s_vars", prefix);
|
|
|
|
getAllEndoNames().writeMat(fd, tmp);
|
|
|
|
getAllEndoNames().writeMatIndices(fd, prefix);
|
|
|
|
sprintf(tmp, "%s_state_vars", prefix);
|
|
|
|
getStateNames().writeMat(fd, tmp);
|
|
|
|
sprintf(tmp, "%s_shocks", prefix);
|
|
|
|
getExogNames().writeMat(fd, tmp);
|
|
|
|
getExogNames().writeMatIndices(fd, prefix);
|
|
|
|
sprintf(tmp, "%s_vcov_exo", prefix);
|
|
|
|
model->getVcov().writeMat(fd, tmp);
|
|
|
|
TwoDMatrix aux(1, 1);
|
|
|
|
sprintf(tmp, "%s_nstat", prefix);
|
|
|
|
aux.get(0, 0) = nstat();
|
|
|
|
aux.writeMat(fd, tmp);
|
|
|
|
sprintf(tmp, "%s_npred", prefix);
|
|
|
|
aux.get(0, 0) = npred();
|
|
|
|
aux.writeMat(fd, tmp);
|
|
|
|
sprintf(tmp, "%s_nboth", prefix);
|
|
|
|
aux.get(0, 0) = nboth();
|
|
|
|
aux.writeMat(fd, tmp);
|
|
|
|
sprintf(tmp, "%s_nforw", prefix);
|
|
|
|
aux.get(0, 0) = nforw();
|
|
|
|
aux.writeMat(fd, tmp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::writeDump(const std::string &basename) const
|
|
|
|
{
|
|
|
|
std::string fname(basename);
|
|
|
|
fname += ".dump";
|
|
|
|
std::ofstream out(fname.c_str());
|
|
|
|
model->dump_model(out);
|
|
|
|
out.close();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::solveDeterministicSteady(Vector &steady)
|
|
|
|
{
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Non-linear solver for deterministic steady state" << endrec;
|
|
|
|
steady = (const Vector &) model->getInit();
|
|
|
|
DynareVectorFunction dvf(*this);
|
|
|
|
DynareJacobian dj(*this);
|
|
|
|
ogu::NLSolver nls(dvf, dj, 500, ss_tol, journal);
|
|
|
|
int iter;
|
|
|
|
if (!nls.solve(steady, iter))
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Could not obtain convergence in non-linear solver");
|
|
|
|
}
|
|
|
|
|
|
|
|
// evaluate system at given y_t=y_{t+1}=y_{t-1}, and given shocks x_t
|
|
|
|
void
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
Dynare::evaluateSystem(Vector &out, const ConstVector &yy, const Vector &xx)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
ConstVector yym(yy, nstat(), nys());
|
|
|
|
ConstVector yyp(yy, nstat()+npred(), nyss());
|
|
|
|
evaluateSystem(out, yym, yy, yyp, xx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// evaluate system at given y^*_{t-1}, y_t, y^{**}_{t+1} and at
|
|
|
|
// exogenous x_t, all three vectors yym, yy, and yyp have the
|
|
|
|
// respective lengths of y^*_{t-1}, y_t, y^{**}_{t+1}
|
|
|
|
void
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
Dynare::evaluateSystem(Vector &out, const ConstVector &yym, const ConstVector &yy,
|
|
|
|
const ConstVector &yyp, const Vector &xx)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
ogdyn::DynareAtomValues dav(model->getAtoms(), model->getParams(), yym, yy, yyp, xx);
|
|
|
|
DynareEvalLoader del(model->getAtoms(), out);
|
|
|
|
fe->eval(dav, del);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::calcDerivatives(const Vector &yy, const Vector &xx)
|
|
|
|
{
|
|
|
|
ConstVector yym(yy, nstat(), nys());
|
|
|
|
ConstVector yyp(yy, nstat()+npred(), nyss());
|
|
|
|
ogdyn::DynareAtomValues dav(model->getAtoms(), model->getParams(), yym, yy, yyp, xx);
|
|
|
|
DynareDerEvalLoader ddel(model->getAtoms(), md, model->getOrder());
|
|
|
|
for (int iord = 1; iord <= model->getOrder(); iord++)
|
|
|
|
fde->eval(dav, ddel, iord);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::calcDerivativesAtSteady()
|
|
|
|
{
|
|
|
|
Vector xx(nexog());
|
|
|
|
xx.zeros();
|
|
|
|
calcDerivatives(*ysteady, xx);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
Dynare::writeModelInfo(Journal &jr) const
|
|
|
|
{
|
|
|
|
// write info on variables
|
|
|
|
{
|
|
|
|
JournalRecordPair rp(journal);
|
|
|
|
rp << "Information on variables" << endrec;
|
|
|
|
JournalRecord rec1(journal);
|
|
|
|
rec1 << "Number of endogenous: " << ny() << endrec;
|
|
|
|
JournalRecord rec2(journal);
|
|
|
|
rec2 << "Number of exogenous: " << nexog() << endrec;
|
|
|
|
JournalRecord rec3(journal);
|
|
|
|
rec3 << "Number of static: " << nstat() << endrec;
|
|
|
|
JournalRecord rec4(journal);
|
|
|
|
rec4 << "Number of predetermined: " << npred()+nboth() << endrec;
|
|
|
|
JournalRecord rec5(journal);
|
|
|
|
rec5 << "Number of forward looking: " << nforw()+nboth() << endrec;
|
|
|
|
JournalRecord rec6(journal);
|
|
|
|
rec6 << "Number of both: " << nboth() << endrec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write info on planner variables
|
|
|
|
const ogdyn::PlannerInfo *pinfo = model->get_planner_info();
|
|
|
|
if (pinfo)
|
|
|
|
{
|
|
|
|
JournalRecordPair rp(journal);
|
|
|
|
rp << "Information on planner variables" << endrec;
|
|
|
|
JournalRecord rec1(journal);
|
|
|
|
rec1 << "Number of Lagrange multipliers: " << pinfo->num_lagrange_mults << endrec;
|
|
|
|
JournalRecord rec2(journal);
|
|
|
|
rec2 << "Number of auxiliary variables: " << pinfo->num_aux_variables << endrec;
|
|
|
|
JournalRecord rec3(journal);
|
|
|
|
rec3 << "Number of new terms in the tree: " << pinfo->num_new_terms << endrec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write info on forward substitutions
|
|
|
|
const ogdyn::ForwSubstInfo *finfo = model->get_forw_subst_info();
|
|
|
|
if (finfo)
|
|
|
|
{
|
|
|
|
JournalRecordPair rp(journal);
|
|
|
|
rp << "Information on forward substitutions" << endrec;
|
|
|
|
JournalRecord rec1(journal);
|
|
|
|
rec1 << "Number of affected equations: " << finfo->num_affected_equations << endrec;
|
|
|
|
JournalRecord rec2(journal);
|
|
|
|
rec2 << "Number of substituted terms: " << finfo->num_subst_terms << endrec;
|
|
|
|
JournalRecord rec3(journal);
|
|
|
|
rec3 << "Number of auxiliary variables: " << finfo->num_aux_variables << endrec;
|
|
|
|
JournalRecord rec4(journal);
|
|
|
|
rec4 << "Number of new terms in the tree: " << finfo->num_new_terms << endrec;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write info on substitutions
|
|
|
|
const ogp::SubstInfo *sinfo = model->get_subst_info();
|
|
|
|
if (sinfo)
|
|
|
|
{
|
|
|
|
JournalRecordPair rp(journal);
|
|
|
|
rp << "Information on substitutions" << endrec;
|
|
|
|
JournalRecord rec1(journal);
|
|
|
|
rec1 << "Number of substitutions: " << sinfo->num_substs << endrec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareNameList::DynareNameList(const Dynare &dynare)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < dynare.ny(); i++)
|
|
|
|
{
|
|
|
|
int j = dynare.model->getAtoms().y2outer_endo()[i];
|
|
|
|
const char *name = dynare.model->getAtoms().get_endovars()[j];
|
|
|
|
names.push_back(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareStateNameList::DynareStateNameList(const Dynare &dynare, const DynareNameList &dnl,
|
|
|
|
const DynareExogNameList &denl)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < dynare.nys(); i++)
|
|
|
|
names.push_back(dnl.getName(i+dynare.nstat()));
|
|
|
|
for (int i = 0; i < dynare.nexog(); i++)
|
|
|
|
names.push_back(denl.getName(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareExogNameList::DynareExogNameList(const Dynare &dynare)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < dynare.nexog(); i++)
|
|
|
|
{
|
|
|
|
int j = dynare.model->getAtoms().y2outer_exo()[i];
|
|
|
|
const char *name = dynare.model->getAtoms().get_exovars()[j];
|
|
|
|
names.push_back(name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareEvalLoader::DynareEvalLoader(const ogp::FineAtoms &a, Vector &out)
|
|
|
|
: Vector(out)
|
|
|
|
{
|
|
|
|
if (a.ny() != out.length())
|
|
|
|
throw DynareException(__FILE__, __LINE__, "Wrong length of out vector in DynareEvalLoader constructor");
|
|
|
|
}
|
|
|
|
|
|
|
|
/** This clears the container of model derivatives and initializes it
|
|
|
|
* inserting empty sparse tensors up to the given order. */
|
|
|
|
DynareDerEvalLoader::DynareDerEvalLoader(const ogp::FineAtoms &a,
|
|
|
|
TensorContainer<FSSparseTensor> &mod_ders,
|
|
|
|
int order)
|
|
|
|
: atoms(a), md(mod_ders)
|
|
|
|
{
|
|
|
|
md.clear();
|
|
|
|
for (int iord = 1; iord <= order; iord++)
|
|
|
|
{
|
2019-02-20 16:50:33 +01:00
|
|
|
auto t = std::make_unique<FSSparseTensor>(iord, atoms.ny()+atoms.nys()+atoms.nyss()+atoms.nexo(), atoms.ny());
|
|
|
|
md.insert(std::move(t));
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareDerEvalLoader::load(int i, int iord, const int *vars, double res)
|
|
|
|
{
|
2019-02-20 17:51:05 +01:00
|
|
|
FSSparseTensor &t = md.get(Symmetry{iord});
|
2019-01-08 17:12:05 +01:00
|
|
|
IntSequence s(iord, 0);
|
|
|
|
for (int j = 0; j < iord; j++)
|
|
|
|
s[j] = atoms.get_pos_of_all(vars[j]);
|
2019-02-20 17:51:05 +01:00
|
|
|
t.insert(s, i, res);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
DynareJacobian::DynareJacobian(Dynare &dyn)
|
|
|
|
: Jacobian(dyn.ny()), d(dyn)
|
|
|
|
{
|
|
|
|
zeros();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareJacobian::eval(const Vector &yy)
|
|
|
|
{
|
|
|
|
ogdyn::DynareSteadyAtomValues
|
|
|
|
dav(d.getModel().getAtoms(), d.getModel().getParams(), yy);
|
|
|
|
zeros();
|
|
|
|
d.fde->eval(dav, *this, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareJacobian::load(int i, int iord, const int *vars, double res)
|
|
|
|
{
|
|
|
|
if (iord != 1)
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Derivative order different from order=1 in DynareJacobian::load");
|
|
|
|
|
|
|
|
int t = vars[0];
|
|
|
|
int j = d.getModel().getAtoms().get_pos_of_all(t);
|
|
|
|
if (j < d.nyss())
|
|
|
|
get(i, j+d.nstat()+d.npred()) += res;
|
|
|
|
else if (j < d.nyss()+d.ny())
|
|
|
|
get(i, j-d.nyss()) += res;
|
|
|
|
else if (j < d.nyss()+d.ny()+d.nys())
|
|
|
|
get(i, j-d.nyss()-d.ny()+d.nstat()) += res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareVectorFunction::eval(const ConstVector &in, Vector &out)
|
|
|
|
{
|
|
|
|
check_for_eval(in, out);
|
|
|
|
Vector xx(d.nexog());
|
|
|
|
xx.zeros();
|
|
|
|
d.evaluateSystem(out, in, xx);
|
|
|
|
}
|