/*
* Copyright (C) 2007-2018 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 .
*/
#include
#include
#include
#include
#include
#include
#include "ExprNode.hh"
#include "DataTree.hh"
#include "ModFile.hh"
ExprNode::ExprNode(DataTree &datatree_arg, int idx_arg) : datatree{datatree_arg}, idx{idx_arg}, preparedForDerivation{false}
{
}
ExprNode::~ExprNode()
= default;
expr_t
ExprNode::getDerivative(int deriv_id)
{
if (!preparedForDerivation)
prepareForDerivation();
// Return zero if derivative is necessarily null (using symbolic a priori)
auto it = non_null_derivatives.find(deriv_id);
if (it == non_null_derivatives.end())
return datatree.Zero;
// If derivative is stored in cache, use the cached value, otherwise compute it (and cache it)
map::const_iterator it2 = derivatives.find(deriv_id);
if (it2 != derivatives.end())
return it2->second;
else
{
expr_t d = computeDerivative(deriv_id);
derivatives[deriv_id] = d;
return d;
}
}
int
ExprNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const
{
// For a constant, a variable, or a unary op, the precedence is maximal
return 100;
}
int
ExprNode::precedenceJson(const temporary_terms_t &temporary_terms) const
{
// For a constant, a variable, or a unary op, the precedence is maximal
return 100;
}
int
ExprNode::cost(int cost, bool is_matlab) const
{
// For a terminal node, the cost is null
return 0;
}
int
ExprNode::cost(const temporary_terms_t &temp_terms_map, bool is_matlab) const
{
// For a terminal node, the cost is null
return 0;
}
int
ExprNode::cost(const map &temp_terms_map, bool is_matlab) const
{
// For a terminal node, the cost is null
return 0;
}
bool
ExprNode::checkIfTemporaryTermThenWrite(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs) const
{
auto it = temporary_terms.find(const_cast(this));
if (it == temporary_terms.end())
return false;
if (output_type == ExprNodeOutputType::matlabDynamicModelSparse)
output << "T" << idx << "(it_)";
else
if (output_type == ExprNodeOutputType::matlabStaticModelSparse || isCOutput(output_type))
output << "T" << idx;
else
{
auto it2 = temporary_terms_idxs.find(const_cast(this));
// It is the responsibility of the caller to ensure that all temporary terms have their index
assert(it2 != temporary_terms_idxs.end());
output << "T" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< it2->second + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
}
return true;
}
void
ExprNode::collectVariables(SymbolType type, set &result) const
{
set> symbs_lags;
collectDynamicVariables(type, symbs_lags);
transform(symbs_lags.begin(), symbs_lags.end(), inserter(result, result.begin()),
[](auto x) { return x.first; });
}
void
ExprNode::collectEndogenous(set> &result) const
{
set> symb_ids;
collectDynamicVariables(SymbolType::endogenous, symb_ids);
for (const auto & symb_id : symb_ids)
result.emplace(datatree.symbol_table.getTypeSpecificID(symb_id.first), symb_id.second);
}
void
ExprNode::collectExogenous(set> &result) const
{
set> symb_ids;
collectDynamicVariables(SymbolType::exogenous, symb_ids);
for (const auto & symb_id : symb_ids)
result.emplace(datatree.symbol_table.getTypeSpecificID(symb_id.first), symb_id.second);
}
void
ExprNode::computeTemporaryTerms(map> &reference_count,
map &temp_terms_map,
bool is_matlab, NodeTreeReference tr) const
{
// Nothing to do for a terminal node
}
void
ExprNode::computeTemporaryTerms(map &reference_count,
temporary_terms_t &temporary_terms,
map> &first_occurence,
int Curr_block,
vector> &v_temporary_terms,
int equation) const
{
// Nothing to do for a terminal node
}
pair
ExprNode::normalizeEquation(int var_endo, vector>> &List_of_Op_RHS) const
{
/* nothing to do */
return { 0, nullptr };
}
void
ExprNode::writeOutput(ostream &output) const
{
writeOutput(output, ExprNodeOutputType::matlabOutsideModel, {}, {});
}
void
ExprNode::writeOutput(ostream &output, ExprNodeOutputType output_type) const
{
writeOutput(output, output_type, {}, {});
}
void
ExprNode::writeOutput(ostream &output, ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms, const temporary_terms_idxs_t &temporary_terms_idxs) const
{
writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, {});
}
void
ExprNode::compile(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic) const
{
compile(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx, dynamic, steady_dynamic, {});
}
void
ExprNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs,
deriv_node_temp_terms_t &tef_terms) const
{
// Nothing to do
}
void
ExprNode::writeJsonExternalFunctionOutput(vector &efout,
const temporary_terms_t &temporary_terms,
deriv_node_temp_terms_t &tef_terms,
const bool isdynamic) const
{
// Nothing to do
}
void
ExprNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
deriv_node_temp_terms_t &tef_terms) const
{
// Nothing to do
}
VariableNode *
ExprNode::createEndoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const
{
int n = maxEndoLead();
assert(n >= 2);
subst_table_t::const_iterator it = subst_table.find(this);
if (it != subst_table.end())
return const_cast(it->second);
expr_t substexpr = decreaseLeadsLags(n-1);
int lag = n-2;
// Each iteration tries to create an auxvar such that auxvar(+1)=expr(-lag)
// At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to expr(-lag-1) (resp. expr(-lag))
while (lag >= 0)
{
expr_t orig_expr = decreaseLeadsLags(lag);
it = subst_table.find(orig_expr);
if (it == subst_table.end())
{
int symb_id = datatree.symbol_table.addEndoLeadAuxiliaryVar(orig_expr->idx, substexpr);
neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
substexpr = datatree.AddVariable(symb_id, +1);
assert(dynamic_cast(substexpr) != nullptr);
subst_table[orig_expr] = dynamic_cast(substexpr);
}
else
substexpr = const_cast(it->second);
lag--;
}
return dynamic_cast(substexpr);
}
VariableNode *
ExprNode::createExoLeadAuxiliaryVarForMyself(subst_table_t &subst_table, vector &neweqs) const
{
int n = maxExoLead();
assert(n >= 1);
subst_table_t::const_iterator it = subst_table.find(this);
if (it != subst_table.end())
return const_cast(it->second);
expr_t substexpr = decreaseLeadsLags(n);
int lag = n-1;
// Each iteration tries to create an auxvar such that auxvar(+1)=expr(-lag)
// At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to expr(-lag-1) (resp. expr(-lag))
while (lag >= 0)
{
expr_t orig_expr = decreaseLeadsLags(lag);
it = subst_table.find(orig_expr);
if (it == subst_table.end())
{
int symb_id = datatree.symbol_table.addExoLeadAuxiliaryVar(orig_expr->idx, substexpr);
neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(symb_id, 0), substexpr)));
substexpr = datatree.AddVariable(symb_id, +1);
assert(dynamic_cast(substexpr) != nullptr);
subst_table[orig_expr] = dynamic_cast(substexpr);
}
else
substexpr = const_cast(it->second);
lag--;
}
return dynamic_cast(substexpr);
}
bool
ExprNode::isNumConstNodeEqualTo(double value) const
{
return false;
}
bool
ExprNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
return false;
}
void
ExprNode::getEndosAndMaxLags(map &model_endos_and_lags) const
{
}
NumConstNode::NumConstNode(DataTree &datatree_arg, int idx_arg, int id_arg) :
ExprNode(datatree_arg, idx_arg),
id(id_arg)
{
}
int
NumConstNode::countDiffs() const
{
return 0;
}
void
NumConstNode::prepareForDerivation()
{
preparedForDerivation = true;
// All derivatives are null, so non_null_derivatives is left empty
}
expr_t
NumConstNode::computeDerivative(int deriv_id)
{
return datatree.Zero;
}
void
NumConstNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
temporary_terms_inuse.insert(idx);
}
void
NumConstNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs,
const deriv_node_temp_terms_t &tef_terms) const
{
if (!checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
output << datatree.num_constants.get(id);
}
void
NumConstNode::writeJsonOutput(ostream &output,
const temporary_terms_t &temporary_terms,
const deriv_node_temp_terms_t &tef_terms,
const bool isdynamic) const
{
output << datatree.num_constants.get(id);
}
bool
NumConstNode::containsExternalFunction() const
{
return false;
}
double
NumConstNode::eval(const eval_context_t &eval_context) const noexcept(false)
{
return (datatree.num_constants.getDouble(id));
}
void
NumConstNode::compile(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
const deriv_node_temp_terms_t &tef_terms) const
{
FLDC_ fldc(datatree.num_constants.getDouble(id));
fldc.write(CompileCode, instruction_number);
}
void
NumConstNode::collectVARLHSVariable(set &result) const
{
cerr << "ERROR: you can only have variables or unary ops on LHS of VAR" << endl;
exit(EXIT_FAILURE);
}
void
NumConstNode::collectDynamicVariables(SymbolType type_arg, set> &result) const
{
}
pair
NumConstNode::normalizeEquation(int var_endo, vector>> &List_of_Op_RHS) const
{
/* return the numercial constant */
return { 0, datatree.AddNonNegativeConstant(datatree.num_constants.get(id)) };
}
expr_t
NumConstNode::getChainRuleDerivative(int deriv_id, const map &recursive_variables)
{
return datatree.Zero;
}
expr_t
NumConstNode::toStatic(DataTree &static_datatree) const
{
return static_datatree.AddNonNegativeConstant(datatree.num_constants.get(id));
}
void
NumConstNode::computeXrefs(EquationInfo &ei) const
{
}
expr_t
NumConstNode::cloneDynamic(DataTree &dynamic_datatree) const
{
return dynamic_datatree.AddNonNegativeConstant(datatree.num_constants.get(id));
}
int
NumConstNode::maxEndoLead() const
{
return 0;
}
int
NumConstNode::maxExoLead() const
{
return 0;
}
int
NumConstNode::maxEndoLag() const
{
return 0;
}
int
NumConstNode::maxExoLag() const
{
return 0;
}
int
NumConstNode::maxLead() const
{
return 0;
}
int
NumConstNode::maxLag() const
{
return 0;
}
expr_t
NumConstNode::undiff() const
{
return const_cast(this);
}
int
NumConstNode::VarMinLag() const
{
return 1;
}
int
NumConstNode::VarMaxLag(DataTree &static_datatree, set &static_lhs) const
{
return 0;
}
int
NumConstNode::PacMaxLag(int lhs_symb_id) const
{
return 0;
}
expr_t
NumConstNode::decreaseLeadsLags(int n) const
{
return const_cast(this);
}
expr_t
NumConstNode::decreaseLeadsLagsPredeterminedVariables() const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteExoLead(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteExoLag(subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteExpectation(subst_table_t &subst_table, vector &neweqs, bool partial_information_model) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteAdl() const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteVarExpectation(const map &subst_table) const
{
return const_cast(this);
}
void
NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}
void
NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}
int
NumConstNode::findTrendVariable(int lhs_symb_id) const
{
return -1;
}
expr_t
NumConstNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
expr_t
NumConstNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
expr_t
NumConstNode::substitutePacExpectation(map &subst_table)
{
return const_cast(this);
}
expr_t
NumConstNode::differentiateForwardVars(const vector &subset, subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
bool
NumConstNode::isNumConstNodeEqualTo(double value) const
{
if (datatree.num_constants.getDouble(id) == value)
return true;
else
return false;
}
bool
NumConstNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
return false;
}
void
NumConstNode::getEndosAndMaxLags(map &model_endos_and_lags) const
{
}
bool
NumConstNode::containsPacExpectation(const string &pac_model_name) const
{
return false;
}
bool
NumConstNode::containsEndogenous() const
{
return false;
}
bool
NumConstNode::containsExogenous() const
{
return false;
}
expr_t
NumConstNode::replaceTrendVar() const
{
return const_cast(this);
}
expr_t
NumConstNode::detrend(int symb_id, bool log_trend, expr_t trend) const
{
return const_cast(this);
}
expr_t
NumConstNode::removeTrendLeadLag(map trend_symbols_map) const
{
return const_cast(this);
}
bool
NumConstNode::isInStaticForm() const
{
return true;
}
bool
NumConstNode::isParamTimesEndogExpr() const
{
return false;
}
void
NumConstNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars,
set>> &ar_params_and_vars) const
{
}
void
NumConstNode::getPacOptimizingShareAndExprNodes(set &optim_share,
expr_t &optim_part,
expr_t &non_optim_part) const
{
}
void
NumConstNode::getPacNonOptimizingPart(set, double>>>
¶ms_vars_and_scaling_factor) const
{
}
void
NumConstNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg)
{
}
void
NumConstNode::fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg)
{
}
bool
NumConstNode::isVarModelReferenced(const string &model_info_name) const
{
return false;
}
expr_t
NumConstNode::substituteStaticAuxiliaryVariable() const
{
return const_cast(this);
}
void
NumConstNode::fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const
{
}
VariableNode::VariableNode(DataTree &datatree_arg, int idx_arg, int symb_id_arg, int lag_arg) :
ExprNode(datatree_arg, idx_arg),
symb_id(symb_id_arg),
type(datatree.symbol_table.getType(symb_id_arg)),
lag(lag_arg)
{
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
assert(type != SymbolType::externalFunction
&& (lag == 0 || (type != SymbolType::modelLocalVariable && type != SymbolType::modFileLocalVariable)));
}
void
VariableNode::prepareForDerivation()
{
if (preparedForDerivation)
return;
preparedForDerivation = true;
// Fill in non_null_derivatives
switch (type)
{
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::parameter:
case SymbolType::trend:
case SymbolType::logTrend:
// For a variable or a parameter, the only non-null derivative is with respect to itself
non_null_derivatives.insert(datatree.getDerivID(symb_id, lag));
break;
case SymbolType::modelLocalVariable:
datatree.getLocalVariable(symb_id)->prepareForDerivation();
// Non null derivatives are those of the value of the local parameter
non_null_derivatives = datatree.getLocalVariable(symb_id)->non_null_derivatives;
break;
case SymbolType::modFileLocalVariable:
case SymbolType::statementDeclaredVariable:
case SymbolType::unusedEndogenous:
// Such a variable is never derived
break;
case SymbolType::externalFunction:
case SymbolType::endogenousVAR:
case SymbolType::endogenousEpilogue:
case SymbolType::exogenousEpilogue:
case SymbolType::parameterEpilogue:
cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
exit(EXIT_FAILURE);
}
}
expr_t
VariableNode::computeDerivative(int deriv_id)
{
switch (type)
{
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::parameter:
case SymbolType::trend:
case SymbolType::logTrend:
if (deriv_id == datatree.getDerivID(symb_id, lag))
return datatree.One;
else
return datatree.Zero;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->getDerivative(deriv_id);
case SymbolType::modFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::statementDeclaredVariable:
cerr << "eStatementDeclaredVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::unusedEndogenous:
cerr << "eUnusedEndogenous is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::externalFunction:
case SymbolType::endogenousVAR:
case SymbolType::endogenousEpilogue:
case SymbolType::exogenousEpilogue:
case SymbolType::parameterEpilogue:
cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
exit(EXIT_FAILURE);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
void
VariableNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
temporary_terms_inuse.insert(idx);
if (type == SymbolType::modelLocalVariable)
datatree.getLocalVariable(symb_id)->collectTemporary_terms(temporary_terms, temporary_terms_inuse, Curr_Block);
}
bool
VariableNode::containsExternalFunction() const
{
return false;
}
void
VariableNode::writeJsonOutput(ostream &output,
const temporary_terms_t &temporary_terms,
const deriv_node_temp_terms_t &tef_terms,
const bool isdynamic) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
{
output << "T" << idx;
return;
}
output << datatree.symbol_table.getName(symb_id);
if (isdynamic && lag != 0)
output << "(" << lag << ")";
}
void
VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs,
const deriv_node_temp_terms_t &tef_terms) const
{
if (checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
return;
if (isLatexOutput(output_type))
{
if (output_type == ExprNodeOutputType::latexDynamicSteadyStateOperator)
output << "\\bar";
output << "{" << datatree.symbol_table.getTeXName(symb_id);
if (output_type == ExprNodeOutputType::latexDynamicModel
&& (type == SymbolType::endogenous || type == SymbolType::exogenous || type == SymbolType::exogenousDet || type == SymbolType::modelLocalVariable || type == SymbolType::trend || type == SymbolType::logTrend))
{
output << "_{t";
if (lag != 0)
{
if (lag > 0)
output << "+";
output << lag;
}
output << "}";
}
output << "}";
return;
}
int i;
int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
switch (type)
{
case SymbolType::parameter:
case SymbolType::parameterEpilogue:
if (output_type == ExprNodeOutputType::matlabOutsideModel)
output << "M_.params" << "(" << tsid + 1 << ")";
else
output << "params" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + ARRAY_SUBSCRIPT_OFFSET(output_type) << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case SymbolType::modelLocalVariable:
if (output_type == ExprNodeOutputType::matlabDynamicModelSparse || output_type == ExprNodeOutputType::matlabStaticModelSparse
|| output_type == ExprNodeOutputType::matlabDynamicSteadyStateOperator || output_type == ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator
|| output_type == ExprNodeOutputType::CDynamicSteadyStateOperator)
{
output << "(";
datatree.getLocalVariable(symb_id)->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
output << ")";
}
else
/* We append underscores to avoid name clashes with "g1" or "oo_".
But we probably never arrive here because MLV are temporary terms… */
output << datatree.symbol_table.getName(symb_id) << "__";
break;
case SymbolType::modFileLocalVariable:
output << datatree.symbol_table.getName(symb_id);
break;
case SymbolType::endogenous:
switch (output_type)
{
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::CDynamicModel:
i = datatree.getDynJacobianCol(datatree.getDerivID(symb_id, lag)) + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::CStaticModel:
case ExprNodeOutputType::juliaStaticModel:
case ExprNodeOutputType::matlabStaticModel:
case ExprNodeOutputType::matlabStaticModelSparse:
i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabDynamicModelSparse:
i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
if (lag > 0)
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
else if (lag < 0)
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
else
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabOutsideModel:
output << "oo_.steady_state(" << tsid + 1 << ")";
break;
case ExprNodeOutputType::juliaDynamicSteadyStateOperator:
case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
case ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator:
output << "steady_state" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::CDynamicSteadyStateOperator:
output << "steady_state[" << tsid << "]";
break;
case ExprNodeOutputType::juliaSteadyStateFile:
case ExprNodeOutputType::steadyStateFile:
output << "ys_" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::epilogueFile:
output << datatree.symbol_table.getName(symb_id)
<< LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__";
if (lag != 0)
output << lag;
output << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case SymbolType::exogenous:
i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::matlabDynamicModelSparse:
if (lag > 0)
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
else if (lag < 0)
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
else
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::CDynamicModel:
if (lag == 0)
output << "x[it_+" << i << "*nb_row_x]";
else if (lag > 0)
output << "x[it_+" << lag << "+" << i << "*nb_row_x]";
else
output << "x[it_" << lag << "+" << i << "*nb_row_x]";
break;
case ExprNodeOutputType::CStaticModel:
case ExprNodeOutputType::juliaStaticModel:
case ExprNodeOutputType::matlabStaticModel:
case ExprNodeOutputType::matlabStaticModelSparse:
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabOutsideModel:
assert(lag == 0);
output << "oo_.exo_steady_state(" << i << ")";
break;
case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
output << "oo_.exo_steady_state(" << i << ")";
break;
case ExprNodeOutputType::juliaSteadyStateFile:
case ExprNodeOutputType::steadyStateFile:
output << "exo_" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::epilogueFile:
output << datatree.symbol_table.getName(symb_id)
<< LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__";
if (lag != 0)
output << lag;
output << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case SymbolType::exogenousDet:
i = tsid + datatree.symbol_table.exo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::matlabDynamicModelSparse:
if (lag > 0)
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_+" << lag << ", " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
else if (lag < 0)
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_" << lag << ", " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
else
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << "it_, " << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::CDynamicModel:
if (lag == 0)
output << "x[it_+" << i << "*nb_row_x]";
else if (lag > 0)
output << "x[it_+" << lag << "+" << i << "*nb_row_x]";
else
output << "x[it_" << lag << "+" << i << "*nb_row_x]";
break;
case ExprNodeOutputType::CStaticModel:
case ExprNodeOutputType::juliaStaticModel:
case ExprNodeOutputType::matlabStaticModel:
case ExprNodeOutputType::matlabStaticModelSparse:
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabOutsideModel:
assert(lag == 0);
output << "oo_.exo_det_steady_state(" << tsid + 1 << ")";
break;
case ExprNodeOutputType::matlabDynamicSteadyStateOperator:
output << "oo_.exo_det_steady_state(" << tsid + 1 << ")";
break;
case ExprNodeOutputType::juliaSteadyStateFile:
case ExprNodeOutputType::steadyStateFile:
output << "exo_" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::matlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::epilogueFile:
output << datatree.symbol_table.getName(symb_id)
<< LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__";
if (lag != 0)
output << lag;
output << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case SymbolType::endogenousEpilogue:
case SymbolType::exogenousEpilogue:
output << datatree.symbol_table.getName(symb_id)
<< LEFT_ARRAY_SUBSCRIPT(output_type) << "epilogue_it__";
if (lag != 0)
output << lag;
output << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case SymbolType::externalFunction:
case SymbolType::trend:
case SymbolType::logTrend:
case SymbolType::statementDeclaredVariable:
case SymbolType::unusedEndogenous:
case SymbolType::endogenousVAR:
cerr << "VariableNode::writeOutput: Impossible case" << endl;
exit(EXIT_FAILURE);
}
}
expr_t
VariableNode::substituteStaticAuxiliaryVariable() const
{
if (type == SymbolType::endogenous)
{
try
{
return datatree.symbol_table.getAuxiliaryVarsExprNode(symb_id)->substituteStaticAuxiliaryVariable();
}
catch (SymbolTable::SearchFailedException &e)
{
}
}
return const_cast(this);
}
double
VariableNode::eval(const eval_context_t &eval_context) const noexcept(false)
{
auto it = eval_context.find(symb_id);
if (it == eval_context.end())
throw EvalException();
return it->second;
}
void
VariableNode::compile(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
const deriv_node_temp_terms_t &tef_terms) const
{
if (type == SymbolType::modelLocalVariable || type == SymbolType::modFileLocalVariable)
datatree.getLocalVariable(symb_id)->compile(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx, dynamic, steady_dynamic, tef_terms);
else
{
int tsid = datatree.symbol_table.getTypeSpecificID(symb_id);
if (type == SymbolType::exogenousDet)
tsid += datatree.symbol_table.exo_nbr();
if (!lhs_rhs)
{
if (dynamic)
{
if (steady_dynamic) // steady state values in a dynamic model
{
FLDVS_ fldvs{static_cast(type), static_cast(tsid)};
fldvs.write(CompileCode, instruction_number);
}
else
{
if (type == SymbolType::parameter)
{
FLDV_ fldv{static_cast(type), static_cast(tsid)};
fldv.write(CompileCode, instruction_number);
}
else
{
FLDV_ fldv{static_cast(type), static_cast(tsid), lag};
fldv.write(CompileCode, instruction_number);
}
}
}
else
{
FLDSV_ fldsv{static_cast(type), static_cast(tsid)};
fldsv.write(CompileCode, instruction_number);
}
}
else
{
if (dynamic)
{
if (steady_dynamic) // steady state values in a dynamic model
{
cerr << "Impossible case: steady_state in rhs of equation" << endl;
exit(EXIT_FAILURE);
}
else
{
if (type == SymbolType::parameter)
{
FSTPV_ fstpv{static_cast(type), static_cast(tsid)};
fstpv.write(CompileCode, instruction_number);
}
else
{
FSTPV_ fstpv{static_cast(type), static_cast(tsid), lag};
fstpv.write(CompileCode, instruction_number);
}
}
}
else
{
FSTPSV_ fstpsv{static_cast(type), static_cast(tsid)};
fstpsv.write(CompileCode, instruction_number);
}
}
}
}
void
VariableNode::computeTemporaryTerms(map &reference_count,
temporary_terms_t &temporary_terms,
map> &first_occurence,
int Curr_block,
vector> &v_temporary_terms,
int equation) const
{
if (type == SymbolType::modelLocalVariable)
datatree.getLocalVariable(symb_id)->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, v_temporary_terms, equation);
}
void
VariableNode::collectVARLHSVariable(set &result) const
{
if (type == SymbolType::endogenous && lag == 0)
result.insert(const_cast(this));
else
{
cerr << "ERROR: you can only have endogenous variables or unary ops on LHS of VAR" << endl;
exit(EXIT_FAILURE);
}
}
void
VariableNode::collectDynamicVariables(SymbolType type_arg, set> &result) const
{
if (type == type_arg)
result.emplace(symb_id, lag);
if (type == SymbolType::modelLocalVariable)
datatree.getLocalVariable(symb_id)->collectDynamicVariables(type_arg, result);
}
pair
VariableNode::normalizeEquation(int var_endo, vector>> &List_of_Op_RHS) const
{
/* The equation has to be normalized with respect to the current endogenous variable ascribed to it.
The two input arguments are :
- The ID of the endogenous variable associated to the equation.
- The list of operators and operands needed to normalize the equation*
The pair returned by NormalizeEquation is composed of
- a flag indicating if the expression returned contains (flag = 1) or not (flag = 0)
the endogenous variable related to the equation.
If the expression contains more than one occurence of the associated endogenous variable,
the flag is equal to 2.
- an expression equal to the RHS if flag = 0 and equal to NULL elsewhere
*/
if (type == SymbolType::endogenous)
{
if (datatree.symbol_table.getTypeSpecificID(symb_id) == var_endo && lag == 0)
/* the endogenous variable */
return { 1, nullptr };
else
return { 0, datatree.AddVariable(symb_id, lag) };
}
else
{
if (type == SymbolType::parameter)
return { 0, datatree.AddVariable(symb_id, 0) };
else
return { 0, datatree.AddVariable(symb_id, lag) };
}
}
expr_t
VariableNode::getChainRuleDerivative(int deriv_id, const map &recursive_variables)
{
switch (type)
{
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::parameter:
case SymbolType::trend:
case SymbolType::logTrend:
if (deriv_id == datatree.getDerivID(symb_id, lag))
return datatree.One;
else
{
//if there is in the equation a recursive variable we could use a chaine rule derivation
auto it = recursive_variables.find(datatree.getDerivID(symb_id, lag));
if (it != recursive_variables.end())
{
map::const_iterator it2 = derivatives.find(deriv_id);
if (it2 != derivatives.end())
return it2->second;
else
{
map recursive_vars2(recursive_variables);
recursive_vars2.erase(it->first);
//expr_t c = datatree.AddNonNegativeConstant("1");
expr_t d = datatree.AddUMinus(it->second->getChainRuleDerivative(deriv_id, recursive_vars2));
//d = datatree.AddTimes(c, d);
derivatives[deriv_id] = d;
return d;
}
}
else
return datatree.Zero;
}
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->getChainRuleDerivative(deriv_id, recursive_variables);
case SymbolType::modFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::statementDeclaredVariable:
cerr << "eStatementDeclaredVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::unusedEndogenous:
cerr << "eUnusedEndogenous is not derivable" << endl;
exit(EXIT_FAILURE);
case SymbolType::externalFunction:
case SymbolType::endogenousVAR:
case SymbolType::endogenousEpilogue:
case SymbolType::exogenousEpilogue:
case SymbolType::parameterEpilogue:
cerr << "VariableNode::getChainRuleDerivative: Impossible case" << endl;
exit(EXIT_FAILURE);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
expr_t
VariableNode::toStatic(DataTree &static_datatree) const
{
return static_datatree.AddVariable(symb_id);
}
void
VariableNode::computeXrefs(EquationInfo &ei) const
{
switch (type)
{
case SymbolType::endogenous:
ei.endo.emplace(symb_id, lag);
break;
case SymbolType::exogenous:
ei.exo.emplace(symb_id, lag);
break;
case SymbolType::exogenousDet:
ei.exo_det.emplace(symb_id, lag);
break;
case SymbolType::parameter:
ei.param.emplace(symb_id, 0);
break;
case SymbolType::trend:
case SymbolType::logTrend:
case SymbolType::modelLocalVariable:
case SymbolType::modFileLocalVariable:
case SymbolType::statementDeclaredVariable:
case SymbolType::unusedEndogenous:
case SymbolType::externalFunction:
case SymbolType::endogenousVAR:
case SymbolType::endogenousEpilogue:
case SymbolType::exogenousEpilogue:
case SymbolType::parameterEpilogue:
break;
}
}
expr_t
VariableNode::cloneDynamic(DataTree &dynamic_datatree) const
{
return dynamic_datatree.AddVariable(symb_id, lag);
}
int
VariableNode::maxEndoLead() const
{
switch (type)
{
case SymbolType::endogenous:
return max(lag, 0);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxEndoLead();
default:
return 0;
}
}
int
VariableNode::maxExoLead() const
{
switch (type)
{
case SymbolType::exogenous:
return max(lag, 0);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxExoLead();
default:
return 0;
}
}
int
VariableNode::maxEndoLag() const
{
switch (type)
{
case SymbolType::endogenous:
return max(-lag, 0);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxEndoLag();
default:
return 0;
}
}
int
VariableNode::maxExoLag() const
{
switch (type)
{
case SymbolType::exogenous:
return max(-lag, 0);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxExoLag();
default:
return 0;
}
}
int
VariableNode::maxLead() const
{
switch (type)
{
case SymbolType::endogenous:
return lag;
case SymbolType::exogenous:
return lag;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxLead();
default:
return 0;
}
}
int
VariableNode::VarMinLag() const
{
switch (type)
{
case SymbolType::endogenous:
return -lag;
case SymbolType::exogenous:
if (lag > 0)
return -lag;
else
return 1; // Can have contemporaneus exog in VAR
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->VarMinLag();
default:
return 1;
}
}
int
VariableNode::maxLag() const
{
switch (type)
{
case SymbolType::endogenous:
return -lag;
case SymbolType::exogenous:
return -lag;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->maxLag();
default:
return 0;
}
}
expr_t
VariableNode::undiff() const
{
return const_cast(this);
}
int
VariableNode::VarMaxLag(DataTree &static_datatree, set &static_lhs) const
{
auto it = static_lhs.find(this->toStatic(static_datatree));
if (it == static_lhs.end())
return 0;
return maxLag();
}
int
VariableNode::PacMaxLag(int lhs_symb_id) const
{
if (lhs_symb_id == symb_id)
return -lag;
return 0;
}
expr_t
VariableNode::substituteAdl() const
{
return const_cast(this);
}
expr_t
VariableNode::substituteVarExpectation(const map &subst_table) const
{
return const_cast(this);
}
void
VariableNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}
void
VariableNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}
int
VariableNode::findTrendVariable(int lhs_symb_id) const
{
return -1;
}
expr_t
VariableNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table,
vector &neweqs) const
{
return const_cast(this);
}
expr_t
VariableNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector &neweqs) const
{
return const_cast(this);
}
expr_t
VariableNode::substitutePacExpectation(map &subst_table)
{
return const_cast(this);
}
expr_t
VariableNode::decreaseLeadsLags(int n) const
{
switch (type)
{
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::trend:
case SymbolType::logTrend:
return datatree.AddVariable(symb_id, lag-n);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id)->decreaseLeadsLags(n);
default:
return const_cast(this);
}
}
expr_t
VariableNode::decreaseLeadsLagsPredeterminedVariables() const
{
if (datatree.symbol_table.isPredetermined(symb_id))
return decreaseLeadsLags(1);
else
return const_cast(this);
}
expr_t
VariableNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
expr_t value;
switch (type)
{
case SymbolType::endogenous:
if (lag <= 1)
return const_cast(this);
else
return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
case SymbolType::modelLocalVariable:
value = datatree.getLocalVariable(symb_id);
if (value->maxEndoLead() <= 1)
return const_cast(this);
else
return value->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model);
default:
return const_cast(this);
}
}
expr_t
VariableNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const
{
VariableNode *substexpr;
expr_t value;
subst_table_t::const_iterator it;
int cur_lag;
switch (type)
{
case SymbolType::endogenous:
if (lag >= -1)
return const_cast(this);
it = subst_table.find(this);
if (it != subst_table.end())
return const_cast(it->second);
substexpr = datatree.AddVariable(symb_id, -1);
cur_lag = -2;
// Each iteration tries to create an auxvar such that auxvar(-1)=curvar(cur_lag)
// At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag+1) (resp. curvar(cur_lag))
while (cur_lag >= lag)
{
VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag);
it = subst_table.find(orig_expr);
if (it == subst_table.end())
{
int aux_symb_id = datatree.symbol_table.addEndoLagAuxiliaryVar(symb_id, cur_lag+1, substexpr);
neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr)));
substexpr = datatree.AddVariable(aux_symb_id, -1);
subst_table[orig_expr] = substexpr;
}
else
substexpr = const_cast(it->second);
cur_lag--;
}
return substexpr;
case SymbolType::modelLocalVariable:
value = datatree.getLocalVariable(symb_id);
if (value->maxEndoLag() <= 1)
return const_cast(this);
else
return value->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
default:
return const_cast(this);
}
}
expr_t
VariableNode::substituteExoLead(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
expr_t value;
switch (type)
{
case SymbolType::exogenous:
if (lag <= 0)
return const_cast(this);
else
return createExoLeadAuxiliaryVarForMyself(subst_table, neweqs);
case SymbolType::modelLocalVariable:
value = datatree.getLocalVariable(symb_id);
if (value->maxExoLead() == 0)
return const_cast(this);
else
return value->substituteExoLead(subst_table, neweqs, deterministic_model);
default:
return const_cast(this);
}
}
expr_t
VariableNode::substituteExoLag(subst_table_t &subst_table, vector &neweqs) const
{
VariableNode *substexpr;
expr_t value;
subst_table_t::const_iterator it;
int cur_lag;
switch (type)
{
case SymbolType::exogenous:
if (lag >= 0)
return const_cast(this);
it = subst_table.find(this);
if (it != subst_table.end())
return const_cast(it->second);
substexpr = datatree.AddVariable(symb_id, 0);
cur_lag = -1;
// Each iteration tries to create an auxvar such that auxvar(-1)=curvar(cur_lag)
// At the beginning (resp. end) of each iteration, substexpr is an expression (possibly an auxvar) equivalent to curvar(cur_lag+1) (resp. curvar(cur_lag))
while (cur_lag >= lag)
{
VariableNode *orig_expr = datatree.AddVariable(symb_id, cur_lag);
it = subst_table.find(orig_expr);
if (it == subst_table.end())
{
int aux_symb_id = datatree.symbol_table.addExoLagAuxiliaryVar(symb_id, cur_lag+1, substexpr);
neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), substexpr)));
substexpr = datatree.AddVariable(aux_symb_id, -1);
subst_table[orig_expr] = substexpr;
}
else
substexpr = const_cast(it->second);
cur_lag--;
}
return substexpr;
case SymbolType::modelLocalVariable:
value = datatree.getLocalVariable(symb_id);
if (value->maxExoLag() == 0)
return const_cast(this);
else
return value->substituteExoLag(subst_table, neweqs);
default:
return const_cast(this);
}
}
expr_t
VariableNode::substituteExpectation(subst_table_t &subst_table, vector &neweqs, bool partial_information_model) const
{
return const_cast(this);
}
expr_t
VariableNode::differentiateForwardVars(const vector &subset, subst_table_t &subst_table, vector &neweqs) const
{
expr_t value;
switch (type)
{
case SymbolType::endogenous:
assert(lag <= 1);
if (lag <= 0
|| (subset.size() > 0
&& find(subset.begin(), subset.end(), datatree.symbol_table.getName(symb_id)) == subset.end()))
return const_cast(this);
else
{
auto it = subst_table.find(this);
VariableNode *diffvar;
if (it != subst_table.end())
diffvar = const_cast(it->second);
else
{
int aux_symb_id = datatree.symbol_table.addDiffForwardAuxiliaryVar(symb_id, datatree.AddMinus(datatree.AddVariable(symb_id, 0),
datatree.AddVariable(symb_id, -1)));
neweqs.push_back(dynamic_cast(datatree.AddEqual(datatree.AddVariable(aux_symb_id, 0), datatree.AddMinus(datatree.AddVariable(symb_id, 0),
datatree.AddVariable(symb_id, -1)))));
diffvar = datatree.AddVariable(aux_symb_id, 1);
subst_table[this] = diffvar;
}
return datatree.AddPlus(datatree.AddVariable(symb_id, 0), diffvar);
}
case SymbolType::modelLocalVariable:
value = datatree.getLocalVariable(symb_id);
if (value->maxEndoLead() <= 0)
return const_cast(this);
else
return value->differentiateForwardVars(subset, subst_table, neweqs);
default:
return const_cast(this);
}
}
bool
VariableNode::isNumConstNodeEqualTo(double value) const
{
return false;
}
bool
VariableNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
if (type == type_arg && datatree.symbol_table.getTypeSpecificID(symb_id) == variable_id && lag == lag_arg)
return true;
else
return false;
}
bool
VariableNode::containsPacExpectation(const string &pac_model_name) const
{
return false;
}
bool
VariableNode::containsEndogenous() const
{
if (type == SymbolType::endogenous)
return true;
else
return false;
}
bool
VariableNode::containsExogenous() const
{
return (type == SymbolType::exogenous || type == SymbolType::exogenousDet);
}
expr_t
VariableNode::replaceTrendVar() const
{
if (get_type() == SymbolType::trend)
return datatree.One;
else if (get_type() == SymbolType::logTrend)
return datatree.Zero;
else
return const_cast(this);
}
expr_t
VariableNode::detrend(int symb_id, bool log_trend, expr_t trend) const
{
if (get_symb_id() != symb_id)
return const_cast(this);
if (log_trend)
{
if (get_lag() == 0)
return datatree.AddPlus(const_cast(this), trend);
else
return datatree.AddPlus(const_cast(this), trend->decreaseLeadsLags(-1*get_lag()));
}
else
{
if (get_lag() == 0)
return datatree.AddTimes(const_cast(this), trend);
else
return datatree.AddTimes(const_cast(this), trend->decreaseLeadsLags(-1*get_lag()));
}
}
int
VariableNode::countDiffs() const
{
return 0;
}
expr_t
VariableNode::removeTrendLeadLag(map trend_symbols_map) const
{
if ((get_type() != SymbolType::trend && get_type() != SymbolType::logTrend) || get_lag() == 0)
return const_cast(this);
map::const_iterator it = trend_symbols_map.find(symb_id);
expr_t noTrendLeadLagNode = datatree.AddVariable(it->first);
bool log_trend = get_type() == SymbolType::logTrend;
expr_t trend = it->second;
if (get_lag() > 0)
{
expr_t growthFactorSequence = trend->decreaseLeadsLags(-1);
if (log_trend)
{
for (int i = 1; i < get_lag(); i++)
growthFactorSequence = datatree.AddPlus(growthFactorSequence, trend->decreaseLeadsLags(-1*(i+1)));
return datatree.AddPlus(noTrendLeadLagNode, growthFactorSequence);
}
else
{
for (int i = 1; i < get_lag(); i++)
growthFactorSequence = datatree.AddTimes(growthFactorSequence, trend->decreaseLeadsLags(-1*(i+1)));
return datatree.AddTimes(noTrendLeadLagNode, growthFactorSequence);
}
}
else //get_lag < 0
{
expr_t growthFactorSequence = trend;
if (log_trend)
{
for (int i = 1; i < abs(get_lag()); i++)
growthFactorSequence = datatree.AddPlus(growthFactorSequence, trend->decreaseLeadsLags(i));
return datatree.AddMinus(noTrendLeadLagNode, growthFactorSequence);
}
else
{
for (int i = 1; i < abs(get_lag()); i++)
growthFactorSequence = datatree.AddTimes(growthFactorSequence, trend->decreaseLeadsLags(i));
return datatree.AddDivide(noTrendLeadLagNode, growthFactorSequence);
}
}
}
bool
VariableNode::isInStaticForm() const
{
return lag == 0;
}
bool
VariableNode::isParamTimesEndogExpr() const
{
return false;
}
void
VariableNode::getPacNonOptimizingPart(set, double>>>
¶ms_vars_and_scaling_factor) const
{
if (type != SymbolType::endogenous
&& type != SymbolType::exogenous)
{
cerr << "ERROR VariableNode::getPacNonOptimizingPart: Error in parsing PAC equation"
<< endl;
exit(EXIT_FAILURE);
}
params_vars_and_scaling_factor.emplace(make_pair(-1,
make_pair(make_pair(symb_id, lag),
1.0)));
}
void
VariableNode::getPacOptimizingPart(int lhs_orig_symb_id, pair, vector>> &ec_params_and_vars,
set>> &ar_params_and_vars) const
{
}
void
VariableNode::getPacOptimizingShareAndExprNodes(set &optim_share,
expr_t &optim_part,
expr_t &non_optim_part) const
{
}
void
VariableNode::addParamInfoToPac(pair &lhs_arg, int optim_share_arg, pair, vector>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg, set, double>>> ¶ms_vars_and_scaling_factor_arg)
{
}
void
VariableNode::fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, int pac_max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg)
{
}
bool
VariableNode::isVarModelReferenced(const string &model_info_name) const
{
return false;
}
void
VariableNode::getEndosAndMaxLags(map &model_endos_and_lags) const
{
string varname = datatree.symbol_table.getName(symb_id);
if (type == SymbolType::endogenous)
if (model_endos_and_lags.find(varname) == model_endos_and_lags.end())
model_endos_and_lags[varname] = min(model_endos_and_lags[varname], lag);
else
model_endos_and_lags[varname] = lag;
}
void
VariableNode::fillAutoregressiveRow(int eqn, const vector &lhs, map, expr_t> &AR) const
{
}
UnaryOpNode::UnaryOpNode(DataTree &datatree_arg, int idx_arg, UnaryOpcode op_code_arg, const expr_t arg_arg, int expectation_information_set_arg, int param1_symb_id_arg, int param2_symb_id_arg, string adl_param_name_arg, vector adl_lags_arg) :
ExprNode(datatree_arg, idx_arg),
arg(arg_arg),
expectation_information_set(expectation_information_set_arg),
param1_symb_id(param1_symb_id_arg),
param2_symb_id(param2_symb_id_arg),
op_code(op_code_arg),
adl_param_name(move(adl_param_name_arg)),
adl_lags(move(adl_lags_arg))
{
}
void
UnaryOpNode::prepareForDerivation()
{
if (preparedForDerivation)
return;
preparedForDerivation = true;
arg->prepareForDerivation();
// Non-null derivatives are those of the argument (except for STEADY_STATE)
non_null_derivatives = arg->non_null_derivatives;
if (op_code == UnaryOpcode::steadyState || op_code == UnaryOpcode::steadyStateParamDeriv
|| op_code == UnaryOpcode::steadyStateParam2ndDeriv)
datatree.addAllParamDerivId(non_null_derivatives);
}
expr_t
UnaryOpNode::composeDerivatives(expr_t darg, int deriv_id)
{
expr_t t11, t12, t13, t14;
switch (op_code)
{
case UnaryOpcode::uminus:
return datatree.AddUMinus(darg);
case UnaryOpcode::exp:
return datatree.AddTimes(darg, this);
case UnaryOpcode::log:
return datatree.AddDivide(darg, arg);
case UnaryOpcode::log10:
t11 = datatree.AddExp(datatree.One);
t12 = datatree.AddLog10(t11);
t13 = datatree.AddDivide(darg, arg);
return datatree.AddTimes(t12, t13);
case UnaryOpcode::cos:
t11 = datatree.AddSin(arg);
t12 = datatree.AddUMinus(t11);
return datatree.AddTimes(darg, t12);
case UnaryOpcode::sin:
t11 = datatree.AddCos(arg);
return datatree.AddTimes(darg, t11);
case UnaryOpcode::tan:
t11 = datatree.AddTimes(this, this);
t12 = datatree.AddPlus(t11, datatree.One);
return datatree.AddTimes(darg, t12);
case UnaryOpcode::acos:
t11 = datatree.AddSin(this);
t12 = datatree.AddDivide(darg, t11);
return datatree.AddUMinus(t12);
case UnaryOpcode::asin:
t11 = datatree.AddCos(this);
return datatree.AddDivide(darg, t11);
case UnaryOpcode::atan:
t11 = datatree.AddTimes(arg, arg);
t12 = datatree.AddPlus(datatree.One, t11);
return datatree.AddDivide(darg, t12);
case UnaryOpcode::cosh:
t11 = datatree.AddSinh(arg);
return datatree.AddTimes(darg, t11);
case UnaryOpcode::sinh:
t11 = datatree.AddCosh(arg);
return datatree.AddTimes(darg, t11);
case UnaryOpcode::tanh:
t11 = datatree.AddTimes(this, this);
t12 = datatree.AddMinus(datatree.One, t11);
return datatree.AddTimes(darg, t12);
case UnaryOpcode::acosh:
t11 = datatree.AddSinh(this);
return datatree.AddDivide(darg, t11);
case UnaryOpcode::asinh:
t11 = datatree.AddCosh(this);
return datatree.AddDivide(darg, t11);
case UnaryOpcode::atanh:
t11 = datatree.AddTimes(arg, arg);
t12 = datatree.AddMinus(datatree.One, t11);
return datatree.AddTimes(darg, t12);
case UnaryOpcode::sqrt:
t11 = datatree.AddPlus(this, this);
return datatree.AddDivide(darg, t11);
case UnaryOpcode::abs:
t11 = datatree.AddSign(arg);
return datatree.AddTimes(t11, darg);
case UnaryOpcode::sign:
return datatree.Zero;
case UnaryOpcode::steadyState:
if (datatree.isDynamic())
{
if (datatree.getTypeByDerivID(deriv_id) == SymbolType::parameter)
{
auto *varg = dynamic_cast(arg);
if (varg == nullptr)
{
cerr << "UnaryOpNode::composeDerivatives: STEADY_STATE() should only be used on "
<< "standalone variables (like STEADY_STATE(y)) to be derivable w.r.t. parameters" << endl;
exit(EXIT_FAILURE);
}
if (datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous)
return datatree.AddSteadyStateParamDeriv(arg, datatree.getSymbIDByDerivID(deriv_id));
else
return datatree.Zero;
}
else
return datatree.Zero;
}
else
return darg;
case UnaryOpcode::steadyStateParamDeriv:
assert(datatree.isDynamic());
if (datatree.getTypeByDerivID(deriv_id) == SymbolType::parameter)
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous);
return datatree.AddSteadyStateParam2ndDeriv(arg, param1_symb_id, datatree.getSymbIDByDerivID(deriv_id));
}
else
return datatree.Zero;
case UnaryOpcode::steadyStateParam2ndDeriv:
assert(datatree.isDynamic());
if (datatree.getTypeByDerivID(deriv_id) == SymbolType::parameter)
{
cerr << "3rd derivative of STEADY_STATE node w.r.t. three parameters not implemented" << endl;
exit(EXIT_FAILURE);
}
else
return datatree.Zero;
case UnaryOpcode::expectation:
cerr << "UnaryOpNode::composeDerivatives: not implemented on UnaryOpcode::expectation" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::erf:
// x^2
t11 = datatree.AddPower(arg, datatree.Two);
// exp(x^2)
t12 = datatree.AddExp(t11);
// sqrt(pi)
t11 = datatree.AddSqrt(datatree.Pi);
// sqrt(pi)*exp(x^2)
t13 = datatree.AddTimes(t11, t12);
// 2/(sqrt(pi)*exp(x^2));
t14 = datatree.AddDivide(datatree.Two, t13);
// (2/(sqrt(pi)*exp(x^2)))*dx;
return datatree.AddTimes(t14, darg);
case UnaryOpcode::diff:
cerr << "UnaryOpNode::composeDerivatives: not implemented on UnaryOpcode::diff" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::adl:
cerr << "UnaryOpNode::composeDerivatives: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
expr_t
UnaryOpNode::computeDerivative(int deriv_id)
{
expr_t darg = arg->getDerivative(deriv_id);
return composeDerivatives(darg, deriv_id);
}
int
UnaryOpNode::cost(const map &temp_terms_map, bool is_matlab) const
{
// For a temporary term, the cost is null
for (const auto & it : temp_terms_map)
if (it.second.find(const_cast(this)) != it.second.end())
return 0;
return cost(arg->cost(temp_terms_map, is_matlab), is_matlab);
}
int
UnaryOpNode::cost(const temporary_terms_t &temporary_terms, bool is_matlab) const
{
// For a temporary term, the cost is null
if (temporary_terms.find(const_cast(this)) != temporary_terms.end())
return 0;
return cost(arg->cost(temporary_terms, is_matlab), is_matlab);
}
int
UnaryOpNode::cost(int cost, bool is_matlab) const
{
if (is_matlab)
// Cost for Matlab files
switch (op_code)
{
case UnaryOpcode::uminus:
case UnaryOpcode::sign:
return cost + 70;
case UnaryOpcode::exp:
return cost + 160;
case UnaryOpcode::log:
return cost + 300;
case UnaryOpcode::log10:
case UnaryOpcode::erf:
return cost + 16000;
case UnaryOpcode::cos:
case UnaryOpcode::sin:
case UnaryOpcode::cosh:
return cost + 210;
case UnaryOpcode::tan:
return cost + 230;
case UnaryOpcode::acos:
return cost + 300;
case UnaryOpcode::asin:
return cost + 310;
case UnaryOpcode::atan:
return cost + 140;
case UnaryOpcode::sinh:
return cost + 240;
case UnaryOpcode::tanh:
return cost + 190;
case UnaryOpcode::acosh:
return cost + 770;
case UnaryOpcode::asinh:
return cost + 460;
case UnaryOpcode::atanh:
return cost + 350;
case UnaryOpcode::sqrt:
case UnaryOpcode::abs:
return cost + 570;
case UnaryOpcode::steadyState:
case UnaryOpcode::steadyStateParamDeriv:
case UnaryOpcode::steadyStateParam2ndDeriv:
case UnaryOpcode::expectation:
return cost;
case UnaryOpcode::diff:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::diff" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::adl:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
}
else
// Cost for C files
switch (op_code)
{
case UnaryOpcode::uminus:
case UnaryOpcode::sign:
return cost + 3;
case UnaryOpcode::exp:
case UnaryOpcode::acosh:
return cost + 210;
case UnaryOpcode::log:
return cost + 137;
case UnaryOpcode::log10:
return cost + 139;
case UnaryOpcode::cos:
case UnaryOpcode::sin:
return cost + 160;
case UnaryOpcode::tan:
return cost + 170;
case UnaryOpcode::acos:
case UnaryOpcode::atan:
return cost + 190;
case UnaryOpcode::asin:
return cost + 180;
case UnaryOpcode::cosh:
case UnaryOpcode::sinh:
case UnaryOpcode::tanh:
case UnaryOpcode::erf:
return cost + 240;
case UnaryOpcode::asinh:
return cost + 220;
case UnaryOpcode::atanh:
return cost + 150;
case UnaryOpcode::sqrt:
case UnaryOpcode::abs:
return cost + 90;
case UnaryOpcode::steadyState:
case UnaryOpcode::steadyStateParamDeriv:
case UnaryOpcode::steadyStateParam2ndDeriv:
case UnaryOpcode::expectation:
return cost;
case UnaryOpcode::diff:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::diff" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::adl:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
}
exit(EXIT_FAILURE);
}
void
UnaryOpNode::computeTemporaryTerms(map> &reference_count,
map &temp_terms_map,
bool is_matlab, NodeTreeReference tr) const
{
expr_t this2 = const_cast(this);
auto it = reference_count.find(this2);
if (it == reference_count.end())
{
reference_count[this2] = { 1, tr };
arg->computeTemporaryTerms(reference_count, temp_terms_map, is_matlab, tr);
}
else
{
reference_count[this2] = { it->second.first + 1, it->second.second };
if (reference_count[this2].first * cost(temp_terms_map, is_matlab) > min_cost(is_matlab))
temp_terms_map[reference_count[this2].second].insert(this2);
}
}
void
UnaryOpNode::computeTemporaryTerms(map &reference_count,
temporary_terms_t &temporary_terms,
map> &first_occurence,
int Curr_block,
vector< vector> &v_temporary_terms,
int equation) const
{
expr_t this2 = const_cast(this);
auto it = reference_count.find(this2);
if (it == reference_count.end())
{
reference_count[this2] = 1;
first_occurence[this2] = { Curr_block, equation };
arg->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, v_temporary_terms, equation);
}
else
{
reference_count[this2]++;
if (reference_count[this2] * cost(temporary_terms, false) > min_cost_c)
{
temporary_terms.insert(this2);
v_temporary_terms[first_occurence[this2].first][first_occurence[this2].second].insert(this2);
}
}
}
void
UnaryOpNode::collectTemporary_terms(const temporary_terms_t &temporary_terms, temporary_terms_inuse_t &temporary_terms_inuse, int Curr_Block) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
temporary_terms_inuse.insert(idx);
else
arg->collectTemporary_terms(temporary_terms, temporary_terms_inuse, Curr_Block);
}
bool
UnaryOpNode::containsExternalFunction() const
{
return arg->containsExternalFunction();
}
void
UnaryOpNode::writeJsonOutput(ostream &output,
const temporary_terms_t &temporary_terms,
const deriv_node_temp_terms_t &tef_terms,
const bool isdynamic) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
{
output << "T" << idx;
return;
}
// Always put parenthesis around uminus nodes
if (op_code == UnaryOpcode::uminus)
output << "(";
switch (op_code)
{
case UnaryOpcode::uminus:
output << "-";
break;
case UnaryOpcode::exp:
output << "exp";
break;
case UnaryOpcode::log:
output << "log";
break;
case UnaryOpcode::log10:
output << "log10";
break;
case UnaryOpcode::cos:
output << "cos";
break;
case UnaryOpcode::sin:
output << "sin";
break;
case UnaryOpcode::tan:
output << "tan";
break;
case UnaryOpcode::acos:
output << "acos";
break;
case UnaryOpcode::asin:
output << "asin";
break;
case UnaryOpcode::atan:
output << "atan";
break;
case UnaryOpcode::cosh:
output << "cosh";
break;
case UnaryOpcode::sinh:
output << "sinh";
break;
case UnaryOpcode::tanh:
output << "tanh";
break;
case UnaryOpcode::acosh:
output << "acosh";
break;
case UnaryOpcode::asinh:
output << "asinh";
break;
case UnaryOpcode::atanh:
output << "atanh";
break;
case UnaryOpcode::sqrt:
output << "sqrt";
break;
case UnaryOpcode::abs:
output << "abs";
break;
case UnaryOpcode::sign:
output << "sign";
break;
case UnaryOpcode::diff:
output << "diff";
break;
case UnaryOpcode::adl:
output << "adl(";
arg->writeJsonOutput(output, temporary_terms, tef_terms);
output << ", '" << adl_param_name << "', [";
for (auto it = adl_lags.begin(); it != adl_lags.end(); it++)
{
if (it != adl_lags.begin())
output << ", ";
output << *it;
}
output << "])";
return;
case UnaryOpcode::steadyState:
output << "(";
arg->writeJsonOutput(output, temporary_terms, tef_terms, isdynamic);
output << ")";
return;
case UnaryOpcode::steadyStateParamDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == SymbolType::parameter);
int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")";
}
return;
case UnaryOpcode::steadyStateParam2ndDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == SymbolType::parameter);
assert(datatree.symbol_table.getType(param2_symb_id) == SymbolType::parameter);
int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
int tsid_param1 = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
int tsid_param2 = datatree.symbol_table.getTypeSpecificID(param2_symb_id);
output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1
<< "," << tsid_param2+1 << ")";
}
return;
case UnaryOpcode::expectation:
output << "EXPECTATION(" << expectation_information_set << ")";
break;
case UnaryOpcode::erf:
output << "erf";
break;
}
bool close_parenthesis = false;
/* Enclose argument with parentheses if:
- current opcode is not uminus, or
- current opcode is uminus and argument has lowest precedence
*/
if (op_code != UnaryOpcode::uminus
|| (op_code == UnaryOpcode::uminus
&& arg->precedenceJson(temporary_terms) < precedenceJson(temporary_terms)))
{
output << "(";
close_parenthesis = true;
}
// Write argument
arg->writeJsonOutput(output, temporary_terms, tef_terms, isdynamic);
if (close_parenthesis)
output << ")";
// Close parenthesis for uminus
if (op_code == UnaryOpcode::uminus)
output << ")";
}
void
UnaryOpNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs,
const deriv_node_temp_terms_t &tef_terms) const
{
if (checkIfTemporaryTermThenWrite(output, output_type, temporary_terms, temporary_terms_idxs))
return;
// Always put parenthesis around uminus nodes
if (op_code == UnaryOpcode::uminus)
output << LEFT_PAR(output_type);
switch (op_code)
{
case UnaryOpcode::uminus:
output << "-";
break;
case UnaryOpcode::exp:
output << "exp";
break;
case UnaryOpcode::log:
if (isLatexOutput(output_type))
output << "\\log";
else
output << "log";
break;
case UnaryOpcode::log10:
if (isLatexOutput(output_type))
output << "\\log_{10}";
else
output << "log10";
break;
case UnaryOpcode::cos:
output << "cos";
break;
case UnaryOpcode::sin:
output << "sin";
break;
case UnaryOpcode::tan:
output << "tan";
break;
case UnaryOpcode::acos:
output << "acos";
break;
case UnaryOpcode::asin:
output << "asin";
break;
case UnaryOpcode::atan:
output << "atan";
break;
case UnaryOpcode::cosh:
output << "cosh";
break;
case UnaryOpcode::sinh:
output << "sinh";
break;
case UnaryOpcode::tanh:
output << "tanh";
break;
case UnaryOpcode::acosh:
output << "acosh";
break;
case UnaryOpcode::asinh:
output << "asinh";
break;
case UnaryOpcode::atanh:
output << "atanh";
break;
case UnaryOpcode::sqrt:
output << "sqrt";
break;
case UnaryOpcode::abs:
output << "abs";
break;
case UnaryOpcode::sign:
if (output_type == ExprNodeOutputType::CDynamicModel || output_type == ExprNodeOutputType::CStaticModel)
output << "copysign";
else
output << "sign";
break;
case UnaryOpcode::steadyState:
ExprNodeOutputType new_output_type;
switch (output_type)
{
case ExprNodeOutputType::matlabDynamicModel:
new_output_type = ExprNodeOutputType::matlabDynamicSteadyStateOperator;
break;
case ExprNodeOutputType::latexDynamicModel:
new_output_type = ExprNodeOutputType::latexDynamicSteadyStateOperator;
break;
case ExprNodeOutputType::CDynamicModel:
new_output_type = ExprNodeOutputType::CDynamicSteadyStateOperator;
break;
case ExprNodeOutputType::juliaDynamicModel:
new_output_type = ExprNodeOutputType::juliaDynamicSteadyStateOperator;
break;
case ExprNodeOutputType::matlabDynamicModelSparse:
new_output_type = ExprNodeOutputType::matlabDynamicSparseSteadyStateOperator;
break;
default:
new_output_type = output_type;
break;
}
output << "(";
arg->writeOutput(output, new_output_type, temporary_terms, temporary_terms_idxs, tef_terms);
output << ")";
return;
case UnaryOpcode::steadyStateParamDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == SymbolType::parameter);
int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
assert(isMatlabOutput(output_type));
output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")";
}
return;
case UnaryOpcode::steadyStateParam2ndDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == SymbolType::endogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == SymbolType::parameter);
assert(datatree.symbol_table.getType(param2_symb_id) == SymbolType::parameter);
int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
int tsid_param1 = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
int tsid_param2 = datatree.symbol_table.getTypeSpecificID(param2_symb_id);
assert(isMatlabOutput(output_type));
output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1
<< "," << tsid_param2+1 << ")";
}
return;
case UnaryOpcode::expectation:
if (!isLatexOutput(output_type))
{
cerr << "UnaryOpNode::writeOutput: not implemented on UnaryOpcode::expectation" << endl;
exit(EXIT_FAILURE);
}
output << "\\mathbb{E}_{t";
if (expectation_information_set != 0)
{
if (expectation_information_set > 0)
output << "+";
output << expectation_information_set;
}
output << "}";
break;
case UnaryOpcode::erf:
output << "erf";
break;
case UnaryOpcode::diff:
output << "diff";
break;
case UnaryOpcode::adl:
output << "adl";
break;
}
bool close_parenthesis = false;
/* Enclose argument with parentheses if:
- current opcode is not uminus, or
- current opcode is uminus and argument has lowest precedence
*/
if (op_code != UnaryOpcode::uminus
|| (op_code == UnaryOpcode::uminus
&& arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms)))
{
output << LEFT_PAR(output_type);
if (op_code == UnaryOpcode::sign && (output_type == ExprNodeOutputType::CDynamicModel || output_type == ExprNodeOutputType::CStaticModel))
output << "1.0,";
close_parenthesis = true;
}
// Write argument
arg->writeOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
if (close_parenthesis)
output << RIGHT_PAR(output_type);
// Close parenthesis for uminus
if (op_code == UnaryOpcode::uminus)
output << RIGHT_PAR(output_type);
}
void
UnaryOpNode::writeExternalFunctionOutput(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms,
const temporary_terms_idxs_t &temporary_terms_idxs,
deriv_node_temp_terms_t &tef_terms) const
{
arg->writeExternalFunctionOutput(output, output_type, temporary_terms, temporary_terms_idxs, tef_terms);
}
void
UnaryOpNode::writeJsonExternalFunctionOutput(vector &efout,
const temporary_terms_t &temporary_terms,
deriv_node_temp_terms_t &tef_terms,
const bool isdynamic) const
{
arg->writeJsonExternalFunctionOutput(efout, temporary_terms, tef_terms, isdynamic);
}
void
UnaryOpNode::compileExternalFunctionOutput(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
deriv_node_temp_terms_t &tef_terms) const
{
arg->compileExternalFunctionOutput(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx,
dynamic, steady_dynamic, tef_terms);
}
double
UnaryOpNode::eval_opcode(UnaryOpcode op_code, double v) noexcept(false)
{
switch (op_code)
{
case UnaryOpcode::uminus:
return (-v);
case UnaryOpcode::exp:
return (exp(v));
case UnaryOpcode::log:
return (log(v));
case UnaryOpcode::log10:
return (log10(v));
case UnaryOpcode::cos:
return (cos(v));
case UnaryOpcode::sin:
return (sin(v));
case UnaryOpcode::tan:
return (tan(v));
case UnaryOpcode::acos:
return (acos(v));
case UnaryOpcode::asin:
return (asin(v));
case UnaryOpcode::atan:
return (atan(v));
case UnaryOpcode::cosh:
return (cosh(v));
case UnaryOpcode::sinh:
return (sinh(v));
case UnaryOpcode::tanh:
return (tanh(v));
case UnaryOpcode::acosh:
return (acosh(v));
case UnaryOpcode::asinh:
return (asinh(v));
case UnaryOpcode::atanh:
return (atanh(v));
case UnaryOpcode::sqrt:
return (sqrt(v));
case UnaryOpcode::abs:
return (abs(v));
case UnaryOpcode::sign:
return (v > 0) ? 1 : ((v < 0) ? -1 : 0);
case UnaryOpcode::steadyState:
return (v);
case UnaryOpcode::steadyStateParamDeriv:
case UnaryOpcode::steadyStateParam2ndDeriv:
case UnaryOpcode::expectation:
case UnaryOpcode::erf:
return (erf(v));
case UnaryOpcode::diff:
cerr << "UnaryOpNode::eval_opcode: not implemented on UnaryOpcode::diff" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::adl:
cerr << "UnaryOpNode::eval_opcode: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
double
UnaryOpNode::eval(const eval_context_t &eval_context) const noexcept(false)
{
double v = arg->eval(eval_context);
return eval_opcode(op_code, v);
}
void
UnaryOpNode::compile(ostream &CompileCode, unsigned int &instruction_number,
bool lhs_rhs, const temporary_terms_t &temporary_terms,
const map_idx_t &map_idx, bool dynamic, bool steady_dynamic,
const deriv_node_temp_terms_t &tef_terms) const
{
auto it = temporary_terms.find(const_cast(this));
if (it != temporary_terms.end())
{
if (dynamic)
{
auto ii = map_idx.find(idx);
FLDT_ fldt(ii->second);
fldt.write(CompileCode, instruction_number);
}
else
{
auto ii = map_idx.find(idx);
FLDST_ fldst(ii->second);
fldst.write(CompileCode, instruction_number);
}
return;
}
if (op_code == UnaryOpcode::steadyState)
arg->compile(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx, dynamic, true, tef_terms);
else
{
arg->compile(CompileCode, instruction_number, lhs_rhs, temporary_terms, map_idx, dynamic, steady_dynamic, tef_terms);
FUNARY_ funary{static_cast(op_code)};
funary.write(CompileCode, instruction_number);
}
}
void
UnaryOpNode::collectVARLHSVariable(set &result) const
{
if (op_code == UnaryOpcode::diff)
result.insert(const_cast(this));
else
arg->collectVARLHSVariable(result);
}
void
UnaryOpNode::collectDynamicVariables(SymbolType type_arg, set> &result) const
{
arg->collectDynamicVariables(type_arg, result);
}
pair
UnaryOpNode::normalizeEquation(int var_endo, vector>> &List_of_Op_RHS) const
{
pair res = arg->normalizeEquation(var_endo, List_of_Op_RHS);
int is_endogenous_present = res.first;
expr_t New_expr_t = res.second;
if (is_endogenous_present == 2) /* The equation could not be normalized and the process is given-up*/
return { 2, nullptr };
else if (is_endogenous_present) /* The argument of the function contains the current values of
the endogenous variable associated to the equation.
In order to normalized, we have to apply the invert function to the RHS.*/
{
switch (op_code)
{
case UnaryOpcode::uminus:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::uminus), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::exp:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::log), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::log:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::exp), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::log10:
List_of_Op_RHS.emplace_back(static_cast(BinaryOpcode::power), make_pair(nullptr, datatree.AddNonNegativeConstant("10")));
return { 1, nullptr };
case UnaryOpcode::cos:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::acos), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::sin:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::asin), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::tan:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::atan), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::acos:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::cos), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::asin:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::sin), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::atan:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::tan), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::cosh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::acosh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::sinh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::asinh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::tanh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::atanh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::acosh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::cosh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::asinh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::sinh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::atanh:
List_of_Op_RHS.emplace_back(static_cast(UnaryOpcode::tanh), make_pair(nullptr, nullptr));
return { 1, nullptr };
case UnaryOpcode::sqrt:
List_of_Op_RHS.emplace_back(static_cast(BinaryOpcode::power), make_pair(nullptr, datatree.Two));
return { 1, nullptr };
case UnaryOpcode::abs:
return { 2, nullptr };
case UnaryOpcode::sign:
return { 2, nullptr };
case UnaryOpcode::steadyState:
return { 2, nullptr };
case UnaryOpcode::erf:
return { 2, nullptr };
default:
cerr << "Unary operator not handled during the normalization process" << endl;
return { 2, nullptr }; // Could not be normalized
}
}
else
{ /* If the argument of the function do not contain the current values of the endogenous variable
related to the equation, the function with its argument is stored in the RHS*/
switch (op_code)
{
case UnaryOpcode::uminus:
return { 0, datatree.AddUMinus(New_expr_t) };
case UnaryOpcode::exp:
return { 0, datatree.AddExp(New_expr_t) };
case UnaryOpcode::log:
return { 0, datatree.AddLog(New_expr_t) };
case UnaryOpcode::log10:
return { 0, datatree.AddLog10(New_expr_t) };
case UnaryOpcode::cos:
return { 0, datatree.AddCos(New_expr_t) };
case UnaryOpcode::sin:
return { 0, datatree.AddSin(New_expr_t) };
case UnaryOpcode::tan:
return { 0, datatree.AddTan(New_expr_t) };
case UnaryOpcode::acos:
return { 0, datatree.AddAcos(New_expr_t) };
case UnaryOpcode::asin:
return { 0, datatree.AddAsin(New_expr_t) };
case UnaryOpcode::atan:
return { 0, datatree.AddAtan(New_expr_t) };
case UnaryOpcode::cosh:
return { 0, datatree.AddCosh(New_expr_t) };
case UnaryOpcode::sinh:
return { 0, datatree.AddSinh(New_expr_t) };
case UnaryOpcode::tanh:
return { 0, datatree.AddTanh(New_expr_t) };
case UnaryOpcode::acosh:
return { 0, datatree.AddAcosh(New_expr_t) };
case UnaryOpcode::asinh:
return { 0, datatree.AddAsinh(New_expr_t) };
case UnaryOpcode::atanh:
return { 0, datatree.AddAtanh(New_expr_t) };
case UnaryOpcode::sqrt:
return { 0, datatree.AddSqrt(New_expr_t) };
case UnaryOpcode::abs:
return { 0, datatree.AddAbs(New_expr_t) };
case UnaryOpcode::sign:
return { 0, datatree.AddSign(New_expr_t) };
case UnaryOpcode::steadyState:
return { 0, datatree.AddSteadyState(New_expr_t) };
case UnaryOpcode::erf:
return { 0, datatree.AddErf(New_expr_t) };
default:
cerr << "Unary operator not handled during the normalization process" << endl;
return { 2, nullptr }; // Could not be normalized
}
}
cerr << "UnaryOpNode::normalizeEquation: impossible case" << endl;
exit(EXIT_FAILURE);
}
expr_t
UnaryOpNode::getChainRuleDerivative(int deriv_id, const map &recursive_variables)
{
expr_t darg = arg->getChainRuleDerivative(deriv_id, recursive_variables);
return composeDerivatives(darg, deriv_id);
}
expr_t
UnaryOpNode::buildSimilarUnaryOpNode(expr_t alt_arg, DataTree &alt_datatree) const
{
switch (op_code)
{
case UnaryOpcode::uminus:
return alt_datatree.AddUMinus(alt_arg);
case UnaryOpcode::exp:
return alt_datatree.AddExp(alt_arg);
case UnaryOpcode::log:
return alt_datatree.AddLog(alt_arg);
case UnaryOpcode::log10:
return alt_datatree.AddLog10(alt_arg);
case UnaryOpcode::cos:
return alt_datatree.AddCos(alt_arg);
case UnaryOpcode::sin:
return alt_datatree.AddSin(alt_arg);
case UnaryOpcode::tan:
return alt_datatree.AddTan(alt_arg);
case UnaryOpcode::acos:
return alt_datatree.AddAcos(alt_arg);
case UnaryOpcode::asin:
return alt_datatree.AddAsin(alt_arg);
case UnaryOpcode::atan:
return alt_datatree.AddAtan(alt_arg);
case UnaryOpcode::cosh:
return alt_datatree.AddCosh(alt_arg);
case UnaryOpcode::sinh:
return alt_datatree.AddSinh(alt_arg);
case UnaryOpcode::tanh:
return alt_datatree.AddTanh(alt_arg);
case UnaryOpcode::acosh:
return alt_datatree.AddAcosh(alt_arg);
case UnaryOpcode::asinh:
return alt_datatree.AddAsinh(alt_arg);
case UnaryOpcode::atanh:
return alt_datatree.AddAtanh(alt_arg);
case UnaryOpcode::sqrt:
return alt_datatree.AddSqrt(alt_arg);
case UnaryOpcode::abs:
return alt_datatree.AddAbs(alt_arg);
case UnaryOpcode::sign:
return alt_datatree.AddSign(alt_arg);
case UnaryOpcode::steadyState:
return alt_datatree.AddSteadyState(alt_arg);
case UnaryOpcode::steadyStateParamDeriv:
cerr << "UnaryOpNode::buildSimilarUnaryOpNode: UnaryOpcode::steadyStateParamDeriv can't be translated" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::steadyStateParam2ndDeriv:
cerr << "UnaryOpNode::buildSimilarUnaryOpNode: UnaryOpcode::steadyStateParam2ndDeriv can't be translated" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::expectation:
return alt_datatree.AddExpectation(expectation_information_set, alt_arg);
case UnaryOpcode::erf:
return alt_datatree.AddErf(alt_arg);
case UnaryOpcode::diff:
return alt_datatree.AddDiff(alt_arg);
case UnaryOpcode::adl:
return alt_datatree.AddAdl(alt_arg, adl_param_name, adl_lags);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
expr_t
UnaryOpNode::toStatic(DataTree &static_datatree) const
{
expr_t sarg = arg->toStatic(static_datatree);
return buildSimilarUnaryOpNode(sarg, static_datatree);
}
void
UnaryOpNode::computeXrefs(EquationInfo &ei) const
{
arg->computeXrefs(ei);
}
expr_t
UnaryOpNode::cloneDynamic(DataTree &dynamic_datatree) const
{
expr_t substarg = arg->cloneDynamic(dynamic_datatree);
return buildSimilarUnaryOpNode(substarg, dynamic_datatree);
}
int
UnaryOpNode::maxEndoLead() const
{
return arg->maxEndoLead();
}
int
UnaryOpNode::maxExoLead() const
{
return arg->maxExoLead();
}
int
UnaryOpNode::maxEndoLag() const
{
return arg->maxEndoLag();
}
int
UnaryOpNode::maxExoLag() const
{
return arg->maxExoLag();
}
int
UnaryOpNode::maxLead() const
{
return arg->maxLead();
}
int
UnaryOpNode::maxLag() const
{
if (op_code == UnaryOpcode::diff)
return arg->maxLag() + 1;
return arg->maxLag();
}
expr_t
UnaryOpNode::undiff() const
{
if (op_code == UnaryOpcode::diff)
return arg;
return arg->undiff();
}
int
UnaryOpNode::VarMaxLag(DataTree &static_datatree, set &static_lhs) const
{
auto it = static_lhs.find(this->toStatic(static_datatree));
if (it == static_lhs.end())
return 0;
return arg->maxLag() - arg->countDiffs();
}
int
UnaryOpNode::VarMinLag() const
{
return arg->VarMinLag();
}
int
UnaryOpNode::PacMaxLag(int lhs_symb_id) const
{
//This will never be an UnaryOpcode::diff node
return arg->PacMaxLag(lhs_symb_id);
}
expr_t
UnaryOpNode::substituteAdl() const
{
if (op_code != UnaryOpcode::adl)
{
expr_t argsubst = arg->substituteAdl();
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t arg1subst = arg->substituteAdl();
expr_t retval = nullptr;
ostringstream inttostr;
for (auto it = adl_lags.begin(); it != adl_lags.end(); it++)
if (it == adl_lags.begin())
{
inttostr << *it;
retval = datatree.AddTimes(datatree.AddVariable(datatree.symbol_table.getID(adl_param_name + "_lag_" + inttostr.str()), 0),
arg1subst->decreaseLeadsLags(*it));
}
else
{
inttostr.clear();
inttostr.str("");
inttostr << *it;
retval = datatree.AddPlus(retval,
datatree.AddTimes(datatree.AddVariable(datatree.symbol_table.getID(adl_param_name + "_lag_"
+ inttostr.str()), 0),
arg1subst->decreaseLeadsLags(*it)));
}
return retval;
}
expr_t
UnaryOpNode::substituteVarExpectation(const map &subst_table) const
{
expr_t argsubst = arg->substituteVarExpectation(subst_table);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
int
UnaryOpNode::countDiffs() const
{
if (op_code == UnaryOpcode::diff)
return arg->countDiffs() + 1;
return arg->countDiffs();
}
bool
UnaryOpNode::createAuxVarForUnaryOpNode() const
{
switch (op_code)
{
case UnaryOpcode::exp:
case UnaryOpcode::log:
case UnaryOpcode::log10:
case UnaryOpcode::cos:
case UnaryOpcode::sin:
case UnaryOpcode::tan:
case UnaryOpcode::acos:
case UnaryOpcode::asin:
case UnaryOpcode::atan:
case UnaryOpcode::cosh:
case UnaryOpcode::sinh:
case UnaryOpcode::tanh:
case UnaryOpcode::acosh:
case UnaryOpcode::asinh:
case UnaryOpcode::atanh:
case UnaryOpcode::sqrt:
case UnaryOpcode::abs:
case UnaryOpcode::sign:
case UnaryOpcode::erf:
return true;
default:
return false;
}
}
void
UnaryOpNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
arg->findUnaryOpNodesForAuxVarCreation(static_datatree, nodes);
if (!this->createAuxVarForUnaryOpNode())
return;
expr_t sthis = this->toStatic(static_datatree);
int arg_max_lag = -arg->maxLag();
// TODO: implement recursive expression comparison, ensuring that the difference in the lags is constant across nodes
auto it = nodes.find(sthis);
if (it != nodes.end())
{
for (map::const_iterator it1 = it->second.begin();
it1 != it->second.end(); it1++)
if (arg == it1->second)
return;
it->second[arg_max_lag] = const_cast(this);
}
else
nodes[sthis][arg_max_lag] = const_cast(this);
}
void
UnaryOpNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
arg->findDiffNodes(static_datatree, diff_table);
if (op_code != UnaryOpcode::diff)
return;
expr_t sthis = this->toStatic(static_datatree);
int arg_max_lag = -arg->maxLag();
// TODO: implement recursive expression comparison, ensuring that the difference in the lags is constant across nodes
auto it = diff_table.find(sthis);
if (it != diff_table.end())
{
for (map::const_iterator it1 = it->second.begin();
it1 != it->second.end(); it1++)
if (arg == it1->second)
return;
it->second[arg_max_lag] = const_cast(this);
}
else
diff_table[sthis][arg_max_lag] = const_cast(this);
}
int
UnaryOpNode::findTrendVariable(int lhs_symb_id) const
{
return arg->findTrendVariable(lhs_symb_id);
}
expr_t
UnaryOpNode::substituteDiff(DataTree &static_datatree, diff_table_t &diff_table, subst_table_t &subst_table,
vector &neweqs) const
{
expr_t argsubst = arg->substituteDiff(static_datatree, diff_table, subst_table, neweqs);
if (op_code != UnaryOpcode::diff)
return buildSimilarUnaryOpNode(argsubst, datatree);
subst_table_t::const_iterator sit = subst_table.find(this);
if (sit != subst_table.end())
return const_cast(sit->second);
expr_t sthis = dynamic_cast(this->toStatic(static_datatree));
auto it = diff_table.find(sthis);
int symb_id;
if (it == diff_table.end() || it->second[-arg->maxLag()] != this)
{
// diff does not appear in VAR equations
// so simply create aux var and return
// Once the comparison of expression nodes works, come back and remove this part, folding into the next loop.
symb_id = datatree.symbol_table.addDiffAuxiliaryVar(argsubst->idx, argsubst);
VariableNode *aux_var = datatree.AddVariable(symb_id, 0);
neweqs.push_back(dynamic_cast(datatree.AddEqual(aux_var,
datatree.AddMinus(argsubst,
argsubst->decreaseLeadsLags(1)))));
subst_table[this] = dynamic_cast(aux_var);
return const_cast(subst_table[this]);
}
int last_arg_max_lag = 0;
VariableNode *last_aux_var = nullptr;
for (auto rit = it->second.rbegin();
rit != it->second.rend(); rit++)
{
expr_t argsubst = dynamic_cast(rit->second)->
get_arg()->substituteDiff(static_datatree, diff_table, subst_table, neweqs);
auto *vn = dynamic_cast(argsubst);
if (rit == it->second.rbegin())
{
if (vn != nullptr)
symb_id = datatree.symbol_table.addDiffAuxiliaryVar(argsubst->idx, argsubst, vn->get_symb_id(), vn->get_lag());
else
symb_id = datatree.symbol_table.addDiffAuxiliaryVar(argsubst->idx, argsubst);
// make originating aux var & equation
last_arg_max_lag = rit->first;
last_aux_var = datatree.AddVariable(symb_id, 0);
//ORIG_AUX_DIFF = argsubst - argsubst(-1)
neweqs.push_back(dynamic_cast(datatree.AddEqual(last_aux_var,
datatree.AddMinus(argsubst,
argsubst->decreaseLeadsLags(1)))));
subst_table[rit->second] = dynamic_cast(last_aux_var);
}
else
{
// just add equation of form: AUX_DIFF = LAST_AUX_VAR(-1)
VariableNode *new_aux_var = nullptr;
for (int i = last_arg_max_lag; i > rit->first; i--)
{
if (i == last_arg_max_lag)
symb_id = datatree.symbol_table.addDiffLagAuxiliaryVar(argsubst->idx, argsubst,
last_aux_var->get_symb_id(), last_aux_var->get_lag());
else
symb_id = datatree.symbol_table.addDiffLagAuxiliaryVar(new_aux_var->idx, new_aux_var,
last_aux_var->get_symb_id(), last_aux_var->get_lag());
new_aux_var = datatree.AddVariable(symb_id, 0);
neweqs.push_back(dynamic_cast(datatree.AddEqual(new_aux_var,
last_aux_var->decreaseLeadsLags(1))));
last_aux_var = new_aux_var;
}
subst_table[rit->second] = dynamic_cast(new_aux_var);
last_arg_max_lag = rit->first;
}
}
return const_cast(subst_table[this]);
}
expr_t
UnaryOpNode::substituteUnaryOpNodes(DataTree &static_datatree, diff_table_t &nodes, subst_table_t &subst_table, vector