Commit f2cf86b7 authored by Sébastien Villemot's avatar Sébastien Villemot

Add copy constructors / assignment operators for the DataTree class hierarchy

In particular, it is necessary to turn back DataTree::AddVariable() into a
non-virtual method, because it is called from DataTree's constructor. Enforcing
the absence of leads/lags is now done using a new boolean DataTree::is_static.

Take advantage of the new copy constructor for handling
PlannerObjectiveStatement more elegantly.

Unfortunately it is not possible to implement *move* constructor / assigment
operators, because the reference ExprNode::datatree is not mutable.
parent 21528300
......@@ -2111,10 +2111,8 @@ ModelComparisonStatement::writeJsonOutput(ostream &output) const
output << "}";
}
PlannerObjectiveStatement::PlannerObjectiveStatement(SymbolTable &symbol_table,
NumericalConstants &num_constants,
ExternalFunctionsTable &external_functions_table) :
model_tree{symbol_table, num_constants, external_functions_table}
PlannerObjectiveStatement::PlannerObjectiveStatement(const StaticModel &model_tree_arg) :
model_tree {model_tree_arg}
{
}
......@@ -2132,8 +2130,8 @@ PlannerObjectiveStatement::checkPass(ModFileStructure &mod_file_struct, WarningC
mod_file_struct.planner_objective_present = true;
}
StaticModel &
PlannerObjectiveStatement::getPlannerObjective()
const StaticModel &
PlannerObjectiveStatement::getPlannerObjective() const
{
return model_tree;
}
......
......@@ -523,9 +523,7 @@ private:
StaticModel model_tree;
bool computing_pass_called{false};
public:
PlannerObjectiveStatement(SymbolTable &symbol_table,
NumericalConstants &num_constants,
ExternalFunctionsTable &external_functions_table);
PlannerObjectiveStatement(const StaticModel &model_tree_arg);
/*! \todo check there are only endogenous variables at the current period in the objective
(no exogenous, no lead/lag) */
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
......@@ -534,7 +532,7 @@ public:
void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream &output) const override;
//! Return a reference the Planner Objective model tree
StaticModel &getPlannerObjective();
const StaticModel &getPlannerObjective() const;
};
class BVARDensityStatement : public Statement
......
......@@ -26,12 +26,8 @@
#include "DataTree.hh"
DataTree::DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg) :
symbol_table{symbol_table_arg},
num_constants{num_constants_arg},
external_functions_table{external_functions_table_arg}
void
DataTree::initConstants()
{
Zero = AddNonNegativeConstant("0");
One = AddNonNegativeConstant("1");
......@@ -46,8 +42,76 @@ DataTree::DataTree(SymbolTable &symbol_table_arg,
Pi = AddNonNegativeConstant("3.141592653589793");
}
DataTree::DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg,
bool is_dynamic_arg) :
symbol_table{symbol_table_arg},
num_constants{num_constants_arg},
external_functions_table{external_functions_table_arg},
is_dynamic {is_dynamic_arg}
{
initConstants();
}
DataTree::~DataTree() = default;
DataTree::DataTree(const DataTree &d) :
symbol_table {d.symbol_table},
num_constants {d.num_constants},
external_functions_table {d.external_functions_table},
is_dynamic {d.is_dynamic},
local_variables_vector {d.local_variables_vector}
{
// Constants must be initialized first because they are used in some Add* methods
initConstants();
for (const auto & it : d.node_list)
it->cloneDynamic(*this);
assert(node_list.size() == d.node_list.size());
for (const auto & it : d.local_variables_table)
local_variables_table[it.first] = it.second->cloneDynamic(*this);
}
DataTree &
DataTree::operator=(const DataTree &d)
{
assert (&symbol_table == &d.symbol_table);
assert (&num_constants == &d.num_constants);
assert (&external_functions_table == &d.external_functions_table);
assert (is_dynamic == d.is_dynamic);
num_const_node_map.clear();
variable_node_map.clear();
unary_op_node_map.clear();
binary_op_node_map.clear();
trinary_op_node_map.clear();
external_function_node_map.clear();
var_expectation_node_map.clear();
pac_expectation_node_map.clear();
first_deriv_external_function_node_map.clear();
second_deriv_external_function_node_map.clear();
node_list.clear();
// Constants must be initialized first because they are used in some Add* methods
initConstants();
for (const auto & it : d.node_list)
it->cloneDynamic(*this);
assert(node_list.size() == d.node_list.size());
local_variables_vector = d.local_variables_vector;
for (const auto & it : d.local_variables_table)
local_variables_table[it.first] = it.second->cloneDynamic(*this);
return *this;
}
expr_t
DataTree::AddNonNegativeConstant(const string &value)
{
......@@ -65,8 +129,14 @@ DataTree::AddNonNegativeConstant(const string &value)
}
VariableNode *
DataTree::AddVariableInternal(int symb_id, int lag)
DataTree::AddVariable(int symb_id, int lag)
{
if (lag != 0 && !is_dynamic)
{
cerr << "Leads/lags not authorized in this DataTree" << endl;
exit(EXIT_FAILURE);
}
auto it = variable_node_map.find({ symb_id, lag });
if (it != variable_node_map.end())
return it->second;
......@@ -87,13 +157,6 @@ DataTree::ParamUsedWithLeadLagInternal() const
return false;
}
VariableNode *
DataTree::AddVariable(int symb_id, int lag)
{
assert(lag == 0);
return AddVariableInternal(symb_id, lag);
}
expr_t
DataTree::AddPlus(expr_t iArg1, expr_t iArg2)
{
......
......@@ -45,6 +45,8 @@ public:
NumericalConstants &num_constants;
//! A reference to the external functions table
ExternalFunctionsTable &external_functions_table;
//! Is it possible to use leads/lags on variable nodes?
const bool is_dynamic;
protected:
//! num_constant_id -> NumConstNode
......@@ -92,9 +94,6 @@ protected:
//! Stores the order of appearance of local variables in the model block. Needed following change in #563
vector<int> local_variables_vector;
//! Internal implementation of AddVariable(), without the check on the lag
VariableNode *AddVariableInternal(int symb_id, int lag);
//! Internal implementation of ParamUsedWithLeadLag()
bool ParamUsedWithLeadLagInternal() const;
......@@ -115,17 +114,21 @@ private:
inline expr_t AddBinaryOp(expr_t arg1, BinaryOpcode op_code, expr_t arg2, int powerDerivOrder = 0);
inline expr_t AddTrinaryOp(expr_t arg1, TrinaryOpcode op_code, expr_t arg2, expr_t arg3);
//! Initializes the predefined constants, used only from the constructors
void initConstants();
public:
DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg);
ExternalFunctionsTable &external_functions_table_arg,
bool is_static_args = false);
virtual
~DataTree();
DataTree(const DataTree &) = delete;
DataTree(const DataTree &d);
DataTree(DataTree &&) = delete;
DataTree & operator=(const DataTree &) = delete;
DataTree & operator=(const DataTree &d);
DataTree & operator=(DataTree &&) = delete;
//! Some predefined constants
......@@ -149,8 +152,7 @@ public:
//! Adds a non-negative numerical constant (possibly Inf or NaN)
expr_t AddNonNegativeConstant(const string &value);
//! Adds a variable
/*! The default implementation of the method refuses any lag != 0 */
virtual VariableNode *AddVariable(int symb_id, int lag = 0);
VariableNode *AddVariable(int symb_id, int lag = 0);
//! Adds "arg1+arg2" to model tree
expr_t AddPlus(expr_t iArg1, expr_t iArg2);
//! Adds "arg1-arg2" to model tree
......
......@@ -31,21 +31,217 @@
#include "DynamicModel.hh"
void
DynamicModel::copyHelper(const DynamicModel &m)
{
auto f = [this](const ExprNode *e) { return e->cloneDynamic(*this); };
for (const auto &it : m.static_only_equations)
static_only_equations.push_back(dynamic_cast<BinaryOpNode *>(f(it)));
auto convert_vector_tt = [this,f](vector<temporary_terms_t> vtt)
{
vector<temporary_terms_t> vtt2;
for (const auto &tt : vtt)
{
temporary_terms_t tt2;
for (const auto &it : tt)
tt2.insert(f(it));
vtt2.push_back(tt2);
}
return vtt2;
};
for (const auto &it : m.v_temporary_terms)
v_temporary_terms.push_back(convert_vector_tt(it));
for (const auto &it : m.first_chain_rule_derivatives)
first_chain_rule_derivatives[it.first] = f(it.second);
for (const auto &it : m.equation_type_and_normalized_equation)
equation_type_and_normalized_equation.push_back(make_pair(it.first, f(it.second)));
for (const auto &it : m.blocks_derivatives)
{
block_derivatives_equation_variable_laglead_nodeid_t v;
for (const auto &it2 : it)
v.push_back(make_pair(it2.first, make_pair(it2.second.first, f(it2.second.second))));
blocks_derivatives.push_back(v);
}
for (const auto &it : m.dynamic_jacobian)
dynamic_jacobian[it.first] = f(it.second);
auto convert_derivative_t = [this,f](derivative_t dt)
{
derivative_t dt2;
for (const auto &it : dt)
dt2[it.first] = f(it.second);
return dt2;
};
for (const auto &it : m.derivative_endo)
derivative_endo.push_back(convert_derivative_t(it));
for (const auto &it : m.derivative_other_endo)
derivative_other_endo.push_back(convert_derivative_t(it));
for (const auto &it : m.derivative_exo)
derivative_exo.push_back(convert_derivative_t(it));
for (const auto &it : m.derivative_exo_det)
derivative_exo_det.push_back(convert_derivative_t(it));
for (const auto &it : m.pac_expectation_info)
pac_expectation_info.insert(dynamic_cast<const PacExpectationNode *>(f(it)));
}
DynamicModel::DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg,
TrendComponentModelTable &trend_component_model_table_arg,
VarModelTable &var_model_table_arg) :
ModelTree{symbol_table_arg, num_constants_arg, external_functions_table_arg},
ModelTree {symbol_table_arg, num_constants_arg, external_functions_table_arg, true},
trend_component_model_table{trend_component_model_table_arg},
var_model_table{var_model_table_arg}
{
}
VariableNode *
DynamicModel::AddVariable(int symb_id, int lag)
DynamicModel::DynamicModel(const DynamicModel &m) :
ModelTree {m},
trend_component_model_table {m.trend_component_model_table},
var_model_table {m.var_model_table},
static_only_equations_lineno {m.static_only_equations_lineno},
static_only_equations_equation_tags {m.static_only_equations_equation_tags},
deriv_id_table {m.deriv_id_table},
inv_deriv_id_table {m.inv_deriv_id_table},
dyn_jacobian_cols_table {m.dyn_jacobian_cols_table},
max_lag {m.max_lag},
max_lead {m.max_lead},
max_endo_lag {m.max_endo_lag},
max_endo_lead {m.max_endo_lead},
max_exo_lag {m.max_exo_lag},
max_exo_lead {m.max_exo_lead},
max_exo_det_lag {m.max_exo_det_lag},
max_exo_det_lead {m.max_exo_det_lead},
max_lag_orig {m.max_lag_orig},
max_lead_orig {m.max_lead_orig},
max_endo_lag_orig {m.max_endo_lag_orig},
max_endo_lead_orig {m.max_endo_lead_orig},
max_exo_lag_orig {m.max_exo_lag_orig},
max_exo_lead_orig {m.max_exo_lead_orig},
max_exo_det_lag_orig {m.max_exo_det_lag_orig},
max_exo_det_lead_orig {m.max_exo_det_lead_orig},
xrefs {m.xrefs},
xref_param {m.xref_param},
xref_endo {m.xref_endo},
xref_exo {m.xref_exo},
xref_exo_det {m.xref_exo_det},
nonzero_hessian_eqs {m.nonzero_hessian_eqs},
v_temporary_terms_inuse {m.v_temporary_terms_inuse},
map_idx {m.map_idx},
global_temporary_terms {m.global_temporary_terms},
block_type_firstequation_size_mfs {m.block_type_firstequation_size_mfs},
blocks_linear {m.blocks_linear},
other_endo_block {m.other_endo_block},
exo_block {m.exo_block},
exo_det_block {m.exo_det_block},
block_var_exo {m.block_var_exo},
block_exo_index {m.block_exo_index},
block_det_exo_index {m.block_det_exo_index},
block_other_endo_index {m.block_other_endo_index},
block_col_type {m.block_col_type},
variable_block_lead_lag {m.variable_block_lead_lag},
equation_block {m.equation_block},
var_expectation_functions_to_write {m.var_expectation_functions_to_write},
endo_max_leadlag_block {m.endo_max_leadlag_block},
other_endo_max_leadlag_block {m.other_endo_max_leadlag_block},
exo_max_leadlag_block {m.exo_max_leadlag_block},
exo_det_max_leadlag_block {m.exo_det_max_leadlag_block},
max_leadlag_block {m.max_leadlag_block}
{
return AddVariableInternal(symb_id, lag);
copyHelper(m);
}
DynamicModel &
DynamicModel::operator=(const DynamicModel &m)
{
ModelTree::operator=(m);
assert(&trend_component_model_table == &m.trend_component_model_table);
assert(&var_model_table == &m.var_model_table);
static_only_equations_lineno = m.static_only_equations_lineno;
static_only_equations_equation_tags = m.static_only_equations_equation_tags;
deriv_id_table = m.deriv_id_table;
inv_deriv_id_table = m.inv_deriv_id_table;
dyn_jacobian_cols_table = m.dyn_jacobian_cols_table;
max_lag = m.max_lag;
max_lead = m.max_lead;
max_endo_lag = m.max_endo_lag;
max_endo_lead = m.max_endo_lead;
max_exo_lag = m.max_exo_lag;
max_exo_lead = m.max_exo_lead;
max_exo_det_lag = m.max_exo_det_lag;
max_exo_det_lead = m.max_exo_det_lead;
max_lag_orig = m.max_lag_orig;
max_lead_orig = m.max_lead_orig;
max_endo_lag_orig = m.max_endo_lag_orig;
max_endo_lead_orig = m.max_endo_lead_orig;
max_exo_lag_orig = m.max_exo_lag_orig;
max_exo_lead_orig = m.max_exo_lead_orig;
max_exo_det_lag_orig = m.max_exo_det_lag_orig;
max_exo_det_lead_orig = m.max_exo_det_lead_orig;
xrefs = m.xrefs;
xref_param = m.xref_param;
xref_endo = m.xref_endo;
xref_exo = m.xref_exo;
xref_exo_det = m.xref_exo_det;
nonzero_hessian_eqs = m.nonzero_hessian_eqs;
v_temporary_terms.clear();
v_temporary_terms_inuse = m.v_temporary_terms_inuse;
first_chain_rule_derivatives.clear();
map_idx = m.map_idx;
global_temporary_terms = m.global_temporary_terms;
equation_type_and_normalized_equation.clear();
block_type_firstequation_size_mfs = m.block_type_firstequation_size_mfs;
blocks_derivatives.clear();
dynamic_jacobian.clear();
blocks_linear = m.blocks_linear;
derivative_endo.clear();
derivative_other_endo.clear();
derivative_exo.clear();
derivative_exo_det.clear();
other_endo_block = m.other_endo_block;
exo_block = m.exo_block;
exo_det_block = m.exo_det_block;
block_var_exo = m.block_var_exo;
block_exo_index = m.block_exo_index;
block_det_exo_index = m.block_det_exo_index;
block_other_endo_index = m.block_other_endo_index;
block_col_type = m.block_col_type;
variable_block_lead_lag = m.variable_block_lead_lag;
equation_block = m.equation_block;
var_expectation_functions_to_write = m.var_expectation_functions_to_write;
pac_expectation_info.clear();
endo_max_leadlag_block = m.endo_max_leadlag_block;
other_endo_max_leadlag_block = m.other_endo_max_leadlag_block;
exo_max_leadlag_block = m.exo_max_leadlag_block;
exo_det_max_leadlag_block = m.exo_det_max_leadlag_block;
max_leadlag_block = m.max_leadlag_block;
copyHelper(m);
return *this;
}
void
......@@ -4827,40 +5023,6 @@ DynamicModel::writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputTyp
}
}
void
DynamicModel::cloneDynamic(DynamicModel &dynamic_model) const
{
/* Ensure that we are using the same symbol table, because at many places we manipulate
symbol IDs rather than strings */
assert(&symbol_table == &dynamic_model.symbol_table);
// Convert model local variables (need to be done first)
for (int it : local_variables_vector)
dynamic_model.AddLocalVariable(it, local_variables_table.find(it)->second->cloneDynamic(dynamic_model));
// Convert equations
for (size_t i = 0; i < equations.size(); i++)
{
vector<pair<string, string>> eq_tags;
for (const auto & equation_tag : equation_tags)
if (equation_tag.first == (int)i)
eq_tags.push_back(equation_tag.second);
dynamic_model.addEquation(equations[i]->cloneDynamic(dynamic_model), equations_lineno[i], eq_tags);
}
// Convert auxiliary equations
for (auto aux_equation : aux_equations)
dynamic_model.addAuxEquation(aux_equation->cloneDynamic(dynamic_model));
// Convert static_only equations
for (size_t i = 0; i < static_only_equations.size(); i++)
dynamic_model.addStaticOnlyEquation(static_only_equations[i]->cloneDynamic(dynamic_model),
static_only_equations_lineno[i],
static_only_equations_equation_tags[i]);
dynamic_model.setLeadsLagsOrig();
}
void
DynamicModel::replaceMyEquations(DynamicModel &dynamic_model) const
{
......
......@@ -254,15 +254,22 @@ private:
void findPacExpectationEquationNumbers(vector<int> &eqnumber) const;
//! Internal helper for the copy constructor and assignment operator
/*! Copies all the structures that contain ExprNode*, by the converting the
pointers into their equivalent in the new tree */
void copyHelper(const DynamicModel &m);
public:
DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg,
TrendComponentModelTable &trend_component_model_table_arg,
VarModelTable &var_model_table_arg);
//! Adds a variable node
/*! This implementation allows for non-zero lag */
VariableNode *AddVariable(int symb_id, int lag = 0) override;
DynamicModel(const DynamicModel &m);
DynamicModel(DynamicModel &&) = delete;
DynamicModel & operator=(const DynamicModel &m);
DynamicModel & operator=(DynamicModel &&) = delete;
//! Compute cross references
void computeXrefs();
......@@ -374,10 +381,6 @@ public:
//! Set the max leads/lags of the original model
void setLeadsLagsOrig();
//! Copies a dynamic model (only the equations)
/*! It assumes that the dynamic model given in argument has just been allocated */
void cloneDynamic(DynamicModel &dynamic_model) const;
//! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous
void computeRamseyPolicyFOCs(const StaticModel &static_model, const bool nopreprocessoroutput);
//! Replaces the model equations in dynamic_model with those in this model
......
......@@ -367,7 +367,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const
// - except adl and diff which we always want expanded
dynamic_model.substituteAdl();
dynamic_model.setLeadsLagsOrig();
dynamic_model.cloneDynamic(original_model);
original_model = dynamic_model;
if (nostrict)
{
......@@ -457,7 +457,7 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const
if (nonstationary_variables)
{
dynamic_model.detrendEquations();
dynamic_model.cloneDynamic(trend_dynamic_model);
trend_dynamic_model = dynamic_model;
dynamic_model.removeTrendVariableFromEquations();
}
......@@ -485,8 +485,8 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, const
we have to call computeDerivIDs (in computeRamseyPolicyFOCs and computingPass)
*/
if (linear)
dynamic_model.cloneDynamic(orig_ramsey_dynamic_model);
dynamic_model.cloneDynamic(ramsey_FOC_equations_dynamic_model);
orig_ramsey_dynamic_model = dynamic_model;
ramsey_FOC_equations_dynamic_model = dynamic_model;
ramsey_FOC_equations_dynamic_model.computeRamseyPolicyFOCs(planner_objective, nopreprocessoroutput);
ramsey_FOC_equations_dynamic_model.replaceMyEquations(dynamic_model);
mod_file_struct.ramsey_eq_nbr = dynamic_model.equation_number() - mod_file_struct.orig_eq_nbr;
......@@ -696,7 +696,7 @@ ModFile::computingPass(bool no_tmp_terms, FileOutputType output, int params_deri
dynamic_model.toStatic(static_model);
if (linear_decomposition)
{
dynamic_model.cloneDynamic(non_linear_equations_dynamic_model);
non_linear_equations_dynamic_model = dynamic_model;
non_linear_equations_dynamic_model.set_cutoff_to_zero();
non_linear_equations_dynamic_model.computingPass(true, false, false, 0, global_eval_context, no_tmp_terms, block, use_dll, byte_code, nopreprocessoroutput, linear_decomposition);
}
......
......@@ -31,6 +31,28 @@ SteadyStateModel::SteadyStateModel(SymbolTable &symbol_table_arg,
{
}
SteadyStateModel::SteadyStateModel(const SteadyStateModel &m) :
DataTree {m},
static_model {m.static_model}
{
for (const auto &it : m.def_table)
def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
}
SteadyStateModel &
SteadyStateModel::operator=(const SteadyStateModel &m)
{
DataTree::operator=(m);
assert(&static_model == &m.static_model);
def_table.clear();
for (const auto &it : m.def_table)
def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
return *this;
}
void
SteadyStateModel::addDefinition(int symb_id, expr_t expr)
{
......@@ -277,6 +299,30 @@ Epilogue::Epilogue(SymbolTable &symbol_table_arg,
{
}
Epilogue::Epilogue(const Epilogue &m) :
DynamicModel {m},
endogs {m.endogs},
exogs {m.exogs}
{
for (const auto &it : m.def_table)
def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
}
Epilogue &
Epilogue::operator=(const Epilogue &m)
{
DynamicModel::operator=(m);
endogs = m.endogs;
exogs = m.exogs;
def_table.clear();
for (const auto &it : m.def_table)
def_table.push_back(make_pair(it.first, it.second->cloneDynamic(*this)));
return *this;
}
void
Epilogue::addDefinition(int symb_id, expr_t expr)
{
......
......@@ -40,6 +40,12 @@ public:
NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg,
const StaticModel &static_model_arg);
SteadyStateModel(const SteadyStateModel &m);
SteadyStateModel(SteadyStateModel &&) = delete;
SteadyStateModel & operator=(const SteadyStateModel &m);
SteadyStateModel & operator=(SteadyStateModel &&) = delete;
//! Add an expression of the form "var = expr;"
void addDefinition(int symb_id, expr_t expr);
//! Add an expression of the form "[ var1, var2, ... ] = expr;"
......@@ -76,6 +82,11 @@ public:
TrendComponentModelTable &trend_component_model_table_arg,
VarModelTable &var_model_table_arg);
Epilogue(const Epilogue &m);
Epilogue(Epilogue &&) = delete;
Epilogue & operator=(const Epilogue &m);
Epilogue & operator=(Epilogue &&) = delete;
//! Add an expression of the form "var = expr;"
void addDefinition(int symb_id, expr_t expr);
......