2019-04-16 11:40:38 +02:00
|
|
|
// Copyright © 2006-2011, Ondra Kamenik
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
#include "parser/cc/parser_exception.hh"
|
|
|
|
#include "parser/cc/location.hh"
|
|
|
|
#include "utils/cc/exception.hh"
|
|
|
|
#include "dynare_model.hh"
|
|
|
|
#include "dynare_exception.hh"
|
|
|
|
#include "planner_builder.hh"
|
|
|
|
#include "forw_subst_builder.hh"
|
|
|
|
|
|
|
|
#include <cstdlib>
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <cmath>
|
|
|
|
#include <climits>
|
2019-01-08 17:38:21 +01:00
|
|
|
#include <ostream>
|
2019-04-19 17:09:04 +02:00
|
|
|
#include <memory>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <iomanip>
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
using namespace ogdyn;
|
|
|
|
|
|
|
|
ParsedMatrix::ParsedMatrix(const ogp::MatrixParser &mp)
|
|
|
|
: TwoDMatrix(mp.nrows(), mp.ncols())
|
|
|
|
{
|
|
|
|
zeros();
|
|
|
|
for (ogp::MPIterator it = mp.begin(); it != mp.end(); ++it)
|
|
|
|
get(it.row(), it.col()) = *it;
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareModel::DynareModel()
|
2019-01-10 14:50:44 +01:00
|
|
|
: atoms(), eqs(atoms)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareModel::DynareModel(const DynareModel &dm)
|
|
|
|
: atoms(dm.atoms), eqs(dm.eqs, atoms), order(dm.order),
|
2019-01-09 16:25:31 +01:00
|
|
|
param_vals(nullptr), init_vals(nullptr), vcov_mat(nullptr),
|
2019-01-08 17:12:05 +01:00
|
|
|
t_plobjective(dm.t_plobjective),
|
|
|
|
t_pldiscount(dm.t_pldiscount),
|
2019-01-09 16:25:31 +01:00
|
|
|
pbuilder(nullptr), fbuilder(nullptr),
|
|
|
|
atom_substs(nullptr), old_atoms(nullptr)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
if (dm.param_vals)
|
2019-04-23 12:58:38 +02:00
|
|
|
param_vals = new Vector(const_cast<const Vector &>(*(dm.param_vals)));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (dm.init_vals)
|
2019-04-23 12:58:38 +02:00
|
|
|
init_vals = new Vector(const_cast<const Vector &>(*(dm.init_vals)));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (dm.vcov_mat)
|
2019-04-23 12:58:38 +02:00
|
|
|
vcov_mat = new TwoDMatrix(const_cast<const TwoDMatrix &>(*(dm.vcov_mat)));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (dm.old_atoms)
|
2019-04-23 12:58:38 +02:00
|
|
|
old_atoms = new DynareDynamicAtoms(static_cast<const DynareDynamicAtoms &>(*(dm.old_atoms)));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (dm.atom_substs)
|
|
|
|
atom_substs = new ogp::AtomSubstitutions((*dm.atom_substs), *old_atoms, atoms);
|
|
|
|
if (dm.pbuilder)
|
|
|
|
pbuilder = new PlannerBuilder(*(dm.pbuilder), *this);
|
|
|
|
if (dm.fbuilder)
|
|
|
|
fbuilder = new ForwSubstBuilder(*(dm.fbuilder), *this);
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareModel::~DynareModel()
|
|
|
|
{
|
|
|
|
if (param_vals)
|
|
|
|
delete param_vals;
|
|
|
|
if (init_vals)
|
|
|
|
delete init_vals;
|
|
|
|
if (vcov_mat)
|
|
|
|
delete vcov_mat;
|
|
|
|
if (old_atoms)
|
|
|
|
delete old_atoms;
|
|
|
|
if (atom_substs)
|
|
|
|
delete atom_substs;
|
|
|
|
if (pbuilder)
|
|
|
|
delete pbuilder;
|
|
|
|
if (fbuilder)
|
|
|
|
delete fbuilder;
|
|
|
|
}
|
|
|
|
|
|
|
|
const PlannerInfo *
|
|
|
|
DynareModel::get_planner_info() const
|
|
|
|
{
|
|
|
|
if (pbuilder)
|
|
|
|
return &(pbuilder->get_info());
|
2019-01-09 16:25:31 +01:00
|
|
|
return nullptr;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const ForwSubstInfo *
|
|
|
|
DynareModel::get_forw_subst_info() const
|
|
|
|
{
|
|
|
|
if (fbuilder)
|
|
|
|
return &(fbuilder->get_info());
|
2019-01-09 16:25:31 +01:00
|
|
|
return nullptr;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
const ogp::SubstInfo *
|
|
|
|
DynareModel::get_subst_info() const
|
|
|
|
{
|
|
|
|
if (atom_substs)
|
|
|
|
return &(atom_substs->get_info());
|
2019-01-09 16:25:31 +01:00
|
|
|
return nullptr;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::setInitOuter(const Vector &x)
|
|
|
|
{
|
|
|
|
if (x.length() != atoms.ny())
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Wrong length of vector in DynareModel::setInitOuter");
|
|
|
|
for (int i = 0; i < atoms.ny(); i++)
|
|
|
|
(*init_vals)[i] = x[atoms.y2outer_endo()[i]];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::print() const
|
|
|
|
{
|
|
|
|
printf("all atoms:\n");
|
|
|
|
atoms.print();
|
|
|
|
printf("formulas:\n");
|
|
|
|
DebugOperationFormatter dof(*this);
|
|
|
|
for (int i = 0; i < eqs.nformulas(); i++)
|
|
|
|
{
|
|
|
|
int tf = eqs.formula(i);
|
|
|
|
printf("formula %d:\n", tf);
|
2019-04-19 17:09:04 +02:00
|
|
|
eqs.getTree().print_operation_tree(tf, std::cout, dof);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::dump_model(std::ostream &os) const
|
|
|
|
{
|
|
|
|
// endogenous variable declaration
|
|
|
|
os << "var";
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto i : atoms.get_endovars())
|
|
|
|
os << " " << i;
|
2019-01-08 17:12:05 +01:00
|
|
|
os << ";\n\n";
|
|
|
|
|
|
|
|
// exogenous variables
|
|
|
|
os << "varexo";
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto i : atoms.get_exovars())
|
|
|
|
os << " " << i;
|
2019-01-08 17:12:05 +01:00
|
|
|
os << ";\n\n";
|
|
|
|
|
|
|
|
// parameters
|
|
|
|
os << "parameters";
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto i : atoms.get_params())
|
|
|
|
os << " " << i;
|
2019-01-08 17:12:05 +01:00
|
|
|
os << ";\n\n";
|
|
|
|
|
|
|
|
// parameter values
|
|
|
|
os.precision(16);
|
2019-04-23 12:58:38 +02:00
|
|
|
for (int i = 0; i < static_cast<int>(atoms.get_params().size()); i++)
|
2019-01-08 17:12:05 +01:00
|
|
|
os << atoms.get_params()[i] << "=" << getParams()[i] << ";\n";
|
|
|
|
os << "\n\n";
|
|
|
|
|
|
|
|
// model section
|
|
|
|
ogp::OperationStringConvertor osc(atoms, getParser().getTree());
|
|
|
|
os << "model;\n";
|
|
|
|
for (int i = 0; i < getParser().nformulas(); i++)
|
|
|
|
{
|
|
|
|
os << "// Equation " << i << "\n0 = ";
|
|
|
|
int t = getParser().formula(i);
|
|
|
|
os << osc.convert(getParser().getTree().operation(t), t);
|
|
|
|
os << ";\n";
|
|
|
|
}
|
|
|
|
os << "end;\n";
|
|
|
|
|
|
|
|
// initval as steady state
|
|
|
|
os << "initval;\n";
|
2019-04-23 12:58:38 +02:00
|
|
|
for (int i = 0; i < static_cast<int>(atoms.get_endovars().size()); i++)
|
2019-01-08 17:12:05 +01:00
|
|
|
os << atoms.get_endovars()[atoms.y2outer_endo()[i]] << "=" << getInit()[i] << ";\n";
|
|
|
|
os << "end;\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::add_name(const char *name, int flag)
|
|
|
|
{
|
|
|
|
if (flag == 1)
|
|
|
|
{
|
|
|
|
// endogenous
|
|
|
|
atoms.register_uniq_endo(name);
|
|
|
|
}
|
|
|
|
else if (flag == 2)
|
|
|
|
{
|
|
|
|
// exogenous
|
|
|
|
atoms.register_uniq_exo(name);
|
|
|
|
}
|
|
|
|
else if (flag == 3)
|
|
|
|
{
|
|
|
|
// parameter
|
|
|
|
atoms.register_uniq_param(name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Unrecognized flag value.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::check_model() const
|
|
|
|
{
|
|
|
|
if (order == -1)
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Order of approximation not set in DynareModel::check_model");
|
|
|
|
|
|
|
|
if (atoms.ny() != eqs.nformulas())
|
|
|
|
{
|
|
|
|
char mes[1000];
|
|
|
|
sprintf(mes, "Model has %d equations for %d endogenous variables", eqs.nformulas(), atoms.ny());
|
|
|
|
throw DynareException(__FILE__, __LINE__, mes);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check whether all nulary terms of all formulas in eqs are
|
|
|
|
// either constant or assigned to a name
|
|
|
|
for (int i = 0; i < eqs.nformulas(); i++)
|
|
|
|
{
|
|
|
|
int ft = eqs.formula(i);
|
|
|
|
const unordered_set<int> &nuls = eqs.nulary_of_term(ft);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int nul : nuls)
|
|
|
|
if (!atoms.is_constant(nul) && !atoms.is_named_atom(nul))
|
2019-01-08 17:12:05 +01:00
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Dangling nulary term found, internal error.");
|
|
|
|
}
|
|
|
|
|
|
|
|
int mlag, mlead;
|
|
|
|
atoms.exovarspan(mlead, mlag);
|
|
|
|
if (atoms.nexo() > 0 && (mlead != 0 || mlag != 0))
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"The model contains occurrences of lagged/leaded exogenous variables");
|
|
|
|
|
|
|
|
atoms.endovarspan(mlead, mlag);
|
|
|
|
if (mlead > 1 || mlag < -1)
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"The model contains occurrences of too lagged/leaded endogenous variables");
|
|
|
|
|
|
|
|
// check the dimension of vcov matrix
|
|
|
|
if (getAtoms().nexo() != getVcov().nrows())
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Dimension of VCOV matrix does not correspond to the shocks");
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
DynareModel::variable_shift(int t, int tshift)
|
|
|
|
{
|
|
|
|
const char *name = atoms.name(t);
|
|
|
|
if (atoms.is_type(name, DynareDynamicAtoms::param)
|
|
|
|
|| atoms.is_constant(t))
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"The tree index is not a variable in DynareModel::variable_shift");
|
|
|
|
int ll = atoms.lead(t) + tshift;
|
|
|
|
int res = atoms.index(name, ll);
|
|
|
|
if (res == -1)
|
|
|
|
{
|
|
|
|
std::string str(name);
|
|
|
|
str += '(';
|
|
|
|
char tmp[50];
|
|
|
|
sprintf(tmp, "%d", ll);
|
|
|
|
str += tmp;
|
|
|
|
str += ')';
|
|
|
|
res = eqs.add_nulary(str.c_str());
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::variable_shift_map(const unordered_set<int> &a_set, int tshift,
|
|
|
|
map<int, int> &s_map)
|
|
|
|
{
|
|
|
|
s_map.clear();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int t : a_set)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
// make shift map only for non-constants and non-parameters
|
|
|
|
if (!atoms.is_constant(t))
|
|
|
|
{
|
|
|
|
const char *name = atoms.name(t);
|
|
|
|
if (atoms.is_type(name, DynareDynamicAtoms::endovar)
|
|
|
|
|| atoms.is_type(name, DynareDynamicAtoms::exovar))
|
|
|
|
{
|
|
|
|
int tt = variable_shift(t, tshift);
|
|
|
|
s_map.insert(map<int, int>::value_type(t, tt));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::termspan(int t, int &mlead, int &mlag) const
|
|
|
|
{
|
|
|
|
mlead = INT_MIN;
|
|
|
|
mlag = INT_MAX;
|
|
|
|
const unordered_set<int> &nul_terms = eqs.nulary_of_term(t);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int nul_term : nul_terms)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
if (!atoms.is_constant(nul_term)
|
|
|
|
&& (atoms.is_type(atoms.name(nul_term), DynareDynamicAtoms::endovar)
|
|
|
|
|| atoms.is_type(atoms.name(nul_term), DynareDynamicAtoms::exovar)))
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
int ll = atoms.lead(nul_term);
|
2019-01-08 17:12:05 +01:00
|
|
|
if (ll < mlag)
|
|
|
|
mlag = ll;
|
|
|
|
if (ll > mlead)
|
|
|
|
mlead = ll;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
DynareModel::is_constant_term(int t) const
|
|
|
|
{
|
|
|
|
const unordered_set<int> &nul_terms = eqs.nulary_of_term(t);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int nul_term : nul_terms)
|
|
|
|
if (!atoms.is_constant(nul_term)
|
|
|
|
&& !atoms.is_type(atoms.name(nul_term), DynareDynamicAtoms::param))
|
2019-01-08 17:12:05 +01:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
unordered_set<int>
|
|
|
|
DynareModel::get_nonlinear_subterms(int t) const
|
|
|
|
{
|
|
|
|
NLSelector nls(*this);
|
|
|
|
return eqs.getTree().select_terms(t, nls);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::substitute_atom_for_term(const char *name, int ll, int t)
|
|
|
|
{
|
|
|
|
// if the term t is itself a named atom (parameter, exo, endo),
|
|
|
|
// then we have to unassign it first
|
|
|
|
if (atoms.is_named_atom(t))
|
|
|
|
atoms.unassign_variable(atoms.name(t), atoms.lead(t), t);
|
|
|
|
// assign allocated tree index
|
|
|
|
// for the term now to name(ll)
|
|
|
|
atoms.assign_variable(name, ll, t);
|
|
|
|
// make operation t nulary in operation tree
|
|
|
|
eqs.nularify(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareModel::final_job()
|
|
|
|
{
|
|
|
|
if (t_plobjective != -1 && t_pldiscount != -1)
|
|
|
|
{
|
|
|
|
// at this moment include all equations and all variables; in
|
|
|
|
// future we will exclude purely exogenous processes; todo:
|
|
|
|
PlannerBuilder::Tvarset vset;
|
|
|
|
for (int i = 0; i < atoms.ny(); i++)
|
|
|
|
vset.insert(atoms.get_endovars()[i]);
|
|
|
|
PlannerBuilder::Teqset eset;
|
|
|
|
for (int i = 0; i < eqs.nformulas(); i++)
|
|
|
|
eset.push_back(i);
|
|
|
|
|
|
|
|
// construct the planner builder, this adds a lot of stuff to
|
|
|
|
// the model
|
|
|
|
if (pbuilder)
|
|
|
|
delete pbuilder;
|
|
|
|
pbuilder = new PlannerBuilder(*this, vset, eset);
|
|
|
|
}
|
|
|
|
|
|
|
|
// construct ForwSubstBuilder
|
|
|
|
if (fbuilder)
|
|
|
|
delete fbuilder;
|
|
|
|
fbuilder = new ForwSubstBuilder(*this);
|
|
|
|
|
|
|
|
// call parsing_finished (this will define an outer ordering of all variables)
|
|
|
|
atoms.parsing_finished(ogp::VarOrdering::bfspbfpb);
|
|
|
|
// make a copy of atoms and name it old_atoms
|
|
|
|
if (old_atoms)
|
|
|
|
delete old_atoms;
|
|
|
|
old_atoms = new DynareDynamicAtoms(atoms);
|
|
|
|
// construct empty substitutions from old_atoms to atoms
|
|
|
|
if (atom_substs)
|
|
|
|
delete atom_substs;
|
|
|
|
atom_substs = new ogp::AtomSubstitutions(*old_atoms, atoms);
|
|
|
|
// do the actual substitution, it will also call
|
|
|
|
// parsing_finished for atoms which creates internal orderings
|
|
|
|
atoms.substituteAllLagsAndExo1Leads(eqs, *atom_substs);
|
|
|
|
}
|
|
|
|
|
|
|
|
extern ogp::location_type dynglob_lloc;
|
|
|
|
|
|
|
|
DynareParser::DynareParser(const char *stream, int len, int ord)
|
|
|
|
: DynareModel(),
|
|
|
|
pa_atoms(), paramset(pa_atoms),
|
|
|
|
ia_atoms(), initval(ia_atoms), vcov(),
|
|
|
|
model_beg(0), model_end(-1),
|
|
|
|
paramset_beg(0), paramset_end(-1),
|
|
|
|
initval_beg(0), initval_end(-1),
|
|
|
|
vcov_beg(0), vcov_end(-1),
|
|
|
|
order_beg(0), order_end(-1),
|
|
|
|
plobjective_beg(0), plobjective_end(-1),
|
|
|
|
pldiscount_beg(0), pldiscount_end(-1)
|
|
|
|
{
|
|
|
|
// global parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
parse_glob(len, stream);
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, dynglob_lloc.off);
|
|
|
|
}
|
|
|
|
// setting parameters parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (paramset_end > paramset_beg)
|
|
|
|
paramset.parse(paramset_end-paramset_beg, stream+paramset_beg);
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, paramset_beg);
|
|
|
|
}
|
|
|
|
// model parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (model_end > model_beg)
|
|
|
|
eqs.parse(model_end-model_beg, stream+model_beg);
|
|
|
|
else
|
|
|
|
throw ogp::ParserException("Model section not found.", 0);
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, model_beg);
|
|
|
|
}
|
|
|
|
// initval setting parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (initval_end > initval_beg)
|
|
|
|
initval.parse(initval_end-initval_beg, stream+initval_beg);
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, initval_beg);
|
|
|
|
}
|
|
|
|
// vcov parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (vcov_end > vcov_beg)
|
|
|
|
{
|
|
|
|
vcov.parse(vcov_end-vcov_beg, stream+vcov_beg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, vcov_beg);
|
|
|
|
}
|
|
|
|
// planner objective parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (plobjective_end > plobjective_beg)
|
|
|
|
{
|
|
|
|
eqs.parse(plobjective_end-plobjective_beg, stream+plobjective_beg);
|
|
|
|
t_plobjective = eqs.pop_last_formula();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, plobjective_beg);
|
|
|
|
}
|
|
|
|
// planner discount parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (pldiscount_end > pldiscount_beg)
|
|
|
|
{
|
|
|
|
t_pldiscount = parse_pldiscount(pldiscount_end - pldiscount_beg,
|
|
|
|
stream + pldiscount_beg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, pldiscount_beg);
|
|
|
|
}
|
|
|
|
// order parse
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if (order_end > order_beg)
|
|
|
|
{
|
2019-04-15 18:33:51 +02:00
|
|
|
order = parse_order(order_end - order_beg, stream + order_beg);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const ogp::ParserException &e)
|
|
|
|
{
|
|
|
|
throw ogp::ParserException(e, order_beg);
|
|
|
|
}
|
|
|
|
|
|
|
|
// check the overridden order
|
|
|
|
if (ord != -1)
|
|
|
|
order = ord;
|
|
|
|
|
|
|
|
// end parsing job, add planner's FOCs, make substitutions
|
|
|
|
DynareModel::final_job();
|
|
|
|
|
|
|
|
// calculate parameters
|
|
|
|
calc_params();
|
|
|
|
// calculate initial values
|
|
|
|
calc_init();
|
|
|
|
|
|
|
|
if (vcov_end > vcov_beg)
|
|
|
|
vcov_mat = new ParsedMatrix(vcov);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// vcov has not been asserted, set it to unit matrix
|
|
|
|
vcov_mat = new TwoDMatrix(atoms.nexo(), atoms.nexo());
|
|
|
|
vcov_mat->unit();
|
|
|
|
}
|
|
|
|
|
|
|
|
// check the model
|
|
|
|
check_model();
|
|
|
|
|
|
|
|
// differentiate
|
|
|
|
if (order >= 1)
|
|
|
|
eqs.differentiate(order);
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareParser::DynareParser(const DynareParser &dp)
|
|
|
|
: DynareModel(dp),
|
|
|
|
pa_atoms(dp.pa_atoms), paramset(dp.paramset, pa_atoms),
|
|
|
|
ia_atoms(dp.ia_atoms), initval(dp.initval, ia_atoms), vcov(dp.vcov),
|
|
|
|
model_beg(dp.model_beg), model_end(dp.model_end),
|
|
|
|
paramset_beg(dp.paramset_beg), paramset_end(dp.paramset_end),
|
|
|
|
initval_beg(dp.initval_beg), initval_end(dp.initval_end),
|
|
|
|
vcov_beg(dp.vcov_beg), vcov_end(dp.vcov_end),
|
|
|
|
order_beg(dp.order_beg), order_end(dp.order_end),
|
|
|
|
plobjective_beg(dp.plobjective_beg), plobjective_end(dp.plobjective_end),
|
|
|
|
pldiscount_beg(dp.pldiscount_beg), pldiscount_end(dp.pldiscount_end)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareParser::~DynareParser()
|
2019-01-09 16:16:29 +01:00
|
|
|
= default;
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::add_name(const char *name, int flag)
|
|
|
|
{
|
|
|
|
DynareModel::add_name(name, flag);
|
|
|
|
// register with static atoms used for atom assignements
|
|
|
|
if (flag == 1)
|
|
|
|
{
|
|
|
|
// endogenous
|
|
|
|
ia_atoms.register_name(name);
|
|
|
|
}
|
|
|
|
else if (flag == 2)
|
|
|
|
{
|
|
|
|
// exogenous
|
|
|
|
ia_atoms.register_name(name);
|
|
|
|
}
|
|
|
|
else if (flag == 3)
|
|
|
|
{
|
|
|
|
// parameter
|
|
|
|
pa_atoms.register_name(name);
|
|
|
|
ia_atoms.register_name(name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Unrecognized flag value.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::error(const char *mes)
|
|
|
|
{
|
|
|
|
// throwing zero offset since this exception will be caugth at
|
|
|
|
// constructor
|
|
|
|
throw ogp::ParserException(mes, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::print() const
|
|
|
|
{
|
|
|
|
DynareModel::print();
|
|
|
|
printf("parameter atoms:\n");
|
|
|
|
paramset.print();
|
|
|
|
printf("initval atoms:\n");
|
|
|
|
initval.print();
|
|
|
|
printf("model position: %d %d\n", model_beg, model_end);
|
|
|
|
printf("paramset position: %d %d\n", paramset_beg, paramset_end);
|
|
|
|
printf("initval position: %d %d\n", initval_beg, initval_end);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** A global symbol for passing info to the DynareParser from
|
|
|
|
* parser. */
|
|
|
|
DynareParser *dynare_parser;
|
|
|
|
|
|
|
|
/** The declarations of functions defined in dynglob_ll.cc and
|
|
|
|
* dynglob_tab.cc generated from dynglob.lex and dynglob.y */
|
|
|
|
void *dynglob__scan_buffer(char *, size_t);
|
|
|
|
void dynglob__destroy_buffer(void *);
|
|
|
|
void dynglob_parse();
|
|
|
|
extern ogp::location_type dynglob_lloc;
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::parse_glob(int length, const char *stream)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
auto buffer = std::make_unique<char[]>(length+2);
|
|
|
|
std::copy_n(stream, length, buffer.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
buffer[length] = '\0';
|
|
|
|
buffer[length+1] = '\0';
|
2019-04-19 17:09:04 +02:00
|
|
|
void *p = dynglob__scan_buffer(buffer.get(), static_cast<unsigned int>(length)+2);
|
2019-01-08 17:12:05 +01:00
|
|
|
dynare_parser = this;
|
|
|
|
dynglob_parse();
|
|
|
|
dynglob__destroy_buffer(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
DynareParser::parse_order(int len, const char *str)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
auto buf = std::make_unique<char[]>(len+1);
|
|
|
|
std::copy_n(str, len, buf.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
buf[len] = '\0';
|
|
|
|
int res;
|
2019-04-19 17:09:04 +02:00
|
|
|
sscanf(buf.get(), "%d", &res);
|
2019-01-08 17:12:05 +01:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
DynareParser::parse_pldiscount(int len, const char *str)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
auto buf = std::make_unique<char[]>(len+1);
|
|
|
|
std::copy_n(str, len, buf.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
buf[len] = '\0';
|
2019-04-19 17:09:04 +02:00
|
|
|
if (!atoms.is_type(buf.get(), DynareDynamicAtoms::param))
|
|
|
|
throw ogp::ParserException(std::string("Name ") + buf.get() + " is not a parameter", 0);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
2019-04-19 17:09:04 +02:00
|
|
|
int t = atoms.index(buf.get(), 0);
|
2019-01-08 17:12:05 +01:00
|
|
|
if (t == -1)
|
2019-04-19 17:09:04 +02:00
|
|
|
t = eqs.add_nulary(buf.get());
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::calc_params()
|
|
|
|
{
|
|
|
|
if (param_vals)
|
|
|
|
delete param_vals;
|
|
|
|
|
|
|
|
param_vals = new Vector(atoms.np());
|
|
|
|
ogp::AtomAsgnEvaluator aae(paramset);
|
|
|
|
aae.eval();
|
|
|
|
for (int i = 0; i < atoms.np(); i++)
|
|
|
|
(*param_vals)[i] = aae.get_value(atoms.get_params()[i]);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < atoms.get_params().size(); i++)
|
|
|
|
if (!std::isfinite((*param_vals)[i]))
|
|
|
|
printf("dynare++: warning: value for parameter %s is not finite\n",
|
|
|
|
atoms.get_params()[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
DynareParser::calc_init()
|
|
|
|
{
|
|
|
|
// update initval atoms assignings according to substitutions
|
|
|
|
if (atom_substs)
|
|
|
|
initval.apply_subst(atom_substs->get_old2new());
|
|
|
|
|
|
|
|
// calculate the vector of initial values
|
|
|
|
if (init_vals)
|
|
|
|
delete init_vals;
|
|
|
|
init_vals = new Vector(atoms.ny());
|
|
|
|
ogp::AtomAsgnEvaluator aae(initval);
|
|
|
|
// set parameters
|
|
|
|
for (int ip = 0; ip < atoms.np(); ip++)
|
|
|
|
aae.set_user_value(atoms.get_params()[ip], (*param_vals)[ip]);
|
|
|
|
// set exogenous to zeros
|
|
|
|
for (int ie = 0; ie < atoms.nexo(); ie++)
|
|
|
|
aae.set_user_value(atoms.get_exovars()[ie], 0.0);
|
|
|
|
// evaluate
|
|
|
|
aae.eval();
|
|
|
|
// set results to internally ordered vector init_vals
|
|
|
|
for (int outer = 0; outer < atoms.ny(); outer++)
|
|
|
|
{
|
|
|
|
int i = atoms.outer2y_endo()[outer];
|
|
|
|
(*init_vals)[i] = aae.get_value(atoms.get_endovars()[outer]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if the planner's FOCs have been added, then add estimate of
|
|
|
|
// Lagrange multipliers to the vector
|
|
|
|
if (pbuilder)
|
|
|
|
{
|
|
|
|
MultInitSS mis(*pbuilder, *param_vals, *init_vals);
|
|
|
|
}
|
|
|
|
|
|
|
|
// if forward substitution builder has been created, we have to
|
|
|
|
// its substitutions and evaluate them
|
|
|
|
if (fbuilder)
|
|
|
|
ogdyn::DynareSteadySubstitutions dss(atoms, eqs.getTree(),
|
|
|
|
fbuilder->get_aux_map(), *param_vals, *init_vals);
|
|
|
|
|
|
|
|
for (unsigned int i = 0; i < atoms.get_endovars().size(); i++)
|
|
|
|
if (!std::isfinite((*init_vals)[i]))
|
|
|
|
printf("dynare++: warning: initval for <%s> is not finite\n",
|
|
|
|
atoms.get_endovars()[atoms.y2outer_endo()[i]]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// this returns false for linear functions
|
|
|
|
bool
|
|
|
|
NLSelector::operator()(int t) const
|
|
|
|
{
|
|
|
|
const ogp::Operation &op = model.getParser().getTree().operation(t);
|
|
|
|
const DynareDynamicAtoms &atoms = model.getAtoms();
|
|
|
|
// if the term is constant, return false
|
|
|
|
if (model.is_constant_term(t))
|
|
|
|
return false;
|
|
|
|
int nary = op.nary();
|
|
|
|
if (nary == 0)
|
|
|
|
{
|
|
|
|
if (atoms.is_type(atoms.name(t), DynareDynamicAtoms::endovar)
|
|
|
|
|| atoms.is_type(atoms.name(t), DynareDynamicAtoms::exovar))
|
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else if (nary == 1)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
if (op.getCode() == ogp::code_t::UMINUS)
|
2019-01-08 17:12:05 +01:00
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
if (op.getCode() == ogp::code_t::TIMES)
|
2019-01-08 17:12:05 +01:00
|
|
|
// if at least one operand is constant, than the TIMES is linear
|
|
|
|
if (model.is_constant_term(op.getOp1())
|
|
|
|
|| model.is_constant_term(op.getOp2()))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
// both PLUS and MINUS are linear
|
2019-04-19 17:09:04 +02:00
|
|
|
if (op.getCode() == ogp::code_t::PLUS
|
|
|
|
|| op.getCode() == ogp::code_t::MINUS)
|
2019-01-08 17:12:05 +01:00
|
|
|
return false;
|
|
|
|
// POWER is linear if exponent or base is 0 or one
|
2019-04-19 17:09:04 +02:00
|
|
|
if (op.getCode() == ogp::code_t::POWER
|
2019-01-08 17:12:05 +01:00
|
|
|
&& (op.getOp1() == ogp::OperationTree::zero
|
|
|
|
|| op.getOp1() == ogp::OperationTree::one
|
|
|
|
|| op.getOp2() == ogp::OperationTree::zero
|
|
|
|
|| op.getOp2() == ogp::OperationTree::one))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
// DIVIDE is linear if the denominator is constant, or if
|
|
|
|
// the nominator is zero
|
2019-04-19 17:09:04 +02:00
|
|
|
if (op.getCode() == ogp::code_t::DIVIDE
|
2019-01-08 17:12:05 +01:00
|
|
|
&& (op.getOp1() == ogp::OperationTree::zero
|
|
|
|
|| model.is_constant_term(op.getOp2())))
|
|
|
|
return false;
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
throw DynareException(__FILE__, __LINE__,
|
|
|
|
"Wrong operation in operation tree");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
DynareSPModel::DynareSPModel(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)
|
|
|
|
: DynareModel()
|
|
|
|
{
|
|
|
|
// set the order
|
|
|
|
order = ord;
|
|
|
|
|
|
|
|
// add names
|
|
|
|
for (int i = 0; i < num_endo; i++)
|
|
|
|
add_name(endo[i], 1);
|
|
|
|
for (int i = 0; i < num_exo; i++)
|
|
|
|
add_name(exo[i], 2);
|
|
|
|
for (int i = 0; i < num_par; i++)
|
|
|
|
add_name(par[i], 3);
|
|
|
|
|
|
|
|
// parse the equations
|
|
|
|
eqs.parse(len, equations);
|
|
|
|
|
|
|
|
// parsing finished
|
|
|
|
atoms.parsing_finished(ogp::VarOrdering::bfspbfpb);
|
|
|
|
|
|
|
|
// create what has to be created from DynareModel
|
|
|
|
param_vals = new Vector(atoms.np());
|
|
|
|
init_vals = new Vector(atoms.ny());
|
|
|
|
vcov_mat = new TwoDMatrix(atoms.nexo(), atoms.nexo());
|
|
|
|
|
|
|
|
// check the model
|
|
|
|
check_model();
|
|
|
|
|
|
|
|
// differentiate
|
|
|
|
if (order >= 1)
|
|
|
|
eqs.differentiate(order);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
ModelSSWriter::write_der0(std::ostream &os)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
write_der0_preamble(os);
|
|
|
|
write_atom_assignment(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
stop_set.clear();
|
|
|
|
for (int fi = 0; fi < model.eqs.nformulas(); fi++)
|
2019-04-19 17:09:04 +02:00
|
|
|
otree.print_operation_tree(model.eqs.formula(fi), os, *this);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
2019-04-19 17:09:04 +02:00
|
|
|
write_der0_assignment(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
ModelSSWriter::write_der1(std::ostream &os)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
write_der1_preamble(os);
|
|
|
|
write_atom_assignment(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
stop_set.clear();
|
|
|
|
|
|
|
|
const vector<int> &variables = model.getAtoms().variables();
|
|
|
|
const vector<int> &eam = model.getAtoms().get_endo_atoms_map();
|
|
|
|
for (int i = 0; i < model.getParser().nformulas(); i++)
|
|
|
|
{
|
|
|
|
const ogp::FormulaDerivatives &fder = model.getParser().derivatives(i);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int j : eam)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
int t = fder.derivative(ogp::FoldMultiIndex(variables.size(), 1, j));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (t > 0)
|
2019-04-19 17:09:04 +02:00
|
|
|
otree.print_operation_tree(t, os, *this);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-19 17:09:04 +02:00
|
|
|
write_der1_assignment(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
MatlabSSWriter::MatlabSSWriter(const DynareModel &dm, const char *idd)
|
|
|
|
: ModelSSWriter(dm), id(new char[strlen(idd)+1])
|
|
|
|
{
|
|
|
|
strcpy(id, idd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_der0_preamble(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% Usage:\n"
|
|
|
|
<< "% out = " << id << "_f(params, y)\n"
|
|
|
|
<< "% where\n"
|
|
|
|
<< "% out is a (" << model.getAtoms().ny() << ",1) column vector of the residuals\n"
|
|
|
|
<< "% of the static system\n";
|
|
|
|
write_common1_preamble(os);
|
|
|
|
os << "function out = " << id << "_f(params, y)\n";
|
|
|
|
write_common2_preamble(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_der1_preamble(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% Usage:\n"
|
|
|
|
<< "% out = " << id << "_ff(params, y)\n"
|
|
|
|
<< "% where\n"
|
|
|
|
<< "% out is a (" << model.getAtoms().ny() << "," << model.getAtoms().ny() << ") matrix of the first order\n"
|
|
|
|
<< "% derivatives of the static system residuals\n"
|
|
|
|
<< "% columns correspond to endo variables in\n"
|
|
|
|
<< "% the ordering as declared\n";
|
|
|
|
write_common1_preamble(os);
|
|
|
|
os << "function out = " << id << "_ff(params, y)\n";
|
|
|
|
write_common2_preamble(os);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_common1_preamble(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% params is a (" << model.getAtoms().np() << ",1) vector of parameter values\n"
|
|
|
|
<< "% in the ordering as declared\n"
|
|
|
|
<< "% y is a (" << model.getAtoms().ny() << ",1) vector of endogenous variables\n"
|
|
|
|
<< "% in the ordering as declared\n"
|
|
|
|
<< "%\n"
|
|
|
|
<< "% Created by Dynare++ v. " << DYNVERSION << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
// write ordering of parameters
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "\n% params ordering\n% =====================\n";
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto parname : model.getAtoms().get_params())
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% " << parname << "\n";
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
// write endogenous variables
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "%\n% y ordering\n% =====================\n";
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto endoname : model.getAtoms().get_endovars())
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% " << endoname << "\n";
|
|
|
|
os << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_common2_preamble(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "if size(y) ~= [" << model.getAtoms().ny() << ",1]\n"
|
|
|
|
<< "\terror('Wrong size of y, must be [" << model.getAtoms().ny() << ",1]');\nend\n"
|
|
|
|
<< "if size(params) ~= [" << model.getAtoms().np() << ",1]\n"
|
|
|
|
<< "\terror('Wrong size of params, must be [" << model.getAtoms().np() << ",1]');\nend\n\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_atom_assignment(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
// write OperationTree::num_constants
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% hardwired constants\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
ogp::EvalTree etree(model.getParser().getTree(), ogp::OperationTree::num_constants-1);
|
|
|
|
for (int i = 0; i < ogp::OperationTree::num_constants; i++)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
format_nulary(i, os);
|
2019-01-08 17:12:05 +01:00
|
|
|
double g = etree.eval(i);
|
|
|
|
if (std::isnan(g))
|
2019-04-19 17:09:04 +02:00
|
|
|
os << " = NaN;\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
else
|
2019-04-19 17:09:04 +02:00
|
|
|
os << " = " << std::defaultfloat << std::setprecision(8) << etree.eval(i) << ";\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
// write numerical constants
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% numerical constants\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
const ogp::Constants::Tconstantmap &cmap = model.getAtoms().get_constantmap();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto it : cmap)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
format_nulary(it.first, os);
|
|
|
|
os << " = " << std::defaultfloat << std::setprecision(8) << it.second << ";\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
// write parameters
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% parameter values\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
for (unsigned int ip = 0; ip < model.getAtoms().get_params().size(); ip++)
|
|
|
|
{
|
|
|
|
const char *parname = model.getAtoms().get_params()[ip];
|
|
|
|
int t = model.getAtoms().index(parname, 0);
|
|
|
|
if (t == -1)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% " << parname << " not used in the model\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
else
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
format_nulary(t, os);
|
|
|
|
os << " = params(" << ip+1 << "); % " << parname << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// write exogenous variables
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% exogenous variables to zeros\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
for (unsigned int ie = 0; ie < model.getAtoms().get_exovars().size(); ie++)
|
|
|
|
{
|
|
|
|
const char *exoname = model.getAtoms().get_exovars()[ie];
|
|
|
|
try
|
|
|
|
{
|
|
|
|
const ogp::DynamicAtoms::Tlagmap &lmap = model.getAtoms().lagmap(exoname);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto it : lmap)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
format_nulary(it.second, os);
|
|
|
|
os << " = 0.0; % " << exoname << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const ogu::Exception &e)
|
|
|
|
{
|
|
|
|
// ignore the error of not found variable in the tree
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// write endogenous variables
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% endogenous variables to y\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
for (unsigned int ie = 0; ie < model.getAtoms().get_endovars().size(); ie++)
|
|
|
|
{
|
|
|
|
const char *endoname = model.getAtoms().get_endovars()[ie];
|
|
|
|
const ogp::DynamicAtoms::Tlagmap &lmap = model.getAtoms().lagmap(endoname);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto it : lmap)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
format_nulary(it.second, os);
|
|
|
|
os << " = y(" << ie+1 << "); % " << endoname << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_der0_assignment(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
// initialize out variable
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% setting the output variable\n"
|
|
|
|
<< "out = zeros(" << model.getParser().nformulas() << ", 1);\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
// fill out with the terms
|
|
|
|
for (int i = 0; i < model.getParser().nformulas(); i++)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "out(" << i+1 << ") = ";
|
|
|
|
format_term(model.getParser().formula(i), os);
|
|
|
|
os << ";\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::write_der1_assignment(std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
// initialize out variable
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "% setting the output variable\n";
|
|
|
|
os << "out = zeros(" << model.getParser().nformulas() << ", " << model.getAtoms().ny() << ");\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
// fill out with the terms
|
|
|
|
const vector<int> &variables = model.getAtoms().variables();
|
|
|
|
const vector<int> &eam = model.getAtoms().get_endo_atoms_map();
|
|
|
|
for (int i = 0; i < model.getParser().nformulas(); i++)
|
|
|
|
{
|
|
|
|
const ogp::FormulaDerivatives &fder = model.getParser().derivatives(i);
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int j : eam)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
int tvar = variables[j];
|
2019-01-08 17:12:05 +01:00
|
|
|
const char *name = model.getAtoms().name(tvar);
|
|
|
|
int yi = model.getAtoms().name2outer_endo(name);
|
2019-01-09 15:44:26 +01:00
|
|
|
int t = fder.derivative(ogp::FoldMultiIndex(variables.size(), 1, j));
|
2019-01-08 17:12:05 +01:00
|
|
|
if (t != ogp::OperationTree::zero)
|
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "out(" << i+1 << "," << yi+1 << ") = out("<< i+1 << "," << yi+1 << ") + ";
|
|
|
|
format_term(t, os);
|
|
|
|
os << "; % " << name << "(" << model.getAtoms().lead(tvar) << ")\n";
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::format_term(int t, std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << 't' << t;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
MatlabSSWriter::format_nulary(int t, std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-04-19 17:09:04 +02:00
|
|
|
os << 'a' << t;
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-04-19 17:09:04 +02:00
|
|
|
DebugOperationFormatter::format_nulary(int t, std::ostream &os) const
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
|
|
|
const DynareDynamicAtoms &a = model.getAtoms();
|
|
|
|
|
|
|
|
if (t == ogp::OperationTree::zero)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << '0';
|
2019-01-08 17:12:05 +01:00
|
|
|
else if (t == ogp::OperationTree::one)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << '1';
|
2019-01-08 17:12:05 +01:00
|
|
|
else if (t == ogp::OperationTree::nan)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "NaN";
|
2019-01-08 17:12:05 +01:00
|
|
|
else if (t == ogp::OperationTree::two_over_pi)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << "2/sqrt(PI)";
|
2019-01-08 17:12:05 +01:00
|
|
|
else if (a.is_constant(t))
|
2019-04-19 17:09:04 +02:00
|
|
|
os << a.get_constant_value(t);
|
2019-01-08 17:12:05 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
int ll = a.lead(t);
|
2019-04-19 17:09:04 +02:00
|
|
|
std::string name{a.name(t)};
|
2019-01-08 17:12:05 +01:00
|
|
|
if (ll == 0)
|
2019-04-19 17:09:04 +02:00
|
|
|
os << name;
|
2019-01-08 17:12:05 +01:00
|
|
|
else
|
2019-04-19 17:09:04 +02:00
|
|
|
os << name << '(' << ll << ')';
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|