2019-04-16 11:40:38 +02:00
|
|
|
// Copyright © 2006-2011, Ondra Kamenik
|
2019-01-08 17:12:05 +01:00
|
|
|
|
|
|
|
#include "forw_subst_builder.hh"
|
|
|
|
|
2019-04-23 18:57:52 +02:00
|
|
|
#include "dynare_model.hh"
|
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
using namespace ogdyn;
|
|
|
|
|
|
|
|
ForwSubstBuilder::ForwSubstBuilder(DynareModel &m)
|
|
|
|
: model(m)
|
|
|
|
{
|
|
|
|
info.num_new_terms -= model.getParser().getTree().get_num_op();
|
|
|
|
|
|
|
|
// go through all equations
|
|
|
|
int neq = model.eqs.nformulas();
|
|
|
|
for (int i = 0; i < neq; i++)
|
|
|
|
{
|
|
|
|
int ft = model.eqs.formula(i);
|
|
|
|
int mlead, mlag;
|
|
|
|
model.termspan(ft, mlead, mlag);
|
|
|
|
// if equation is too forward looking
|
|
|
|
if (mlead > 1)
|
|
|
|
{
|
|
|
|
info.num_affected_equations++;
|
|
|
|
// break it to non-linear terms
|
|
|
|
unordered_set<int> nlt = model.get_nonlinear_subterms(ft);
|
|
|
|
int j = 0; // indexes subterms
|
|
|
|
// and make substitutions for all these non-linear subterms
|
2019-04-23 18:57:52 +02:00
|
|
|
for (const auto &it : nlt)
|
|
|
|
substitute_for_term(it, i, j++);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// unassign all variables with lead greater than 1
|
|
|
|
unassign_gt_1_leads();
|
|
|
|
|
|
|
|
// forget the derivatives in the tree because some variables could
|
|
|
|
// have been unassigned
|
|
|
|
model.eqs.getTree().forget_derivative_maps();
|
|
|
|
|
|
|
|
info.num_new_terms += model.getParser().getTree().get_num_op();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ForwSubstBuilder::substitute_for_term(int t, int i, int j)
|
|
|
|
{
|
|
|
|
int mlead, mlag;
|
|
|
|
model.termspan(t, mlead, mlag);
|
|
|
|
if (mlead > 1)
|
|
|
|
{
|
|
|
|
info.num_subst_terms++;
|
|
|
|
// Example for comments: let t = f(x(+4))
|
|
|
|
// first make lagsubst be substitution setting f(x(+4)) to f(x(+1))
|
|
|
|
// this is lag = -3 (1-mlead)
|
|
|
|
map<int, int> lagsubst;
|
|
|
|
unordered_set<int> nult = model.eqs.nulary_of_term(t);// make copy of nult!
|
|
|
|
model.variable_shift_map(nult, 1-mlead, lagsubst);
|
|
|
|
int lagt = model.eqs.add_substitution(t, lagsubst);
|
|
|
|
|
|
|
|
// now maxlead of lagt is +1
|
|
|
|
// add AUXLD_*_*_1 = f(x(+1)) to the model
|
2019-04-23 18:57:52 +02:00
|
|
|
std::string name = "AUXLD_" + std::to_string(i) + '_' + std::to_string(j) + "_1";
|
|
|
|
model.atoms.register_uniq_endo(name.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
info.num_aux_variables++;
|
2019-04-23 18:57:52 +02:00
|
|
|
const char *ss = model.atoms.get_name_storage().query(name.c_str());
|
|
|
|
int auxt = model.eqs.add_nulary(name.c_str());
|
2019-04-19 17:09:04 +02:00
|
|
|
model.eqs.add_formula(model.eqs.add_binary(ogp::code_t::MINUS, auxt, lagt));
|
2019-04-23 18:57:52 +02:00
|
|
|
aux_map.emplace(ss, lagt);
|
2019-01-08 17:12:05 +01:00
|
|
|
// now add variables and equations
|
|
|
|
// AUXLD_*_*_2 = AUXLD_*_*_1(+1) through
|
|
|
|
// AUXLD_*_*_{mlead-1} = AUXLD_*_*_{mlead-2}(+1)
|
|
|
|
for (int ll = 1; ll <= mlead-2; ll++)
|
|
|
|
{
|
|
|
|
// create AUXLD_*_*_{ll}(+1)
|
2019-04-23 18:57:52 +02:00
|
|
|
name = "AUXLD_" + std::to_string(i) + '_' + std::to_string(j) + '_' + std::to_string(ll) + "(+1)";
|
|
|
|
int lastauxt_lead = model.eqs.add_nulary(name.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
// create AUXLD_*_*{ll+1}
|
2019-04-23 18:57:52 +02:00
|
|
|
name = "AUXLD_" + std::to_string(i) + '_' + std::to_string(j) + '_' + std::to_string(ll+1);
|
|
|
|
model.atoms.register_uniq_endo(name.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
info.num_aux_variables++;
|
2019-04-23 18:57:52 +02:00
|
|
|
ss = model.atoms.get_name_storage().query(name.c_str());
|
|
|
|
auxt = model.eqs.add_nulary(name.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
// add AUXLD_*_*_{ll+1} = AUXLD_*_*_{ll}(+1)
|
2019-04-19 17:09:04 +02:00
|
|
|
model.eqs.add_formula(model.eqs.add_binary(ogp::code_t::MINUS, auxt, lastauxt_lead));
|
2019-01-08 17:12:05 +01:00
|
|
|
// add substitution to the map; todo: this
|
|
|
|
// works well because in the context where
|
|
|
|
// aux_map is used the timing doesn't matter,
|
|
|
|
// however, it is misleading, needs to be
|
|
|
|
// changed
|
2019-04-23 18:57:52 +02:00
|
|
|
aux_map.emplace(ss, lagt);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// now we have to substitute AUXLD_*_*{mlead-1}(+1) for t
|
2019-04-23 18:57:52 +02:00
|
|
|
name = "AUXLD_" + std::to_string(i) + '_' + std::to_string(j) + '_' + std::to_string(mlead-1);
|
|
|
|
ss = model.atoms.get_name_storage().query(name.c_str());
|
2019-01-08 17:12:05 +01:00
|
|
|
model.substitute_atom_for_term(ss, +1, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ForwSubstBuilder::unassign_gt_1_leads(const char *name)
|
|
|
|
{
|
|
|
|
const char *ss = model.atoms.get_name_storage().query(name);
|
|
|
|
int mlead, mlag;
|
|
|
|
model.atoms.varspan(name, mlead, mlag);
|
|
|
|
for (int ll = 2; ll <= mlead; ll++)
|
|
|
|
{
|
|
|
|
int t = model.atoms.index(ss, ll);
|
|
|
|
if (t != -1)
|
|
|
|
model.atoms.unassign_variable(ss, ll, t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ForwSubstBuilder::unassign_gt_1_leads()
|
|
|
|
{
|
|
|
|
const vector<const char *> &endovars = model.atoms.get_endovars();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto endovar : endovars)
|
|
|
|
unassign_gt_1_leads(endovar);
|
2019-01-08 17:12:05 +01:00
|
|
|
const vector<const char *> &exovars = model.atoms.get_exovars();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto exovar : exovars)
|
|
|
|
unassign_gt_1_leads(exovar);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ForwSubstBuilder::ForwSubstBuilder(const ForwSubstBuilder &b, DynareModel &m)
|
|
|
|
: model(m)
|
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
for (auto it : b.aux_map)
|
2019-01-08 17:12:05 +01:00
|
|
|
{
|
2019-01-09 15:44:26 +01:00
|
|
|
const char *ss = m.atoms.get_name_storage().query(it.first);
|
2019-04-23 18:57:52 +02:00
|
|
|
aux_map.emplace(ss, it.second);
|
2019-01-08 17:12:05 +01:00
|
|
|
}
|
|
|
|
}
|