/*
* 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) : datatree(datatree_arg), preparedForDerivation(false)
{
// Add myself to datatree
datatree.node_list.push_back(this);
// Set my index and increment counter
idx = datatree.node_counter++;
}
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 == oMatlabDynamicModelSparse)
output << "T" << idx << "(it_)";
else
if (output_type == oMatlabStaticModelSparse || IS_C(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(eEndogenous, 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(eExogenous, 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, oMatlabOutsideModel, {}, {});
}
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 id_arg) :
ExprNode(datatree_arg),
id(id_arg)
{
// Add myself to the num const map
datatree.num_const_node_map[id] = this;
}
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(vector &lhs) 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);
}
void
NumConstNode::findDiffNodes(DataTree &static_datatree, diff_table_t &diff_table) const
{
}
void
NumConstNode::findUnaryOpNodesForAuxVarCreation(DataTree &static_datatree, diff_table_t &nodes) const
{
}
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
{
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;
}
void
NumConstNode::setVarExpectationIndex(map> &var_model_info)
{
}
void
NumConstNode::walkPacParameters(bool &pac_encountered, pair &lhs, set>> &ec_params_and_vars, set>> &ar_params_and_vars) const
{
}
void
NumConstNode::addParamInfoToPac(pair &lhs_arg, set>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg)
{
}
void
NumConstNode::fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int 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);
}
VariableNode::VariableNode(DataTree &datatree_arg, int symb_id_arg, int lag_arg) :
ExprNode(datatree_arg),
symb_id(symb_id_arg),
type(datatree.symbol_table.getType(symb_id_arg)),
lag(lag_arg)
{
// Add myself to the variable map
datatree.variable_node_map[{ symb_id, lag }] = this;
// It makes sense to allow a lead/lag on parameters: during steady state calibration, endogenous and parameters can be swapped
assert(type != eExternalFunction
&& (lag == 0 || (type != eModelLocalVariable && type != eModFileLocalVariable)));
}
void
VariableNode::prepareForDerivation()
{
if (preparedForDerivation)
return;
preparedForDerivation = true;
// Fill in non_null_derivatives
switch (type)
{
case eEndogenous:
case eExogenous:
case eExogenousDet:
case eParameter:
case eTrend:
case eLogTrend:
// 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 eModelLocalVariable:
datatree.local_variables_table[symb_id]->prepareForDerivation();
// Non null derivatives are those of the value of the local parameter
non_null_derivatives = datatree.local_variables_table[symb_id]->non_null_derivatives;
break;
case eModFileLocalVariable:
case eStatementDeclaredVariable:
case eUnusedEndogenous:
// Such a variable is never derived
break;
case eExternalFunction:
case eEndogenousVAR:
cerr << "VariableNode::prepareForDerivation: impossible case" << endl;
exit(EXIT_FAILURE);
}
}
expr_t
VariableNode::computeDerivative(int deriv_id)
{
switch (type)
{
case eEndogenous:
case eExogenous:
case eExogenousDet:
case eParameter:
case eTrend:
case eLogTrend:
if (deriv_id == datatree.getDerivID(symb_id, lag))
return datatree.One;
else
return datatree.Zero;
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->getDerivative(deriv_id);
case eModFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case eStatementDeclaredVariable:
cerr << "eStatementDeclaredVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case eUnusedEndogenous:
cerr << "eUnusedEndogenous is not derivable" << endl;
exit(EXIT_FAILURE);
case eExternalFunction:
case eEndogenousVAR:
cerr << "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 == eModelLocalVariable)
datatree.local_variables_table[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 (IS_LATEX(output_type))
{
if (output_type == oLatexDynamicSteadyStateOperator)
output << "\\bar";
output << "{" << datatree.symbol_table.getTeXName(symb_id);
if (output_type == oLatexDynamicModel
&& (type == eEndogenous || type == eExogenous || type == eExogenousDet || type == eModelLocalVariable || type == eTrend || type == eLogTrend))
{
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 eParameter:
if (output_type == oMatlabOutsideModel)
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 eModelLocalVariable:
if (output_type == oMatlabDynamicModelSparse || output_type == oMatlabStaticModelSparse
|| output_type == oMatlabDynamicSteadyStateOperator || output_type == oMatlabDynamicSparseSteadyStateOperator
|| output_type == oCDynamicSteadyStateOperator)
{
output << "(";
datatree.local_variables_table[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 eModFileLocalVariable:
output << datatree.symbol_table.getName(symb_id);
break;
case eEndogenous:
switch (output_type)
{
case oJuliaDynamicModel:
case oMatlabDynamicModel:
case oCDynamicModel:
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 oCDynamic2Model:
i = tsid + (lag+1)*datatree.symbol_table.endo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCStaticModel:
case oJuliaStaticModel:
case oMatlabStaticModel:
case oMatlabStaticModelSparse:
i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oMatlabDynamicModelSparse:
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 oMatlabOutsideModel:
output << "oo_.steady_state(" << tsid + 1 << ")";
break;
case oJuliaDynamicSteadyStateOperator:
case oMatlabDynamicSteadyStateOperator:
case oMatlabDynamicSparseSteadyStateOperator:
output << "steady_state" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCDynamicSteadyStateOperator:
output << "steady_state[" << tsid << "]";
break;
case oJuliaSteadyStateFile:
case oSteadyStateFile:
output << "ys_" << LEFT_ARRAY_SUBSCRIPT(output_type) << tsid + 1 << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCSteadyStateFile:
output << "ys_[" << tsid << "]";
break;
case oMatlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case eExogenous:
i = tsid + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case oJuliaDynamicModel:
case oMatlabDynamicModel:
case oMatlabDynamicModelSparse:
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 oCDynamicModel:
case oCDynamic2Model:
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 oCStaticModel:
case oJuliaStaticModel:
case oMatlabStaticModel:
case oMatlabStaticModelSparse:
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oMatlabOutsideModel:
assert(lag == 0);
output << "oo_.exo_steady_state(" << i << ")";
break;
case oMatlabDynamicSteadyStateOperator:
output << "oo_.exo_steady_state(" << i << ")";
break;
case oJuliaSteadyStateFile:
case oSteadyStateFile:
output << "exo_" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCSteadyStateFile:
output << "exo_[" << i - 1 << "]";
break;
case oMatlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case eExogenousDet:
i = tsid + datatree.symbol_table.exo_nbr() + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case oJuliaDynamicModel:
case oMatlabDynamicModel:
case oMatlabDynamicModelSparse:
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 oCDynamicModel:
case oCDynamic2Model:
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 oCStaticModel:
case oJuliaStaticModel:
case oMatlabStaticModel:
case oMatlabStaticModelSparse:
output << "x" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oMatlabOutsideModel:
assert(lag == 0);
output << "oo_.exo_det_steady_state(" << tsid + 1 << ")";
break;
case oMatlabDynamicSteadyStateOperator:
output << "oo_.exo_det_steady_state(" << tsid + 1 << ")";
break;
case oJuliaSteadyStateFile:
case oSteadyStateFile:
output << "exo_" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case oCSteadyStateFile:
output << "exo_[" << i - 1 << "]";
break;
case oMatlabDseries:
output << "ds." << datatree.symbol_table.getName(symb_id);
if (lag != 0)
output << LEFT_ARRAY_SUBSCRIPT(output_type) << lag << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: should not reach this point" << endl;
exit(EXIT_FAILURE);
}
break;
case eExternalFunction:
case eTrend:
case eLogTrend:
case eStatementDeclaredVariable:
case eUnusedEndogenous:
case eEndogenousVAR:
cerr << "Impossible case" << endl;
exit(EXIT_FAILURE);
}
}
expr_t
VariableNode::substituteStaticAuxiliaryVariable() const
{
if (type == eEndogenous)
{
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 == eModelLocalVariable || type == eModFileLocalVariable)
datatree.local_variables_table[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 == eExogenousDet)
tsid += datatree.symbol_table.exo_nbr();
if (!lhs_rhs)
{
if (dynamic)
{
if (steady_dynamic) // steady state values in a dynamic model
{
FLDVS_ fldvs(type, tsid);
fldvs.write(CompileCode, instruction_number);
}
else
{
if (type == eParameter)
{
FLDV_ fldv(type, tsid);
fldv.write(CompileCode, instruction_number);
}
else
{
FLDV_ fldv(type, tsid, lag);
fldv.write(CompileCode, instruction_number);
}
}
}
else
{
FLDSV_ fldsv(type, 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 == eParameter)
{
FSTPV_ fstpv(type, tsid);
fstpv.write(CompileCode, instruction_number);
}
else
{
FSTPV_ fstpv(type, tsid, lag);
fstpv.write(CompileCode, instruction_number);
}
}
}
else
{
FSTPSV_ fstpsv(type, 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 == eModelLocalVariable)
datatree.local_variables_table[symb_id]->computeTemporaryTerms(reference_count, temporary_terms, first_occurence, Curr_block, v_temporary_terms, equation);
}
void
VariableNode::collectVARLHSVariable(set &result) const
{
if (type == eEndogenous && 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 == eModelLocalVariable)
datatree.local_variables_table[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 == eEndogenous)
{
if (datatree.symbol_table.getTypeSpecificID(symb_id) == var_endo && lag == 0)
/* the endogenous variable */
return { 1, nullptr };
else
return { 0, datatree.AddVariableInternal(symb_id, lag) };
}
else
{
if (type == eParameter)
return { 0, datatree.AddVariableInternal(symb_id, 0) };
else
return { 0, datatree.AddVariableInternal(symb_id, lag) };
}
}
expr_t
VariableNode::getChainRuleDerivative(int deriv_id, const map &recursive_variables)
{
switch (type)
{
case eEndogenous:
case eExogenous:
case eExogenousDet:
case eParameter:
case eTrend:
case eLogTrend:
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 eModelLocalVariable:
return datatree.local_variables_table[symb_id]->getChainRuleDerivative(deriv_id, recursive_variables);
case eModFileLocalVariable:
cerr << "ModFileLocalVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case eStatementDeclaredVariable:
cerr << "eStatementDeclaredVariable is not derivable" << endl;
exit(EXIT_FAILURE);
case eUnusedEndogenous:
cerr << "eUnusedEndogenous is not derivable" << endl;
exit(EXIT_FAILURE);
case eExternalFunction:
case eEndogenousVAR:
cerr << "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 eEndogenous:
ei.endo.emplace(symb_id, lag);
break;
case eExogenous:
ei.exo.emplace(symb_id, lag);
break;
case eExogenousDet:
ei.exo_det.emplace(symb_id, lag);
break;
case eParameter:
ei.param.emplace(symb_id, 0);
break;
case eTrend:
case eLogTrend:
case eModelLocalVariable:
case eModFileLocalVariable:
case eStatementDeclaredVariable:
case eUnusedEndogenous:
case eExternalFunction:
case eEndogenousVAR:
break;
}
}
expr_t
VariableNode::cloneDynamic(DataTree &dynamic_datatree) const
{
return dynamic_datatree.AddVariable(symb_id, lag);
}
int
VariableNode::maxEndoLead() const
{
switch (type)
{
case eEndogenous:
return max(lag, 0);
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->maxEndoLead();
default:
return 0;
}
}
int
VariableNode::maxExoLead() const
{
switch (type)
{
case eExogenous:
return max(lag, 0);
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->maxExoLead();
default:
return 0;
}
}
int
VariableNode::maxEndoLag() const
{
switch (type)
{
case eEndogenous:
return max(-lag, 0);
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->maxEndoLag();
default:
return 0;
}
}
int
VariableNode::maxExoLag() const
{
switch (type)
{
case eExogenous:
return max(-lag, 0);
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->maxExoLag();
default:
return 0;
}
}
int
VariableNode::maxLead() const
{
switch (type)
{
case eEndogenous:
return lag;
case eExogenous:
return lag;
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->maxLead();
default:
return 0;
}
}
int
VariableNode::VarMinLag() const
{
switch (type)
{
case eEndogenous:
return -lag;
case eExogenous:
if (lag > 0)
return -lag;
else
return 1; // Can have contemporaneus exog in VAR
case eModelLocalVariable:
return datatree.local_variables_table[symb_id]->VarMinLag();
default:
return 1;
}
}
int
VariableNode::maxLag() const
{
switch (type)
{
case eEndogenous:
return -lag;
case eExogenous:
return -lag;
case eModelLocalVariable:
return datatree.local_variables_table[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(vector &lhs) const
{
return -lag;
}
expr_t
VariableNode::substituteAdl() 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
{
}
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 eEndogenous:
case eExogenous:
case eExogenousDet:
case eTrend:
case eLogTrend:
return datatree.AddVariable(symb_id, lag-n);
case eModelLocalVariable:
return datatree.local_variables_table[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 eEndogenous:
if (lag <= 1)
return const_cast(this);
else
return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
case eModelLocalVariable:
value = datatree.local_variables_table[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 eEndogenous:
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 eModelLocalVariable:
value = datatree.local_variables_table[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 eExogenous:
if (lag <= 0)
return const_cast(this);
else
return createExoLeadAuxiliaryVarForMyself(subst_table, neweqs);
case eModelLocalVariable:
value = datatree.local_variables_table[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 eExogenous:
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 eModelLocalVariable:
value = datatree.local_variables_table[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 eEndogenous:
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 eModelLocalVariable:
value = datatree.local_variables_table[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
{
return false;
}
bool
VariableNode::containsEndogenous() const
{
if (type == eEndogenous)
return true;
else
return false;
}
bool
VariableNode::containsExogenous() const
{
return (type == eExogenous || type == eExogenousDet);
}
expr_t
VariableNode::replaceTrendVar() const
{
if (get_type() == eTrend)
return datatree.One;
else if (get_type() == eLogTrend)
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() != eTrend && get_type() != eLogTrend) || get_lag() == 0)
return const_cast(this);
map::const_iterator it = trend_symbols_map.find(symb_id);
expr_t noTrendLeadLagNode = new VariableNode(datatree, it->first, 0);
bool log_trend = get_type() == eLogTrend;
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;
}
void
VariableNode::setVarExpectationIndex(map> &var_model_info)
{
}
void
VariableNode::walkPacParameters(bool &pac_encountered, pair &lhs, set>> &ec_params_and_vars, set>> &ar_params_and_vars) const
{
}
void
VariableNode::addParamInfoToPac(pair &lhs_arg, set>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg)
{
}
void
VariableNode::fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int 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 == eEndogenous)
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;
}
UnaryOpNode::UnaryOpNode(DataTree &datatree_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),
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))
{
// Add myself to the unary op map
datatree.unary_op_node_map[{ arg, op_code, expectation_information_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags }] = this;
}
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 == oSteadyState || op_code == oSteadyStateParamDeriv
|| op_code == oSteadyStateParam2ndDeriv)
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 oUminus:
return datatree.AddUMinus(darg);
case oExp:
return datatree.AddTimes(darg, this);
case oLog:
return datatree.AddDivide(darg, arg);
case oLog10:
t11 = datatree.AddExp(datatree.One);
t12 = datatree.AddLog10(t11);
t13 = datatree.AddDivide(darg, arg);
return datatree.AddTimes(t12, t13);
case oCos:
t11 = datatree.AddSin(arg);
t12 = datatree.AddUMinus(t11);
return datatree.AddTimes(darg, t12);
case oSin:
t11 = datatree.AddCos(arg);
return datatree.AddTimes(darg, t11);
case oTan:
t11 = datatree.AddTimes(this, this);
t12 = datatree.AddPlus(t11, datatree.One);
return datatree.AddTimes(darg, t12);
case oAcos:
t11 = datatree.AddSin(this);
t12 = datatree.AddDivide(darg, t11);
return datatree.AddUMinus(t12);
case oAsin:
t11 = datatree.AddCos(this);
return datatree.AddDivide(darg, t11);
case oAtan:
t11 = datatree.AddTimes(arg, arg);
t12 = datatree.AddPlus(datatree.One, t11);
return datatree.AddDivide(darg, t12);
case oCosh:
t11 = datatree.AddSinh(arg);
return datatree.AddTimes(darg, t11);
case oSinh:
t11 = datatree.AddCosh(arg);
return datatree.AddTimes(darg, t11);
case oTanh:
t11 = datatree.AddTimes(this, this);
t12 = datatree.AddMinus(datatree.One, t11);
return datatree.AddTimes(darg, t12);
case oAcosh:
t11 = datatree.AddSinh(this);
return datatree.AddDivide(darg, t11);
case oAsinh:
t11 = datatree.AddCosh(this);
return datatree.AddDivide(darg, t11);
case oAtanh:
t11 = datatree.AddTimes(arg, arg);
t12 = datatree.AddMinus(datatree.One, t11);
return datatree.AddTimes(darg, t12);
case oSqrt:
t11 = datatree.AddPlus(this, this);
return datatree.AddDivide(darg, t11);
case oAbs:
t11 = datatree.AddSign(arg);
return datatree.AddTimes(t11, darg);
case oSign:
return datatree.Zero;
case oSteadyState:
if (datatree.isDynamic())
{
if (datatree.getTypeByDerivID(deriv_id) == eParameter)
{
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) == eEndogenous)
return datatree.AddSteadyStateParamDeriv(arg, datatree.getSymbIDByDerivID(deriv_id));
else
return datatree.Zero;
}
else
return datatree.Zero;
}
else
return darg;
case oSteadyStateParamDeriv:
assert(datatree.isDynamic());
if (datatree.getTypeByDerivID(deriv_id) == eParameter)
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
return datatree.AddSteadyStateParam2ndDeriv(arg, param1_symb_id, datatree.getSymbIDByDerivID(deriv_id));
}
else
return datatree.Zero;
case oSteadyStateParam2ndDeriv:
assert(datatree.isDynamic());
if (datatree.getTypeByDerivID(deriv_id) == eParameter)
{
cerr << "3rd derivative of STEADY_STATE node w.r.t. three parameters not implemented" << endl;
exit(EXIT_FAILURE);
}
else
return datatree.Zero;
case oExpectation:
cerr << "UnaryOpNode::composeDerivatives: not implemented on oExpectation" << endl;
exit(EXIT_FAILURE);
case oErf:
// 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 oDiff:
cerr << "UnaryOpNode::composeDerivatives: not implemented on oDiff" << endl;
exit(EXIT_FAILURE);
case oAdl:
cerr << "UnaryOpNode::composeDerivatives: not implemented on oAdl" << 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 oUminus:
case oSign:
return cost + 70;
case oExp:
return cost + 160;
case oLog:
return cost + 300;
case oLog10:
case oErf:
return cost + 16000;
case oCos:
case oSin:
case oCosh:
return cost + 210;
case oTan:
return cost + 230;
case oAcos:
return cost + 300;
case oAsin:
return cost + 310;
case oAtan:
return cost + 140;
case oSinh:
return cost + 240;
case oTanh:
return cost + 190;
case oAcosh:
return cost + 770;
case oAsinh:
return cost + 460;
case oAtanh:
return cost + 350;
case oSqrt:
case oAbs:
return cost + 570;
case oSteadyState:
case oSteadyStateParamDeriv:
case oSteadyStateParam2ndDeriv:
case oExpectation:
return cost;
case oDiff:
cerr << "UnaryOpNode::cost: not implemented on oDiff" << endl;
exit(EXIT_FAILURE);
case oAdl:
cerr << "UnaryOpNode::cost: not implemented on oAdl" << endl;
exit(EXIT_FAILURE);
}
else
// Cost for C files
switch (op_code)
{
case oUminus:
case oSign:
return cost + 3;
case oExp:
case oAcosh:
return cost + 210;
case oLog:
return cost + 137;
case oLog10:
return cost + 139;
case oCos:
case oSin:
return cost + 160;
case oTan:
return cost + 170;
case oAcos:
case oAtan:
return cost + 190;
case oAsin:
return cost + 180;
case oCosh:
case oSinh:
case oTanh:
case oErf:
return cost + 240;
case oAsinh:
return cost + 220;
case oAtanh:
return cost + 150;
case oSqrt:
case oAbs:
return cost + 90;
case oSteadyState:
case oSteadyStateParamDeriv:
case oSteadyStateParam2ndDeriv:
case oExpectation:
return cost;
case oDiff:
cerr << "UnaryOpNode::cost: not implemented on oDiff" << endl;
exit(EXIT_FAILURE);
case oAdl:
cerr << "UnaryOpNode::cost: not implemented on oAdl" << 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 == oUminus)
output << "(";
switch (op_code)
{
case oUminus:
output << "-";
break;
case oExp:
output << "exp";
break;
case oLog:
output << "log";
break;
case oLog10:
output << "log10";
break;
case oCos:
output << "cos";
break;
case oSin:
output << "sin";
break;
case oTan:
output << "tan";
break;
case oAcos:
output << "acos";
break;
case oAsin:
output << "asin";
break;
case oAtan:
output << "atan";
break;
case oCosh:
output << "cosh";
break;
case oSinh:
output << "sinh";
break;
case oTanh:
output << "tanh";
break;
case oAcosh:
output << "acosh";
break;
case oAsinh:
output << "asinh";
break;
case oAtanh:
output << "atanh";
break;
case oSqrt:
output << "sqrt";
break;
case oAbs:
output << "abs";
break;
case oSign:
output << "sign";
break;
case oDiff:
output << "diff";
break;
case oAdl:
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 oSteadyState:
output << "(";
arg->writeJsonOutput(output, temporary_terms, tef_terms, isdynamic);
output << ")";
return;
case oSteadyStateParamDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
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 oSteadyStateParam2ndDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
assert(datatree.symbol_table.getType(param2_symb_id) == eParameter);
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 oExpectation:
output << "EXPECTATION(" << expectation_information_set << ")";
break;
case oErf:
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 != oUminus
|| (op_code == oUminus
&& 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 == oUminus)
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 == oUminus)
output << LEFT_PAR(output_type);
switch (op_code)
{
case oUminus:
output << "-";
break;
case oExp:
output << "exp";
break;
case oLog:
if (IS_LATEX(output_type))
output << "\\log";
else
output << "log";
break;
case oLog10:
if (IS_LATEX(output_type))
output << "\\log_{10}";
else
output << "log10";
break;
case oCos:
output << "cos";
break;
case oSin:
output << "sin";
break;
case oTan:
output << "tan";
break;
case oAcos:
output << "acos";
break;
case oAsin:
output << "asin";
break;
case oAtan:
output << "atan";
break;
case oCosh:
output << "cosh";
break;
case oSinh:
output << "sinh";
break;
case oTanh:
output << "tanh";
break;
case oAcosh:
output << "acosh";
break;
case oAsinh:
output << "asinh";
break;
case oAtanh:
output << "atanh";
break;
case oSqrt:
output << "sqrt";
break;
case oAbs:
output << "abs";
break;
case oSign:
if (output_type == oCDynamicModel || output_type == oCStaticModel)
output << "copysign";
else
output << "sign";
break;
case oSteadyState:
ExprNodeOutputType new_output_type;
switch (output_type)
{
case oMatlabDynamicModel:
new_output_type = oMatlabDynamicSteadyStateOperator;
break;
case oLatexDynamicModel:
new_output_type = oLatexDynamicSteadyStateOperator;
break;
case oCDynamicModel:
new_output_type = oCDynamicSteadyStateOperator;
break;
case oJuliaDynamicModel:
new_output_type = oJuliaDynamicSteadyStateOperator;
break;
case oMatlabDynamicModelSparse:
new_output_type = oMatlabDynamicSparseSteadyStateOperator;
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 oSteadyStateParamDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
int tsid_endo = datatree.symbol_table.getTypeSpecificID(varg->symb_id);
int tsid_param = datatree.symbol_table.getTypeSpecificID(param1_symb_id);
assert(IS_MATLAB(output_type));
output << "ss_param_deriv(" << tsid_endo+1 << "," << tsid_param+1 << ")";
}
return;
case oSteadyStateParam2ndDeriv:
{
auto *varg = dynamic_cast(arg);
assert(varg != nullptr);
assert(datatree.symbol_table.getType(varg->symb_id) == eEndogenous);
assert(datatree.symbol_table.getType(param1_symb_id) == eParameter);
assert(datatree.symbol_table.getType(param2_symb_id) == eParameter);
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(IS_MATLAB(output_type));
output << "ss_param_2nd_deriv(" << tsid_endo+1 << "," << tsid_param1+1
<< "," << tsid_param2+1 << ")";
}
return;
case oExpectation:
if (!IS_LATEX(output_type))
{
cerr << "UnaryOpNode::writeOutput: not implemented on oExpectation" << 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 oErf:
output << "erf";
break;
case oDiff:
output << "diff";
break;
case oAdl:
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 != oUminus
|| (op_code == oUminus
&& arg->precedence(output_type, temporary_terms) < precedence(output_type, temporary_terms)))
{
output << LEFT_PAR(output_type);
if (op_code == oSign && (output_type == oCDynamicModel || output_type == oCStaticModel))
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 == oUminus)
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 oUminus:
return (-v);
case oExp:
return (exp(v));
case oLog:
return (log(v));
case oLog10:
return (log10(v));
case oCos:
return (cos(v));
case oSin:
return (sin(v));
case oTan:
return (tan(v));
case oAcos:
return (acos(v));
case oAsin:
return (asin(v));
case oAtan:
return (atan(v));
case oCosh:
return (cosh(v));
case oSinh:
return (sinh(v));
case oTanh:
return (tanh(v));
case oAcosh:
return (acosh(v));
case oAsinh:
return (asinh(v));
case oAtanh:
return (atanh(v));
case oSqrt:
return (sqrt(v));
case oAbs:
return (abs(v));
case oSign:
return (v > 0) ? 1 : ((v < 0) ? -1 : 0);
case oSteadyState:
return (v);
case oSteadyStateParamDeriv:
case oSteadyStateParam2ndDeriv:
case oExpectation:
case oErf:
return (erf(v));
case oDiff:
cerr << "UnaryOpNode::eval_opcode: not implemented on oDiff" << endl;
exit(EXIT_FAILURE);
case oAdl:
cerr << "UnaryOpNode::eval_opcode: not implemented on oAdl" << 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 == oSteadyState)
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(op_code);
funary.write(CompileCode, instruction_number);
}
}
void
UnaryOpNode::collectVARLHSVariable(set &result) const
{
if (op_code == oDiff)
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 oUminus:
List_of_Op_RHS.emplace_back(oUminus, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oExp:
List_of_Op_RHS.emplace_back(oLog, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oLog:
List_of_Op_RHS.emplace_back(oExp, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oLog10:
List_of_Op_RHS.emplace_back(oPower, make_pair(nullptr, datatree.AddNonNegativeConstant("10")));
return { 1, nullptr };
case oCos:
List_of_Op_RHS.emplace_back(oAcos, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oSin:
List_of_Op_RHS.emplace_back(oAsin, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oTan:
List_of_Op_RHS.emplace_back(oAtan, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAcos:
List_of_Op_RHS.emplace_back(oCos, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAsin:
List_of_Op_RHS.emplace_back(oSin, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAtan:
List_of_Op_RHS.emplace_back(oTan, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oCosh:
List_of_Op_RHS.emplace_back(oAcosh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oSinh:
List_of_Op_RHS.emplace_back(oAsinh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oTanh:
List_of_Op_RHS.emplace_back(oAtanh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAcosh:
List_of_Op_RHS.emplace_back(oCosh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAsinh:
List_of_Op_RHS.emplace_back(oSinh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oAtanh:
List_of_Op_RHS.emplace_back(oTanh, make_pair(nullptr, nullptr));
return { 1, nullptr };
case oSqrt:
List_of_Op_RHS.emplace_back(oPower, make_pair(nullptr, datatree.Two));
return { 1, nullptr };
case oAbs:
return { 2, nullptr };
case oSign:
return { 2, nullptr };
case oSteadyState:
return { 2, nullptr };
case oErf:
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 oUminus:
return { 0, datatree.AddUMinus(New_expr_t) };
case oExp:
return { 0, datatree.AddExp(New_expr_t) };
case oLog:
return { 0, datatree.AddLog(New_expr_t) };
case oLog10:
return { 0, datatree.AddLog10(New_expr_t) };
case oCos:
return { 0, datatree.AddCos(New_expr_t) };
case oSin:
return { 0, datatree.AddSin(New_expr_t) };
case oTan:
return { 0, datatree.AddTan(New_expr_t) };
case oAcos:
return { 0, datatree.AddAcos(New_expr_t) };
case oAsin:
return { 0, datatree.AddAsin(New_expr_t) };
case oAtan:
return { 0, datatree.AddAtan(New_expr_t) };
case oCosh:
return { 0, datatree.AddCosh(New_expr_t) };
case oSinh:
return { 0, datatree.AddSinh(New_expr_t) };
case oTanh:
return { 0, datatree.AddTanh(New_expr_t) };
case oAcosh:
return { 0, datatree.AddAcosh(New_expr_t) };
case oAsinh:
return { 0, datatree.AddAsinh(New_expr_t) };
case oAtanh:
return { 0, datatree.AddAtanh(New_expr_t) };
case oSqrt:
return { 0, datatree.AddSqrt(New_expr_t) };
case oAbs:
return { 0, datatree.AddAbs(New_expr_t) };
case oSign:
return { 0, datatree.AddSign(New_expr_t) };
case oSteadyState:
return { 0, datatree.AddSteadyState(New_expr_t) };
case oErf:
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 oUminus:
return alt_datatree.AddUMinus(alt_arg);
case oExp:
return alt_datatree.AddExp(alt_arg);
case oLog:
return alt_datatree.AddLog(alt_arg);
case oLog10:
return alt_datatree.AddLog10(alt_arg);
case oCos:
return alt_datatree.AddCos(alt_arg);
case oSin:
return alt_datatree.AddSin(alt_arg);
case oTan:
return alt_datatree.AddTan(alt_arg);
case oAcos:
return alt_datatree.AddAcos(alt_arg);
case oAsin:
return alt_datatree.AddAsin(alt_arg);
case oAtan:
return alt_datatree.AddAtan(alt_arg);
case oCosh:
return alt_datatree.AddCosh(alt_arg);
case oSinh:
return alt_datatree.AddSinh(alt_arg);
case oTanh:
return alt_datatree.AddTanh(alt_arg);
case oAcosh:
return alt_datatree.AddAcosh(alt_arg);
case oAsinh:
return alt_datatree.AddAsinh(alt_arg);
case oAtanh:
return alt_datatree.AddAtanh(alt_arg);
case oSqrt:
return alt_datatree.AddSqrt(alt_arg);
case oAbs:
return alt_datatree.AddAbs(alt_arg);
case oSign:
return alt_datatree.AddSign(alt_arg);
case oSteadyState:
return alt_datatree.AddSteadyState(alt_arg);
case oSteadyStateParamDeriv:
cerr << "UnaryOpNode::buildSimilarUnaryOpNode: oSteadyStateParamDeriv can't be translated" << endl;
exit(EXIT_FAILURE);
case oSteadyStateParam2ndDeriv:
cerr << "UnaryOpNode::buildSimilarUnaryOpNode: oSteadyStateParam2ndDeriv can't be translated" << endl;
exit(EXIT_FAILURE);
case oExpectation:
return alt_datatree.AddExpectation(expectation_information_set, alt_arg);
case oErf:
return alt_datatree.AddErf(alt_arg);
case oDiff:
return alt_datatree.AddDiff(alt_arg);
case oAdl:
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 == oDiff)
return arg->maxLag() + 1;
return arg->maxLag();
}
expr_t
UnaryOpNode::undiff() const
{
if (op_code == oDiff)
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(vector &lhs) const
{
//This will never be an oDiff node
return arg->PacMaxLag(lhs);
}
expr_t
UnaryOpNode::substituteAdl() const
{
if (op_code != oAdl)
{
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;
}
int
UnaryOpNode::countDiffs() const
{
if (op_code == oDiff)
return arg->countDiffs() + 1;
return arg->countDiffs();
}
bool
UnaryOpNode::createAuxVarForUnaryOpNode() const
{
switch (op_code)
{
case oExp:
case oLog:
case oLog10:
case oCos:
case oSin:
case oTan:
case oAcos:
case oAsin:
case oAtan:
case oCosh:
case oSinh:
case oTanh:
case oAcosh:
case oAsinh:
case oAtanh:
case oSqrt:
case oAbs:
case oSign:
case oErf:
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 != oDiff)
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);
}
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 != oDiff)
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 &neweqs) const
{
subst_table_t::const_iterator sit = subst_table.find(this);
if (sit != subst_table.end())
return const_cast(sit->second);
auto *sthis = dynamic_cast(this->toStatic(static_datatree));
auto it = nodes.find(sthis);
expr_t argsubst = arg->substituteUnaryOpNodes(static_datatree, nodes, subst_table, neweqs);
if (it == nodes.end())
return buildSimilarUnaryOpNode(argsubst, datatree);
int base_aux_lag;
VariableNode *aux_var = nullptr;
for (auto rit = it->second.rbegin(); rit != it->second.rend(); rit++)
if (rit == it->second.rbegin())
{
int symb_id;
auto *vn = dynamic_cast(argsubst);
if (vn == nullptr)
symb_id = datatree.symbol_table.addUnaryOpAuxiliaryVar(this->idx, dynamic_cast(rit->second));
else
symb_id = datatree.symbol_table.addUnaryOpAuxiliaryVar(this->idx, dynamic_cast(rit->second),
vn->get_symb_id(), vn->get_lag());
aux_var = datatree.AddVariable(symb_id, 0);
neweqs.push_back(dynamic_cast(datatree.AddEqual(aux_var,
dynamic_cast(rit->second))));
subst_table[rit->second] = dynamic_cast(aux_var);
base_aux_lag = rit->first;
}
else
subst_table[rit->second] = dynamic_cast(aux_var->decreaseLeadsLags(base_aux_lag - rit->first));
sit = subst_table.find(this);
return const_cast(sit->second);
}
expr_t
UnaryOpNode::substitutePacExpectation(map &subst_table)
{
expr_t argsubst = arg->substitutePacExpectation(subst_table);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::decreaseLeadsLags(int n) const
{
expr_t argsubst = arg->decreaseLeadsLags(n);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::decreaseLeadsLagsPredeterminedVariables() const
{
expr_t argsubst = arg->decreaseLeadsLagsPredeterminedVariables();
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::substituteEndoLeadGreaterThanTwo(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
if (op_code == oUminus || deterministic_model)
{
expr_t argsubst = arg->substituteEndoLeadGreaterThanTwo(subst_table, neweqs, deterministic_model);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
else
{
if (maxEndoLead() >= 2)
return createEndoLeadAuxiliaryVarForMyself(subst_table, neweqs);
else
return const_cast(this);
}
}
expr_t
UnaryOpNode::substituteEndoLagGreaterThanTwo(subst_table_t &subst_table, vector &neweqs) const
{
expr_t argsubst = arg->substituteEndoLagGreaterThanTwo(subst_table, neweqs);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::substituteExoLead(subst_table_t &subst_table, vector &neweqs, bool deterministic_model) const
{
if (op_code == oUminus || deterministic_model)
{
expr_t argsubst = arg->substituteExoLead(subst_table, neweqs, deterministic_model);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
else
{
if (maxExoLead() >= 1)
return createExoLeadAuxiliaryVarForMyself(subst_table, neweqs);
else
return const_cast(this);
}
}
expr_t
UnaryOpNode::substituteExoLag(subst_table_t &subst_table, vector &neweqs) const
{
expr_t argsubst = arg->substituteExoLag(subst_table, neweqs);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::substituteExpectation(subst_table_t &subst_table, vector &neweqs, bool partial_information_model) const
{
if (op_code == oExpectation)
{
auto it = subst_table.find(const_cast(this));
if (it != subst_table.end())
return const_cast(it->second);
//Arriving here, we need to create an auxiliary variable for this Expectation Operator:
//AUX_EXPECT_(LEAD/LAG)_(period)_(arg.idx) OR
//AUX_EXPECT_(info_set_name)_(arg.idx)
int symb_id = datatree.symbol_table.addExpectationAuxiliaryVar(expectation_information_set, arg->idx, arg);
expr_t newAuxE = datatree.AddVariable(symb_id, 0);
if (partial_information_model && expectation_information_set == 0)
if (dynamic_cast(arg) == nullptr)
{
cerr << "ERROR: In Partial Information models, EXPECTATION(0)(X) "
<< "can only be used when X is a single variable." << endl;
exit(EXIT_FAILURE);
}
//take care of any nested expectation operators by calling arg->substituteExpectation(.), then decreaseLeadsLags for this oExpectation operator
//arg(lag-period) (holds entire subtree of arg(lag-period)
expr_t substexpr = (arg->substituteExpectation(subst_table, neweqs, partial_information_model))->decreaseLeadsLags(expectation_information_set);
assert(substexpr != nullptr);
neweqs.push_back(dynamic_cast(datatree.AddEqual(newAuxE, substexpr))); //AUXE_period_arg.idx = arg(lag-period)
newAuxE = datatree.AddVariable(symb_id, expectation_information_set);
assert(dynamic_cast(newAuxE) != nullptr);
subst_table[this] = dynamic_cast(newAuxE);
return newAuxE;
}
else
{
expr_t argsubst = arg->substituteExpectation(subst_table, neweqs, partial_information_model);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
}
expr_t
UnaryOpNode::differentiateForwardVars(const vector &subset, subst_table_t &subst_table, vector &neweqs) const
{
expr_t argsubst = arg->differentiateForwardVars(subset, subst_table, neweqs);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
bool
UnaryOpNode::isNumConstNodeEqualTo(double value) const
{
return false;
}
bool
UnaryOpNode::isVariableNodeEqualTo(SymbolType type_arg, int variable_id, int lag_arg) const
{
return false;
}
bool
UnaryOpNode::containsPacExpectation() const
{
return arg->containsPacExpectation();
}
bool
UnaryOpNode::containsEndogenous() const
{
return arg->containsEndogenous();
}
bool
UnaryOpNode::containsExogenous() const
{
return arg->containsExogenous();
}
expr_t
UnaryOpNode::replaceTrendVar() const
{
expr_t argsubst = arg->replaceTrendVar();
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::detrend(int symb_id, bool log_trend, expr_t trend) const
{
expr_t argsubst = arg->detrend(symb_id, log_trend, trend);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::removeTrendLeadLag(map trend_symbols_map) const
{
expr_t argsubst = arg->removeTrendLeadLag(trend_symbols_map);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
bool
UnaryOpNode::isInStaticForm() const
{
if (op_code == oSteadyState || op_code == oSteadyStateParamDeriv
|| op_code == oSteadyStateParam2ndDeriv
|| op_code == oExpectation)
return false;
else
return arg->isInStaticForm();
}
void
UnaryOpNode::setVarExpectationIndex(map> &var_model_info)
{
arg->setVarExpectationIndex(var_model_info);
}
void
UnaryOpNode::walkPacParameters(bool &pac_encountered, pair &lhs, set>> &ec_params_and_vars, set>> &ar_params_and_vars) const
{
arg->walkPacParameters(pac_encountered, lhs, ec_params_and_vars, ar_params_and_vars);
}
void
UnaryOpNode::addParamInfoToPac(pair &lhs_arg, set>> &ec_params_and_vars_arg, set>> &ar_params_and_vars_arg)
{
arg->addParamInfoToPac(lhs_arg, ec_params_and_vars_arg, ar_params_and_vars_arg);
}
void
UnaryOpNode::fillPacExpectationVarInfo(string &model_name_arg, vector &lhs_arg, int max_lag_arg, vector &nonstationary_arg, int growth_symb_id_arg, int equation_number_arg)
{
arg->fillPacExpectationVarInfo(model_name_arg, lhs_arg, max_lag_arg, nonstationary_arg, growth_symb_id_arg, equation_number_arg);
}
bool
UnaryOpNode::isVarModelReferenced(const string &model_info_name) const
{
return arg->isVarModelReferenced(model_info_name);
}
void
UnaryOpNode::getEndosAndMaxLags(map &model_endos_and_lags) const
{
arg->getEndosAndMaxLags(model_endos_and_lags);
}
expr_t
UnaryOpNode::substituteStaticAuxiliaryVariable() const
{
expr_t argsubst = arg->substituteStaticAuxiliaryVariable();
if (op_code == oExpectation)
return argsubst;
else
return buildSimilarUnaryOpNode(argsubst, datatree);
}
BinaryOpNode::BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
BinaryOpcode op_code_arg, const expr_t arg2_arg) :
ExprNode(datatree_arg),
arg1(arg1_arg),
arg2(arg2_arg),
op_code(op_code_arg),
powerDerivOrder(0)
{
datatree.binary_op_node_map[{ arg1, arg2, op_code, powerDerivOrder }] = this;
}
BinaryOpNode::BinaryOpNode(DataTree &datatree_arg, const expr_t arg1_arg,
BinaryOpcode op_code_arg, const expr_t arg2_arg, int powerDerivOrder_arg) :
ExprNode(datatree_arg),
arg1(arg1_arg),
arg2(arg2_arg),
op_code(op_code_arg),
powerDerivOrder(powerDerivOrder_arg)
{
assert(powerDerivOrder >= 0);
datatree.binary_op_node_map[{ arg1, arg2, op_code, powerDerivOrder }] = this;
}
void
BinaryOpNode::prepareForDerivation()
{
if (preparedForDerivation)
return;
preparedForDerivation = true;
arg1->prepareForDerivation();
arg2->prepareForDerivation();
// Non-null derivatives are the union of those of the arguments
// Compute set union of arg1->non_null_derivatives and arg2->non_null_derivatives
set_union(arg1->non_null_derivatives.begin(),
arg1->non_null_derivatives.end(),
arg2->non_null_derivatives.begin(),
arg2->non_null_derivatives.end(),
inserter(non_null_derivatives, non_null_derivatives.begin()));
}
expr_t
BinaryOpNode::getNonZeroPartofEquation() const
{
assert(arg1 == datatree.Zero || arg2 == datatree.Zero);
if (arg1 == datatree.Zero)
return arg2;
return arg1;
}
expr_t
BinaryOpNode::composeDerivatives(expr_t darg1, expr_t darg2)
{
expr_t t11, t12, t13, t14, t15;
switch (op_code)
{
case oPlus:
return datatree.AddPlus(darg1, darg2);
case oMinus:
return datatree.AddMinus(darg1, darg2);
case oTimes:
t11 = datatree.AddTimes(darg1, arg2);
t12 = datatree.AddTimes(darg2, arg1);
return datatree.AddPlus(t11, t12);
case oDivide:
if (darg2 != datatree.Zero)
{
t11 = datatree.AddTimes(darg1, arg2);
t12 = datatree.AddTimes(darg2, arg1);
t13 = datatree.AddMinus(t11, t12);
t14 = datatree.AddTimes(arg2, arg2);
return datatree.AddDivide(t13, t14);
}
else
return datatree.AddDivide(darg1, arg2);
case oLess:
case oGreater:
case oLessEqual:
case oGreaterEqual:
case oEqualEqual:
case oDifferent:
return datatree.Zero;
case oPower:
if (darg2 == datatree.Zero)
if (darg1 == datatree.Zero)
return datatree.Zero;
else
if (dynamic_cast(arg2) != nullptr)
{
t11 = datatree.AddMinus(arg2, datatree.One);
t12 = datatree.AddPower(arg1, t11);
t13 = datatree.AddTimes(arg2, t12);
return datatree.AddTimes(darg1, t13);
}
else
return datatree.AddTimes(darg1, datatree.AddPowerDeriv(arg1, arg2, powerDerivOrder + 1));
else
{
t11 = datatree.AddLog(arg1);
t12 = datatree.AddTimes(darg2, t11);
t13 = datatree.AddTimes(darg1, arg2);
t14 = datatree.AddDivide(t13, arg1);
t15 = datatree.AddPlus(t12, t14);
return datatree.AddTimes(t15, this);
}
case oPowerDeriv:
if (darg2 == datatree.Zero)
return datatree.AddTimes(darg1, datatree.AddPowerDeriv(arg1, arg2, powerDerivOrder + 1));
else
{
t11 = datatree.AddTimes(darg2, datatree.AddLog(arg1));
t12 = datatree.AddMinus(arg2, datatree.AddPossiblyNegativeConstant(powerDerivOrder));
t13 = datatree.AddTimes(darg1, t12);
t14 = datatree.AddDivide(t13, arg1);
t15 = datatree.AddPlus(t11, t14);
expr_t f = datatree.AddPower(arg1, t12);
expr_t first_part = datatree.AddTimes(f, t15);
for (int i = 0; i < powerDerivOrder; i++)
first_part = datatree.AddTimes(first_part, datatree.AddMinus(arg2, datatree.AddPossiblyNegativeConstant(i)));
t13 = datatree.Zero;
for (int i = 0; i < powerDerivOrder; i++)
{
t11 = datatree.One;
for (int j = 0; j < powerDerivOrder; j++)
if (i != j)
{
t12 = datatree.AddMinus(arg2, datatree.AddPossiblyNegativeConstant(j));
t11 = datatree.AddTimes(t11, t12);
}
t13 = datatree.AddPlus(t13, t11);
}
t13 = datatree.AddTimes(darg2, t13);
t14 = datatree.AddTimes(f, t13);
return datatree.AddPlus(first_part, t14);
}
case oMax:
t11 = datatree.AddGreater(arg1, arg2);
t12 = datatree.AddTimes(t11, darg1);
t13 = datatree.AddMinus(datatree.One, t11);
t14 = datatree.AddTimes(t13, darg2);
return datatree.AddPlus(t14, t12);
case oMin:
t11 = datatree.AddGreater(arg2, arg1);
t12 = datatree.AddTimes(t11, darg1);
t13 = datatree.AddMinus(datatree.One, t11);
t14 = datatree.AddTimes(t13, darg2);
return datatree.AddPlus(t14, t12);
case oEqual:
return datatree.AddMinus(darg1, darg2);
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
expr_t
BinaryOpNode::unpackPowerDeriv() const
{
if (op_code != oPowerDeriv)
return const_cast(this);
expr_t front = datatree.One;
for (int i = 0; i < powerDerivOrder; i++)
front = datatree.AddTimes(front,
datatree.AddMinus(arg2,
datatree.AddPossiblyNegativeConstant(i)));
expr_t tmp = datatree.AddPower(arg1,
datatree.AddMinus(arg2,
datatree.AddPossiblyNegativeConstant(powerDerivOrder)));
return datatree.AddTimes(front, tmp);
}
expr_t
BinaryOpNode::computeDerivative(int deriv_id)
{
expr_t darg1 = arg1->getDerivative(deriv_id);
expr_t darg2 = arg2->getDerivative(deriv_id);
return composeDerivatives(darg1, darg2);
}
int
BinaryOpNode::precedence(ExprNodeOutputType output_type, const temporary_terms_t &temporary_terms) const
{
auto it = temporary_terms.find(const_cast(this));
// A temporary term behaves as a variable
if (it != temporary_terms.end())
return 100;
switch (op_code)
{
case oEqual:
return 0;
case oEqualEqual:
case oDifferent:
return 1;
case oLessEqual:
case oGreaterEqual:
case oLess:
case oGreater:
return 2;
case oPlus:
case oMinus:
return 3;
case oTimes:
case oDivide:
return 4;
case oPower:
case oPowerDeriv:
if (IS_C(output_type))
// In C, power operator is of the form pow(a, b)
return 100;
else
return 5;
case oMin:
case oMax:
return 100;
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
int
BinaryOpNode::precedenceJson(const temporary_terms_t &temporary_terms) const
{
auto it = temporary_terms.find(const_cast(this));
// A temporary term behaves as a variable
if (it != temporary_terms.end())
return 100;
switch (op_code)
{
case oEqual:
return 0;
case oEqualEqual:
case oDifferent:
return 1;
case oLessEqual:
case oGreaterEqual:
case oLess:
case oGreater:
return 2;
case oPlus:
case oMinus:
return 3;
case oTimes:
case oDivide:
return 4;
case oPower:
case oPowerDeriv:
return 5;
case oMin:
case oMax:
return 100;
}
// Suppress GCC warning
exit(EXIT_FAILURE);
}
int
BinaryOpNode::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;
int arg_cost = arg1->cost(temp_terms_map, is_matlab) + arg2->cost(temp_terms_map, is_matlab);
return cost(arg_cost, is_matlab);
}
int
BinaryOpNode::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