PAC: new “pac_target_info” block and “pac_target_nonstationary” operator

Ref. Madysson/estimation-codes#5
pac-components
Sébastien Villemot 2021-10-26 18:06:26 +02:00
parent 6a31ba4b62
commit ea6fb40db7
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
18 changed files with 1099 additions and 79 deletions

View File

@ -241,6 +241,14 @@ enum class PriorDistributions
weibull = 8
};
enum class PacTargetKind
{
unspecified, // Must be the first one, because its the default initializer
ll,
dl,
dd
};
struct Block_contain_type
{
int Equation, Variable, Own_Derivative;

View File

@ -93,6 +93,7 @@ DataTree::operator=(const DataTree &d)
external_function_node_map.clear();
var_expectation_node_map.clear();
pac_expectation_node_map.clear();
pac_target_nonstationary_node_map.clear();
first_deriv_external_function_node_map.clear();
second_deriv_external_function_node_map.clear();
@ -704,6 +705,20 @@ DataTree::AddPacExpectation(const string &model_name)
return p;
}
expr_t
DataTree::AddPacTargetNonstationary(const string &model_name)
{
if (auto it = pac_target_nonstationary_node_map.find(model_name);
it != pac_target_nonstationary_node_map.end())
return it->second;
auto sp = make_unique<PacTargetNonstationaryNode>(*this, node_list.size(), model_name);
auto p = sp.get();
node_list.push_back(move(sp));
pac_target_nonstationary_node_map[model_name] = p;
return p;
}
BinaryOpNode *
DataTree::AddEqual(expr_t iArg1, expr_t iArg2)
{

View File

@ -81,6 +81,10 @@ private:
using pac_expectation_node_map_t = map<string, PacExpectationNode *>;
pac_expectation_node_map_t pac_expectation_node_map;
// model_name -> PacTargetNonstationaryNode
using pac_target_nonstationary_node_map_t = map<string, PacTargetNonstationaryNode *>;
pac_target_nonstationary_node_map_t pac_target_nonstationary_node_map;
// (arguments, deriv_idx, symb_id) -> FirstDerivExternalFunctionNode
using first_deriv_external_function_node_map_t = map<tuple<vector<expr_t>, int, int>, FirstDerivExternalFunctionNode *>;
first_deriv_external_function_node_map_t first_deriv_external_function_node_map;
@ -101,13 +105,6 @@ protected:
//! Internal implementation of ParamUsedWithLeadLag()
bool ParamUsedWithLeadLagInternal() const;
/*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
and returns the name of the corresponding filesystem directory (which
is created by the function if it does not exist).
In practice the package nesting is used for the planner_objective (stored
inside +objective subdir). */
static string packageDir(const string &package);
/* Writes the contents of “new_contents” to the file “filename”. However, if
the file already exists and would not be modified by this operation, then do
nothing. */
@ -260,6 +257,8 @@ public:
expr_t AddVarExpectation(const string &model_name);
//! Adds pac_expectation command to model tree
expr_t AddPacExpectation(const string &model_name);
//! Adds a pac_target_nonstationary node to model tree
expr_t AddPacTargetNonstationary(const string &model_name);
//! Adds a model local variable with its value
void AddLocalVariable(int symb_id, expr_t value) noexcept(false);
//! Adds an external function node
@ -344,6 +343,13 @@ public:
{
no_commutativity = true;
}
/*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
and returns the name of the corresponding filesystem directory (which
is created by the function if it does not exist).
In practice the package nesting is used for the planner_objective (stored
inside +objective subdir). */
static string packageDir(const string &package);
};
inline expr_t

View File

@ -4080,6 +4080,80 @@ DynamicModel::computePacBackwardExpectationSubstitution(const string &name,
pac_expectation_substitution[name] = AddVariable(expect_var_id);
}
void
DynamicModel::computePacBackwardExpectationSubstitutionWithComponents(const string &name,
const vector<int> &lhs,
int max_lag,
const string &aux_model_type,
vector<PacModelTable::target_component_t> &pac_target_components,
map<string, expr_t> &pac_expectation_substitution)
{
auto create_aux_param = [&](const string &param_name)
{
try
{
return symbol_table.addSymbol(param_name, SymbolType::parameter);
}
catch (SymbolTable::AlreadyDeclaredException)
{
cerr << "ERROR: the variable/parameter '" << param_name << "' conflicts with some auxiliary parameter that will be generated for the '" << name << "' PAC model. Please rename that parameter." << endl;
exit(EXIT_FAILURE);
}
};
expr_t substexpr = Zero;
int component_idx = 1;
for (auto &[component, growth, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth, growth_info] : pac_target_components)
{
string name_component = name + "_component" + to_string(component_idx);
// Create the linear combination of the variables from the auxiliary model
expr_t auxdef = Zero;
if (aux_model_type == "var")
{
/* If the auxiliary model is a VAR, add a parameter corresponding
to the constant. */
int new_param_symb_id = create_aux_param("h_" + name_component + "_constant");
h_indices.push_back(new_param_symb_id);
auxdef = AddPlus(auxdef, AddVariable(new_param_symb_id));
}
for (int i = 1; i < max_lag + 1; i++)
for (auto lhsit : lhs)
{
int new_param_symb_id = create_aux_param("h_" + name_component + "_var_" + symbol_table.getName(lhsit) + "_lag_" + to_string(i));
h_indices.push_back(new_param_symb_id);
auxdef = AddPlus(auxdef, AddTimes(AddVariable(new_param_symb_id),
AddVariable(lhsit, -i)));
}
// If needed, add the growth neutrality correction for this component
if (growth)
{
growth_neutrality_param = create_aux_param(name_component + "_pac_growth_neutrality_correction");
auxdef = AddPlus(auxdef, AddTimes(growth, AddVariable(growth_neutrality_param)));
}
else
growth_neutrality_param = -1;
// Create the auxiliary variable for this component
int aux_id = symbol_table.addPacExpectationAuxiliaryVar(auxname, auxdef);
expr_t auxvar = AddVariable(aux_id);
// Add the equation defining the auxiliary variable for this component
expr_t neweq = AddEqual(auxvar, auxdef);
addEquation(neweq, -1);
addAuxEquation(neweq);
// Update the expression to be substituted for the pac_expectation operator
substexpr = AddPlus(substexpr, AddTimes(coeff, auxvar));
component_idx++;
}
pac_expectation_substitution[name] = substexpr;
}
void
DynamicModel::substitutePacExpectation(const map<string, expr_t> &pac_expectation_substitution,
const map<string, string> &pac_eq_name)
@ -4093,6 +4167,13 @@ DynamicModel::substitutePacExpectation(const map<string, expr_t> &pac_expectatio
}
}
void
DynamicModel::substitutePacTargetNonstationary(const string &pac_model_name, expr_t substexpr)
{
for (auto &eq : equations)
eq = dynamic_cast<BinaryOpNode *>(eq->substitutePacTargetNonstationary(pac_model_name, substexpr));
}
void
DynamicModel::computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsOrder,
const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll,
@ -6482,3 +6563,15 @@ DynamicModel::simplifyEquations()
findConstantEquationsWithoutMcpTag(subst_table);
}
}
void
DynamicModel::checkNoRemainingPacTargetNonstationary() const
{
for (size_t eq = 0; eq < equations.size(); eq++)
if (equations[eq]->containsPacTargetNonstationary())
{
cerr << "ERROR: in equation " << equation_tags.getTagValueByEqnAndKey(eq, "name")
<< ", the pac_target_nonstationary operator does not match a corresponding 'pac_target_info' block" << endl;
exit(EXIT_FAILURE);
}
}

View File

@ -582,10 +582,28 @@ public:
map<string, vector<int>> &pac_aux_param_symb_ids,
map<string, expr_t> &pac_expectation_substitution);
/* Same as above, but for PAC models which have an associated
pac_target_info.
Contrary to the above routine, this one will create the growth correction
parameters as needed.
Those parameter IDs, as well as the IDs for the h parameters, are stored
in target_components.
The routine also creates the auxiliary variables for the components, and
adds the corresponding equations. */
void computePacBackwardExpectationSubstitutionWithComponents(const string &name,
const vector<int> &lhs,
int max_lag,
const string &aux_model_type,
vector<PacModelTable::target_component_t> &pac_target_components,
map<string, expr_t> &pac_expectation_substitution);
//! Substitutes pac_expectation operator with expectation based on auxiliary model
void substitutePacExpectation(const map<string, expr_t> &pac_expectation_substitution,
const map<string, string> &pac_eq_name);
//! Substitutes the pac_target_nonstationary operator of a given pac_model
void substitutePacTargetNonstationary(const string &pac_model_name, expr_t substexpr);
//! Table to undiff LHS variables for pac vector z
vector<int> getUndiffLHSForPac(const string &aux_model_name,
const ExprNode::subst_table_t &diff_subst_table) const;
@ -605,6 +623,10 @@ public:
out otherwise */
void checkNoRemainingPacExpectation() const;
/*! Checks that all pac_target_nonstationary operators have been substituted, error
out otherwise */
void checkNoRemainingPacTargetNonstationary() const;
auto
getStaticOnlyEquationsInfo() const
{

View File

@ -174,6 +174,8 @@ class ParsingDriver;
%token RANDOM_FUNCTION_CONVERGENCE_CRITERION RANDOM_PARAMETER_CONVERGENCE_CRITERION NO_INIT_ESTIMATION_CHECK_FIRST_OBS
%token HETEROSKEDASTIC_FILTER TIME_SHIFT STRUCTURAL TERMINAL_STEADY_STATE_AS_GUESS_VALUE
%token SURPRISE OCCBIN_CONSTRAINTS
%token PAC_TARGET_INFO COMPONENT TARGET AUXNAME AUXNAME_TARGET_NONSTATIONARY PAC_TARGET_NONSTATIONARY
%token <string> KIND LL DL DD
/* Method of Moments */
%token METHOD_OF_MOMENTS MOM_METHOD
%token BARTLETT_KERNEL_LAG WEIGHTING_MATRIX WEIGHTING_MATRIX_SCALING_FACTOR ANALYTIC_STANDARD_ERRORS ANALYTIC_JACOBIAN PENALIZED_ESTIMATOR VERBOSE
@ -214,6 +216,7 @@ class ParsingDriver;
%type <vector<tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>>> occbin_constraints_regimes_list
%type <map<string, expr_t>> occbin_constraints_regime_options_list
%type <pair<string, expr_t>> occbin_constraints_regime_option
%type <PacTargetKind> pac_target_kind
%%
%start statement_list;
@ -348,6 +351,7 @@ statement : parameters
| model_replace
| model_options
| var_remove
| pac_target_info
;
dsample : DSAMPLE INT_NUMBER ';'
@ -945,6 +949,49 @@ occbin_constraints_regime_option : BIND hand_side ';'
{ $$ = { "error_relax", $2 }; }
;
pac_target_info : PAC_TARGET_INFO '(' symbol ')' ';'
{ driver.begin_pac_target_info($3); }
pac_target_info_statement_list
END ';'
{ driver.end_pac_target_info(); }
;
pac_target_info_statement_list : pac_target_info_statement
| pac_target_info_statement_list pac_target_info_statement
;
pac_target_info_statement : TARGET hand_side ';'
{ driver.set_pac_target_info_target($2); }
| AUXNAME_TARGET_NONSTATIONARY symbol ';'
{ driver.set_pac_target_info_auxname_target_nonstationary($2); }
| pac_target_info_component
;
pac_target_info_component : COMPONENT hand_side ';'
pac_target_info_component_list
{ driver.add_pac_target_info_component($2); }
;
pac_target_info_component_list : pac_target_info_component_elem
| pac_target_info_component_list pac_target_info_component_elem
;
pac_target_info_component_elem : GROWTH hand_side ';'
{ driver.set_pac_target_info_component_growth($2); }
| AUXNAME symbol ';'
{ driver.set_pac_target_info_component_auxname($2); }
| KIND pac_target_kind ';'
{ driver.set_pac_target_info_component_kind($2); }
;
pac_target_kind : LL
{ $$ = PacTargetKind::ll; }
| DL
{ $$ = PacTargetKind::dl; }
| DD
{ $$ = PacTargetKind::dd; }
;
/* The tokens below must be accepted in both DYNARE_STATEMENT and DYNARE_BLOCK
states in the lexer, because of model block and model_options statement */
model_option : BLOCK { driver.block(); }
@ -1036,6 +1083,8 @@ hand_side : '(' hand_side ')'
{ $$ = driver.add_var_expectation($3); }
| PAC_EXPECTATION '(' symbol ')'
{ $$ = driver.add_pac_expectation($3); }
| PAC_TARGET_NONSTATIONARY '(' symbol ')'
{ $$ = driver.add_pac_target_nonstationary($3); }
| MINUS hand_side %prec UNARY
{ $$ = driver.add_uminus($2); }
| PLUS hand_side %prec UNARY
@ -4301,6 +4350,10 @@ symbol : NAME
| RELAX
| ERROR_BIND
| ERROR_RELAX
| KIND
| LL
| DL
| DD
;
%%

View File

@ -236,6 +236,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<INITIAL>matched_moments {BEGIN DYNARE_BLOCK; return token::MATCHED_MOMENTS;}
<INITIAL>occbin_constraints {BEGIN DYNARE_BLOCK; return token::OCCBIN_CONSTRAINTS;}
<INITIAL>model_replace {BEGIN DYNARE_BLOCK; return token::MODEL_REPLACE;}
<INITIAL>pac_target_info {BEGIN DYNARE_BLOCK; return token::PAC_TARGET_INFO;}
/* For the semicolon after an "end" keyword */
<INITIAL>; {return Dynare::parser::token_type (yytext[0]);}
@ -684,7 +685,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>epilogue {return token::EPILOGUE;}
<DYNARE_STATEMENT>growth_factor {return token::GROWTH_FACTOR;}
<DYNARE_STATEMENT>log_growth_factor {return token::LOG_GROWTH_FACTOR;}
<DYNARE_STATEMENT>growth {return token::GROWTH;}
<DYNARE_STATEMENT,DYNARE_BLOCK>growth {return token::GROWTH;}
<DYNARE_STATEMENT>cova_compute {return token::COVA_COMPUTE;}
<DYNARE_STATEMENT>discretionary_tol {return token::DISCRETIONARY_TOL;}
<DYNARE_STATEMENT>analytic_derivation {return token::ANALYTIC_DERIVATION;}
@ -800,6 +801,27 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK># {return Dynare::parser::token_type (yytext[0]);}
<DYNARE_BLOCK>restriction {return token::RESTRICTION;}
<DYNARE_BLOCK>component {return token::COMPONENT;}
<DYNARE_BLOCK>target {return token::TARGET;}
<DYNARE_BLOCK>auxname {return token::AUXNAME;}
<DYNARE_BLOCK>auxname_target_nonstationary {return token::AUXNAME_TARGET_NONSTATIONARY;}
<DYNARE_BLOCK>kind {
yylval->build<string>(yytext);
return token::KIND;
}
<DYNARE_BLOCK>ll {
yylval->build<string>(yytext);
return token::LL;
}
<DYNARE_BLOCK>dl {
yylval->build<string>(yytext);
return token::DL;
}
<DYNARE_BLOCK>dd {
yylval->build<string>(yytext);
return token::DD;
}
/* Inside Dynare statement */
<DYNARE_STATEMENT>solve_algo {return token::SOLVE_ALGO;}
@ -945,6 +967,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT,DYNARE_BLOCK>expectation {return token::EXPECTATION;}
<DYNARE_BLOCK>var_expectation {return token::VAR_EXPECTATION;}
<DYNARE_BLOCK>pac_expectation {return token::PAC_EXPECTATION;}
<DYNARE_BLOCK>pac_target_nonstationary {return token::PAC_TARGET_NONSTATIONARY;}
<DYNARE_STATEMENT>discount {return token::DISCOUNT;}
<DYNARE_STATEMENT,DYNARE_BLOCK>varobs {return token::VAROBS;}
<DYNARE_STATEMENT,DYNARE_BLOCK>varexobs {return token::VAREXOBS;}

View File

@ -667,6 +667,12 @@ NumConstNode::substitutePacExpectation(const string &name, expr_t subexpr)
return const_cast<NumConstNode *>(this);
}
expr_t
NumConstNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
return const_cast<NumConstNode *>(this);
}
expr_t
NumConstNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
@ -694,6 +700,12 @@ NumConstNode::containsPacExpectation(const string &pac_model_name) const
return false;
}
bool
NumConstNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return false;
}
expr_t
NumConstNode::replaceTrendVar() const
{
@ -1588,6 +1600,15 @@ VariableNode::substitutePacExpectation(const string &name, expr_t subexpr)
return const_cast<VariableNode *>(this);
}
expr_t
VariableNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
if (get_type() == SymbolType::modelLocalVariable)
return datatree.getLocalVariable(symb_id)->substitutePacTargetNonstationary(name, subexpr);
return const_cast<VariableNode *>(this);
}
expr_t
VariableNode::decreaseLeadsLags(int n) const
{
@ -1820,6 +1841,15 @@ VariableNode::containsPacExpectation(const string &pac_model_name) const
return false;
}
bool
VariableNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
if (get_type() == SymbolType::modelLocalVariable)
return datatree.getLocalVariable(symb_id)->containsPacTargetNonstationary(pac_model_name);
return false;
}
expr_t
VariableNode::replaceTrendVar() const
{
@ -3538,6 +3568,13 @@ UnaryOpNode::substitutePacExpectation(const string &name, expr_t subexpr)
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
expr_t argsubst = arg->substitutePacTargetNonstationary(name, subexpr);
return buildSimilarUnaryOpNode(argsubst, datatree);
}
expr_t
UnaryOpNode::decreaseLeadsLags(int n) const
{
@ -3665,6 +3702,12 @@ UnaryOpNode::containsPacExpectation(const string &pac_model_name) const
return arg->containsPacExpectation(pac_model_name);
}
bool
UnaryOpNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return arg->containsPacTargetNonstationary(pac_model_name);
}
expr_t
UnaryOpNode::replaceTrendVar() const
{
@ -5086,6 +5129,14 @@ BinaryOpNode::substitutePacExpectation(const string &name, expr_t subexpr)
return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
}
expr_t
BinaryOpNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
expr_t arg1subst = arg1->substitutePacTargetNonstationary(name, subexpr);
expr_t arg2subst = arg2->substitutePacTargetNonstationary(name, subexpr);
return buildSimilarBinaryOpNode(arg1subst, arg2subst, datatree);
}
expr_t
BinaryOpNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
@ -5120,6 +5171,12 @@ BinaryOpNode::containsPacExpectation(const string &pac_model_name) const
return arg1->containsPacExpectation(pac_model_name) || arg2->containsPacExpectation(pac_model_name);
}
bool
BinaryOpNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return arg1->containsPacTargetNonstationary(pac_model_name) || arg2->containsPacTargetNonstationary(pac_model_name);
}
expr_t
BinaryOpNode::replaceTrendVar() const
{
@ -6341,6 +6398,15 @@ TrinaryOpNode::substitutePacExpectation(const string &name, expr_t subexpr)
return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
}
expr_t
TrinaryOpNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
expr_t arg1subst = arg1->substitutePacTargetNonstationary(name, subexpr);
expr_t arg2subst = arg2->substitutePacTargetNonstationary(name, subexpr);
expr_t arg3subst = arg3->substitutePacTargetNonstationary(name, subexpr);
return buildSimilarTrinaryOpNode(arg1subst, arg2subst, arg3subst, datatree);
}
expr_t
TrinaryOpNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
@ -6368,6 +6434,14 @@ TrinaryOpNode::containsPacExpectation(const string &pac_model_name) const
return (arg1->containsPacExpectation(pac_model_name) || arg2->containsPacExpectation(pac_model_name) || arg3->containsPacExpectation(pac_model_name));
}
bool
TrinaryOpNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return arg1->containsPacTargetNonstationary(pac_model_name)
|| arg2->containsPacTargetNonstationary(pac_model_name)
|| arg3->containsPacTargetNonstationary(pac_model_name);
}
expr_t
TrinaryOpNode::replaceTrendVar() const
{
@ -6741,6 +6815,15 @@ AbstractExternalFunctionNode::substitutePacExpectation(const string &name, expr_
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
}
expr_t
AbstractExternalFunctionNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
vector<expr_t> arguments_subst;
for (auto argument : arguments)
arguments_subst.push_back(argument->substitutePacTargetNonstationary(name, subexpr));
return buildSimilarExternalFunctionNode(arguments_subst, datatree);
}
expr_t
AbstractExternalFunctionNode::differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const
{
@ -6835,6 +6918,15 @@ AbstractExternalFunctionNode::containsPacExpectation(const string &pac_model_nam
return false;
}
bool
AbstractExternalFunctionNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
for (auto argument : arguments)
if (argument->containsPacTargetNonstationary(pac_model_name))
return true;
return false;
}
expr_t
AbstractExternalFunctionNode::replaceTrendVar() const
{
@ -8344,12 +8436,24 @@ VarExpectationNode::substitutePacExpectation(const string &name, expr_t subexpr)
return const_cast<VarExpectationNode *>(this);
}
expr_t
VarExpectationNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
return const_cast<VarExpectationNode *>(this);
}
bool
VarExpectationNode::containsPacExpectation(const string &pac_model_name) const
{
return false;
}
bool
VarExpectationNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return false;
}
void
VarExpectationNode::writeJsonAST(ostream &output) const
{
@ -8417,6 +8521,12 @@ PacExpectationNode::containsPacExpectation(const string &pac_model_name) const
return pac_model_name == model_name;
}
bool
PacExpectationNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
return false;
}
void
PacExpectationNode::writeJsonAST(ostream &output) const
{
@ -8443,6 +8553,99 @@ PacExpectationNode::substitutePacExpectation(const string &name, expr_t subexpr)
return subexpr;
}
expr_t
PacExpectationNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
return const_cast<PacExpectationNode *>(this);
}
PacTargetNonstationaryNode::PacTargetNonstationaryNode(DataTree &datatree_arg,
int idx_arg,
string model_name_arg) :
SubModelNode{datatree_arg, idx_arg, move(model_name_arg)}
{
}
expr_t
PacTargetNonstationaryNode::clone(DataTree &datatree) const
{
return datatree.AddPacTargetNonstationary(model_name);
}
void
PacTargetNonstationaryNode::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
{
assert(output_type != ExprNodeOutputType::matlabOutsideModel);
if (isLatexOutput(output_type))
{
output << "PAC_TARGET_NONSTATIONARY" << LEFT_PAR(output_type) << model_name << RIGHT_PAR(output_type);
return;
}
}
int
PacTargetNonstationaryNode::maxLagWithDiffsExpanded() const
{
// This node will be replaced by the target lagged by one
return 1;
}
expr_t
PacTargetNonstationaryNode::substituteVarExpectation(const map<string, expr_t> &subst_table) const
{
return const_cast<PacTargetNonstationaryNode *>(this);
}
bool
PacTargetNonstationaryNode::containsPacExpectation(const string &pac_model_name) const
{
return false;
}
bool
PacTargetNonstationaryNode::containsPacTargetNonstationary(const string &pac_model_name) const
{
if (pac_model_name.empty())
return true;
else
return pac_model_name == model_name;
}
void
PacTargetNonstationaryNode::writeJsonAST(ostream &output) const
{
output << R"({"node_type" : "PacTargetNonstationaryNode", )"
<< R"("name" : ")" << model_name << R"("})";
}
void
PacTargetNonstationaryNode::writeJsonOutput(ostream &output,
const temporary_terms_t &temporary_terms,
const deriv_node_temp_terms_t &tef_terms,
bool isdynamic) const
{
output << "pac_target_nonstationary("
<< "model_name = " << model_name
<< ")";
}
expr_t
PacTargetNonstationaryNode::substitutePacExpectation(const string &name, expr_t subexpr)
{
return const_cast<PacTargetNonstationaryNode *>(this);
}
expr_t
PacTargetNonstationaryNode::substitutePacTargetNonstationary(const string &name, expr_t subexpr)
{
if (model_name != name)
return const_cast<PacTargetNonstationaryNode *>(this);
return subexpr;
}
void
ExprNode::decomposeAdditiveTerms(vector<pair<expr_t, int>> &terms, int current_sign) const
{
@ -8649,6 +8852,8 @@ ExprNode::matchParamTimesTargetMinusVariable(int symb_id) const
if (datatree.symbol_table.isAuxiliaryVariable(target->symb_id))
{
auto avi = datatree.symbol_table.getAuxVarInfo(target->symb_id);
if (avi.get_type() == AuxVarType::pacTargetNonstationary && target->lag == -1)
return true;
return (avi.get_type() == AuxVarType::unaryOp
&& avi.get_unary_op() == "log"
&& avi.get_orig_symb_id() != -1
@ -8664,3 +8869,59 @@ ExprNode::matchParamTimesTargetMinusVariable(int symb_id) const
else
throw MatchFailureException{"Neither factor is of the form (target-variable) where target is endo or exo (possibly logged), and has one lag"};
}
pair<int, expr_t>
ExprNode::matchEndogenousTimesConstant() const
{
throw MatchFailureException{"This expression is not of the form endogenous*constant"};
}
pair<int, expr_t>
VariableNode::matchEndogenousTimesConstant() const
{
if (get_type() == SymbolType::endogenous)
return { symb_id, datatree.One };
else
throw MatchFailureException{"This expression is not of the form endogenous*constant"};
}
pair<int, expr_t>
BinaryOpNode::matchEndogenousTimesConstant() const
{
if (op_code == BinaryOpcode::times)
{
if (auto varg1 = dynamic_cast<VariableNode *>(arg1);
varg1 && varg1->get_type() == SymbolType::endogenous && arg2->isConstant())
return { varg1->symb_id, arg2 };
if (auto varg2 = dynamic_cast<VariableNode *>(arg2);
varg2 && varg2->get_type() == SymbolType::endogenous && arg1->isConstant())
return { varg2->symb_id, arg1 };
}
throw MatchFailureException{"This expression is not of the form endogenous*constant"};
}
pair<vector<pair<int, expr_t>>, expr_t>
ExprNode::matchLinearCombinationOfEndogenousWithConstant() const
{
vector<pair<expr_t, int>> all_terms;
decomposeAdditiveTerms(all_terms);
vector<pair<int, expr_t>> endo_terms;
expr_t intercept = datatree.Zero;
for (auto [term, sign] : all_terms)
if (term->isConstant())
{
if (sign == -1)
intercept = datatree.AddMinus(intercept, term);
else
intercept = datatree.AddPlus(intercept, term);
}
else
{
auto [endo_id, constant] = term->matchEndogenousTimesConstant();
if (sign == -1)
constant = datatree.AddUMinus(constant);
endo_terms.emplace_back(endo_id, constant);
}
return { endo_terms, intercept };
}

View File

@ -612,6 +612,9 @@ public:
//! Substitute pac_expectation operator
virtual expr_t substitutePacExpectation(const string &name, expr_t subexpr) = 0;
//! Substitute pac_target_nonstationary operator
virtual expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) = 0;
virtual int findTargetVariable(int lhs_symb_id) const = 0;
//! Add ExprNodes to the provided datatree
@ -626,7 +629,7 @@ public:
//! Substitute auxiliary variables by their expression in static model
virtual expr_t substituteStaticAuxiliaryVariable() const = 0;
//! Matches a linear combination of variables, where scalars can be constant*parameter
//! Matches a linear combination of variables (endo or exo), where scalars can be constant*parameter
/*! Returns a list of (variable_id, lag, param_id, constant)
corresponding to the terms in the expression. When there is no
parameter in a term, param_id == -1.
@ -638,6 +641,15 @@ public:
*/
vector<tuple<int, int, int, double>> matchLinearCombinationOfVariables(bool variable_obligatory_in_each_term = true) const;
/* Matches a linear combination of endogenous, where scalars can be any
constant expression (i.e. containing no endogenous, no exogenous and no
exogenous deterministic). The linear combination can contain constant
terms (intercept).
Returns a pair composed of:
the terms of the form endogenous*scalar, as a list of (endo_id, constant expr);
the sum of all constant (intercept) terms */
pair<vector<pair<int, expr_t>>, expr_t> matchLinearCombinationOfEndogenousWithConstant() const;
pair<int, vector<tuple<int, int, int, double>>> matchParamTimesLinearCombinationOfVariables() const;
/* Matches an expression of the form parameter*(var1-endo2).
@ -663,6 +675,9 @@ public:
//! Returns true if PacExpectationNode encountered
virtual bool containsPacExpectation(const string &pac_model_name = "") const = 0;
//! Returns true if PacTargetNonstationaryNode encountered
virtual bool containsPacTargetNonstationary(const string &pac_model_name = "") const = 0;
//! Decompose an expression into its additive terms
/*! Returns a list of terms, with their sign (either 1 or -1, depending
on whether the terms appears with a plus or a minus).
@ -691,7 +706,14 @@ public:
*/
tuple<int, int, int, double> matchVariableTimesConstantTimesParam(bool variable_obligatory = true) const;
//! Exception thrown by matchVariableTimesConstantTimesParam when matching fails
/* Matches an expression of the form endogenous*constant where constant is an
expression containing no endogenous, no exogenous and no exogenous deterministic.
Returns (endo_id, constant expr).
Note that it will also match a simple endogenous (in which case the
constant will of course be equal to one). */
virtual pair<int, expr_t> matchEndogenousTimesConstant() const;
//! Exception thrown when matching fails
class MatchFailureException
{
public:
@ -780,6 +802,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
bool isNumConstNodeEqualTo(double value) const override;
@ -792,6 +815,7 @@ public:
bool isInStaticForm() const override;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
bool isParamTimesEndogExpr() const override;
expr_t substituteStaticAuxiliaryVariable() const override;
};
@ -850,6 +874,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
bool isNumConstNodeEqualTo(double value) const override;
@ -862,10 +887,12 @@ public:
bool isInStaticForm() const override;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
bool isParamTimesEndogExpr() const override;
//! Substitute auxiliary variables by their expression in static model
expr_t substituteStaticAuxiliaryVariable() const override;
void matchMatchedMoment(vector<int> &symb_ids, vector<int> &lags, vector<int> &powers) const override;
pair<int, expr_t> matchEndogenousTimesConstant() const override;
};
//! Unary operator node
@ -951,6 +978,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
bool isNumConstNodeEqualTo(double value) const override;
@ -963,6 +991,7 @@ public:
bool isInStaticForm() const override;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
bool isParamTimesEndogExpr() const override;
//! Substitute auxiliary variables by their expression in static model
expr_t substituteStaticAuxiliaryVariable() const override;
@ -1056,6 +1085,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
bool isNumConstNodeEqualTo(double value) const override;
@ -1077,6 +1107,7 @@ public:
void findConstantEquations(map<VariableNode *, NumConstNode *> &table) const;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
/*
ec_params_and_vars:
- 1st element = feedback force parameter
@ -1108,6 +1139,7 @@ public:
void decomposeAdditiveTerms(vector<pair<expr_t, int>> &terms, int current_sign) const override;
void decomposeMultiplicativeFactors(vector<pair<expr_t, int>> &factors, int current_exponent = 1) const override;
void matchMatchedMoment(vector<int> &symb_ids, vector<int> &lags, vector<int> &powers) const override;
pair<int, expr_t> matchEndogenousTimesConstant() const override;
};
//! Trinary operator node
@ -1187,6 +1219,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
bool isNumConstNodeEqualTo(double value) const override;
@ -1199,6 +1232,7 @@ public:
bool isInStaticForm() const override;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
bool isParamTimesEndogExpr() const override;
//! Substitute auxiliary variables by their expression in static model
expr_t substituteStaticAuxiliaryVariable() const override;
@ -1294,6 +1328,7 @@ public:
expr_t substituteDiff(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
virtual expr_t buildSimilarExternalFunctionNode(vector<expr_t> &alt_args, DataTree &alt_datatree) const = 0;
expr_t decreaseLeadsLagsPredeterminedVariables() const override;
expr_t differentiateForwardVars(const vector<string> &subset, subst_table_t &subst_table, vector<BinaryOpNode *> &neweqs) const override;
@ -1308,6 +1343,7 @@ public:
bool isInStaticForm() const override;
expr_t replaceVarsInEquation(map<VariableNode *, NumConstNode *> &table) const override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
bool isParamTimesEndogExpr() const override;
//! Substitute auxiliary variables by their expression in static model
expr_t substituteStaticAuxiliaryVariable() const override;
@ -1498,7 +1534,9 @@ public:
int maxLagWithDiffsExpanded() const override;
expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
void writeJsonAST(ostream &output) const override;
void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, bool isdynamic) const override;
};
@ -1512,7 +1550,25 @@ public:
int maxLagWithDiffsExpanded() const override;
expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
void writeJsonAST(ostream &output) const override;
void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, bool isdynamic) const override;
};
class PacTargetNonstationaryNode : public SubModelNode
{
public:
PacTargetNonstationaryNode(DataTree &datatree_arg, int idx_arg, string model_name);
void 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 override;
expr_t clone(DataTree &datatree) const override;
int maxLagWithDiffsExpanded() const override;
expr_t substituteVarExpectation(const map<string, expr_t> &subst_table) const override;
expr_t substitutePacExpectation(const string &name, expr_t subexpr) override;
expr_t substitutePacTargetNonstationary(const string &name, expr_t subexpr) override;
bool containsPacExpectation(const string &pac_model_name = "") const override;
bool containsPacTargetNonstationary(const string &pac_model_name = "") const override;
void writeJsonAST(ostream &output) const override;
void writeJsonOutput(ostream &output, const temporary_terms_t &temporary_terms, const deriv_node_temp_terms_t &tef_terms, bool isdynamic) const override;
};

View File

@ -442,7 +442,9 @@ ModFile::transformPass(bool nostrict, bool stochastic, bool compute_xrefs, bool
original_model.fillVarModelTableFromOrigModel();
// PAC model
pac_model_table.transformPass(diff_subst_table, dynamic_model, var_model_table,
pac_model_table.transformPass(unary_ops_nodes, unary_ops_subst_table,
diff_nodes, diff_subst_table,
dynamic_model, var_model_table,
trend_component_model_table);
// Create auxiliary vars for Expectation operator
@ -1119,6 +1121,8 @@ ModFile::writeMOutput(const string &basename, bool clear_all, bool clear_global,
// Create epilogue file
epilogue.writeEpilogueFile(basename);
pac_model_table.writeTargetCoefficientsFile(basename);
}
cout << "done" << endl;

View File

@ -2047,3 +2047,12 @@ ModelTree::updateReverseVariableEquationOrderings()
eq_idx_orig2block[eq_idx_block2orig[i]] = i;
}
}
expr_t
ModelTree::getRHSFromLHS(expr_t lhs) const
{
for (auto eq : equations)
if (eq->arg1 == lhs)
return eq->arg2;
throw ExprNode::MatchFailureException{"Cannot find an equation with the requested LHS"};
}

View File

@ -444,6 +444,10 @@ public:
//! Helper for writing the Jacobian elements in MATLAB and C
/*! Writes either (i+1,j+1) or [i+j*no_eq] */
void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
/* Given an expression, searches for the first equation that has exactly this
expression on the LHS, and returns the RHS of that equation.
If no such equation can be found, throws an ExprNode::MatchFailureExpression */
expr_t getRHSFromLHS(expr_t lhs) const;
//! Returns all the equation tags associated to an equation
inline map<string, string>

View File

@ -2615,6 +2615,15 @@ ParsingDriver::add_pac_expectation(const string &model_name)
return data_tree->AddPacExpectation(model_name);
}
expr_t
ParsingDriver::add_pac_target_nonstationary(const string &model_name)
{
if (data_tree == occbin_constraints_tree.get())
error("The 'pac_target_nonstationary' operator is forbidden in 'occbin_constraints'.");
return data_tree->AddPacTargetNonstationary(model_name);
}
void
ParsingDriver::begin_pac_growth()
{
@ -3502,6 +3511,57 @@ ParsingDriver::end_occbin_constraints(const vector<tuple<string, BinaryOpNode *,
reset_data_tree();
}
void
ParsingDriver::begin_pac_target_info(string name)
{
pac_target_info_name = move(name);
set_current_data_tree(&mod_file->dynamic_model);
}
void
ParsingDriver::end_pac_target_info()
{
reset_data_tree();
}
void
ParsingDriver::set_pac_target_info_target(expr_t target)
{
mod_file->pac_model_table.setTargetExpr(pac_target_info_name, target);
}
void
ParsingDriver::set_pac_target_info_auxname_target_nonstationary(string auxname)
{
mod_file->pac_model_table.setTargetAuxnameNonstationary(pac_target_info_name, move(auxname));
}
void
ParsingDriver::add_pac_target_info_component(expr_t component_expr)
{
get<0>(pac_target_info_component) = component_expr;
mod_file->pac_model_table.addTargetComponent(pac_target_info_name, pac_target_info_component);
pac_target_info_component = {};
}
void
ParsingDriver::set_pac_target_info_component_growth(expr_t growth)
{
get<1>(pac_target_info_component) = growth;
}
void
ParsingDriver::set_pac_target_info_component_auxname(string auxname)
{
get<2>(pac_target_info_component) = move(auxname);
}
void
ParsingDriver::set_pac_target_info_component_kind(PacTargetKind kind)
{
get<3>(pac_target_info_component) = kind;
}
vector<string>
ParsingDriver::strsplit(const string &str, char delim)
{

View File

@ -249,6 +249,9 @@ private:
SymbolList graph_formats;
//! Temporary storage for equation tags
map<string, string> eq_tags;
// Temporary storages for pac_target_info
string pac_target_info_name;
PacModelTable::target_component_t pac_target_info_component;
//! The mod file representation constructed by this ParsingDriver
unique_ptr<ModFile> mod_file;
@ -741,6 +744,8 @@ public:
expr_t add_var_expectation(const string &model_name);
//! Writes token "PAC_EXPECTATION(model_name, discount, growth)" to model tree
expr_t add_pac_expectation(const string &model_name);
//! Adds a pac_target_nonstationary(model_name, discount, growth) node to model tree
expr_t add_pac_target_nonstationary(const string &model_name);
//! Creates pac_model statement
void begin_pac_growth();
void begin_pac_model();
@ -897,6 +902,14 @@ public:
void begin_model_replace(const vector<pair<string, string>> &listed_eqs_by_tags);
// Add a var_remove statement
void var_remove();
void begin_pac_target_info(string name);
void end_pac_target_info();
void set_pac_target_info_target(expr_t target);
void set_pac_target_info_auxname_target_nonstationary(string auxname);
void add_pac_target_info_component(expr_t component_expr);
void set_pac_target_info_component_growth(expr_t growth);
void set_pac_target_info_component_auxname(string auxname);
void set_pac_target_info_component_kind(PacTargetKind kind);
// Equivalent of MATLABs strsplit. Returns an empty vector given an empty string.
static vector<string> strsplit(const string &str, char delim);
// Returns true iff the string is a legal symbol identifier (see NAME token in lexer)

View File

@ -18,6 +18,7 @@
*/
#include <algorithm>
#include <cassert>
#include "SubModel.hh"
#include "DynamicModel.hh"
@ -791,7 +792,60 @@ PacModelTable::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation
{
for (auto &[name, gv] : growth)
if (gv)
gv->collectVariables(SymbolType::exogenous, mod_file_struct.pac_params);
{
if (target_info.find(name) != target_info.end())
{
cerr << "ERROR: for PAC model '" << name << "', it is not possible to declare a 'growth' option in the 'pac_model' command when there is also a 'pac_target_info' block" << endl;
exit(EXIT_FAILURE);
}
gv->collectVariables(SymbolType::exogenous, mod_file_struct.pac_params);
}
for (const auto &[name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
if (gv)
gv->collectVariables(SymbolType::exogenous, mod_file_struct.pac_params);
for (const auto &[name, ti] : target_info)
{
auto &[target, auxname_target_nonstationary, components] = ti;
if (!target)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'target' statement" << endl;
exit(EXIT_FAILURE);
}
if (auxname_target_nonstationary.empty())
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'auxname_target_nonstationary' statement" << endl;
exit(EXIT_FAILURE);
}
int nonstationary_nb = 0;
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
{
if (auxname.empty())
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'auxname' statement in some 'component'" << endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::unspecified)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is missing the 'kind' statement in some 'component'" << endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::ll && growth_component)
{
cerr << "ERROR: in the block 'pac_target_info(" << name << ")', a component of 'kind ll' (i.e. stationary) has a 'growth' option. This is not permitted." << endl;
exit(EXIT_FAILURE);
}
if (kind == PacTargetKind::dd || kind == PacTargetKind::dl)
nonstationary_nb++;
}
if (!nonstationary_nb)
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' must contain at least one nonstationary component (i.e. of 'kind' equal to either 'dd' or 'dl')." << endl;
exit(EXIT_FAILURE);
}
}
}
void
@ -800,6 +854,11 @@ PacModelTable::findDiffNodesInGrowth(lag_equivalence_table_t &diff_nodes) const
for (auto &[name, gv] : growth)
if (gv)
gv->findDiffNodes(diff_nodes);
for (const auto &[name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
if (gv)
gv->findDiffNodes(diff_nodes);
}
void
@ -808,10 +867,18 @@ PacModelTable::substituteDiffNodesInGrowth(const lag_equivalence_table_t &diff_n
for (auto &[name, gv] : growth)
if (gv)
gv = gv->substituteDiff(diff_nodes, diff_subst_table, neweqs);
for (auto &[name, ti] : target_info)
for (auto &[expr, gv, auxname, kind, coeff, growth_neutrality_param, h_indices, original_gv, gv_info] : get<2>(ti))
if (gv)
gv = gv->substituteDiff(diff_nodes, diff_subst_table, neweqs);
}
void
PacModelTable::transformPass(ExprNode::subst_table_t &diff_subst_table,
PacModelTable::transformPass(const lag_equivalence_table_t &unary_ops_nodes,
ExprNode::subst_table_t &unary_ops_subst_table,
const lag_equivalence_table_t &diff_nodes,
ExprNode::subst_table_t &diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
const TrendComponentModelTable &trend_component_model_table)
{
@ -834,6 +901,123 @@ PacModelTable::transformPass(ExprNode::subst_table_t &diff_subst_table,
exit(EXIT_FAILURE);
}
// Perform transformations for the pac_target_info block (if any)
if (target_info.find(name) != target_info.end())
{
// Substitute unary ops and diffs in the target…
expr_t &target = get<0>(target_info[name]);
vector<BinaryOpNode *> neweqs;
target = target->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the 'target' expression of 'pac_target_info(" << name << ")' contains a variable with a unary operator that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
target = target->substituteDiff(diff_nodes, diff_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: the 'target' expression of 'pac_target_info(" << name << ")' contains a diff'd variable that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
// …and in component expressions
auto &components = get<2>(target_info[name]);
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
{
component = component->substituteUnaryOpNodes(unary_ops_nodes, unary_ops_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name << ")' contains a variable with a unary operator that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
component = component->substituteDiff(diff_nodes, diff_subst_table, neweqs);
if (neweqs.size() > 0)
{
cerr << "ERROR: a 'component' expression of 'pac_target_info(" << name << ")' contains a diff'd variable that is not present in the model" << endl;
exit(EXIT_FAILURE);
}
}
/* Fill the growth_info structure.
Cannot be done in an earlier pass since growth terms can be
transformed by DynamicModel::substituteDiff(). */
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
{
if (growth_component)
try
{
growth_component_info = growth_component->matchLinearCombinationOfVariables(false);
}
catch (ExprNode::MatchFailureException &e)
{
cerr << "ERROR: PAC growth must be a linear combination of variables" << endl;
exit(EXIT_FAILURE);
}
}
// Identify the model equation defining the target
expr_t target_expr;
try
{
target_expr = dynamic_model.getRHSFromLHS(target);
}
catch (ExprNode::MatchFailureException)
{
cerr << "ERROR: there is no equation whose LHS is equal to the 'target' of 'pac_target_info(" << name << ")'" << endl;
exit(EXIT_FAILURE);
}
// Parse that model equation
vector<pair<int, expr_t>> terms;
expr_t constant;
try
{
tie(terms, constant) = target_expr->matchLinearCombinationOfEndogenousWithConstant();
}
catch (ExprNode::MatchFailureException)
{
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info(" << name << ")' is not of the right form (should be a linear combination of endogenous variables)" << endl;
exit(EXIT_FAILURE);
}
// Associate the coefficients of the linear combination with the right components
for (auto [var, coeff] : terms)
if (auto it = find_if(components.begin(), components.end(),
[&](const auto &v) { return get<0>(v) == dynamic_model.AddVariable(var); });
it != components.end())
get<4>(*it) = coeff;
else
{
cerr << "ERROR: the model equation defining the 'target' of 'pac_target_info(" << name << ")' contains a variable (" << symbol_table.getName(var) << ") that is not declared as a 'component'" << endl;
exit(EXIT_FAILURE);
}
// Verify that all declared components appear in that equation
for (const auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
if (!coeff)
{
cerr << "ERROR: a 'component' of 'pac_target_info(" << name << ")' does not appear in the model equation defining the 'target'" << endl;
exit(EXIT_FAILURE);
}
/* Add the variable and equation defining the stationary part of the
target. Note that it includes the constant. */
expr_t yns = constant;
for (const auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : components)
if (kind != PacTargetKind::ll)
yns = dynamic_model.AddPlus(yns, dynamic_model.AddTimes(coeff, component));
int target_nonstationary_id = symbol_table.addPacTargetNonstationaryAuxiliaryVar(get<1>(target_info[name]), yns);
expr_t neweq = dynamic_model.AddEqual(dynamic_model.AddVariable(target_nonstationary_id), yns);
dynamic_model.addEquation(neweq, -1);
dynamic_model.addAuxEquation(neweq);
/* Perform the substitution of the pac_target_nonstationary operator.
This needs to be done here, otherwise
DynamicModel::analyzePacEquationStructure() will not be able to
identify the error-correction part */
dynamic_model.substitutePacTargetNonstationary(name, dynamic_model.AddVariable(target_nonstationary_id, -1));
}
// Collect some information about PAC models
int max_lag;
if (trend_component_model_table.isExistingTrendComponentModelName(aux_model_name[name]))
@ -878,31 +1062,106 @@ PacModelTable::transformPass(ExprNode::subst_table_t &diff_subst_table,
if (growth[name])
growth_correction_term = dynamic_model.AddTimes(growth[name], dynamic_model.AddVariable(growth_neutrality_params[name]));
if (aux_model_name[name].empty())
dynamic_model.computePacModelConsistentExpectationSubstitution(name,
symbol_table.getID(discount[name]),
pacEquationMaxLag(name),
growth_correction_term,
diff_subst_table,
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
{
if (target_info.find(name) != target_info.end())
{
cerr << "ERROR: the block 'pac_target_info(" << name << ")' is not supported in the context of a PAC model with model-consistent expectations (MCE)." << endl;
exit(EXIT_FAILURE);
}
else
dynamic_model.computePacModelConsistentExpectationSubstitution(name,
symbol_table.getID(discount[name]),
pacEquationMaxLag(name),
growth_correction_term,
diff_subst_table,
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
}
else
dynamic_model.computePacBackwardExpectationSubstitution(name, lhs[name], max_lag,
aux_model_type[name],
growth_correction_term,
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
{
if (target_info.find(name) != target_info.end())
{
assert(growth_correction_term == dynamic_model.Zero);
dynamic_model.computePacBackwardExpectationSubstitutionWithComponents(name, lhs[name],
max_lag,
aux_model_type[name],
get<2>(target_info[name]),
pac_expectation_substitution);
}
else
dynamic_model.computePacBackwardExpectationSubstitution(name, lhs[name], max_lag,
aux_model_type[name],
growth_correction_term,
aux_var_symb_ids,
aux_param_symb_ids,
pac_expectation_substitution);
}
}
// Actually perform the substitution of pac_expectation
dynamic_model.substitutePacExpectation(pac_expectation_substitution, eq_name);
dynamic_model.checkNoRemainingPacExpectation();
// Check that there is no remaining pac_target_nonstationary operator
dynamic_model.checkNoRemainingPacTargetNonstationary();
}
void
PacModelTable::writeOutput(const string &basename, ostream &output) const
{
// Helper to print the “growth_info” structure (linear decomposition of growth)
auto growth_info_helper = [&](const string &fieldname, const growth_info_t &gi)
{
int i = 1;
for (auto [growth_symb_id, growth_lag, param_id, constant] : gi)
{
string structname = fieldname + "(" + to_string(i++) + ").";
if (growth_symb_id >= 0)
{
string var_field = "endo_id";
if (symbol_table.getType(growth_symb_id) == SymbolType::exogenous)
{
var_field = "exo_id";
output << structname << "endo_id = 0;" << endl;
}
else
output << structname << "exo_id = 0;" << endl;
try
{
// case when this is not the highest lag of the growth variable
int aux_symb_id = symbol_table.searchAuxiliaryVars(growth_symb_id, growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = 0;" << endl;
}
catch (...)
{
try
{
// case when this is the highest lag of the growth variable
int tmp_growth_lag = growth_lag + 1;
int aux_symb_id = symbol_table.searchAuxiliaryVars(growth_symb_id, tmp_growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = -1;" << endl;
}
catch (...)
{
// case when there is no aux var for the variable
output << structname << var_field << " = "<< symbol_table.getTypeSpecificID(growth_symb_id) + 1 << ";" << endl
<< structname << "lag = " << growth_lag << ";" << endl;
}
}
}
else
output << structname << "endo_id = 0;" << endl
<< structname << "exo_id = 0;" << endl
<< structname << "lag = 0;" << endl;
output << structname << "param_id = "
<< (param_id == -1 ? 0 : symbol_table.getTypeSpecificID(param_id) + 1) << ";" << endl
<< structname << "constant = " << constant << ";" << endl;
}
};
for (const auto &name : names)
{
output << "M_.pac." << name << ".auxiliary_model_name = '" << aux_model_name.at(name) << "';" << endl
@ -913,53 +1172,7 @@ PacModelTable::writeOutput(const string &basename, ostream &output) const
output << "M_.pac." << name << ".growth_str = '";
original_growth.at(name)->writeJsonOutput(output, {}, {}, true);
output << "';" << endl;
int i = 0;
for (auto [growth_symb_id, growth_lag, param_id, constant] : growth_info.at(name))
{
string structname = "M_.pac." + name + ".growth_linear_comb(" + to_string(++i) + ").";
if (growth_symb_id >= 0)
{
string var_field = "endo_id";
if (symbol_table.getType(growth_symb_id) == SymbolType::exogenous)
{
var_field = "exo_id";
output << structname << "endo_id = 0;" << endl;
}
else
output << structname << "exo_id = 0;" << endl;
try
{
// case when this is not the highest lag of the growth variable
int aux_symb_id = symbol_table.searchAuxiliaryVars(growth_symb_id, growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = 0;" << endl;
}
catch (...)
{
try
{
// case when this is the highest lag of the growth variable
int tmp_growth_lag = growth_lag + 1;
int aux_symb_id = symbol_table.searchAuxiliaryVars(growth_symb_id, tmp_growth_lag);
output << structname << var_field << " = " << symbol_table.getTypeSpecificID(aux_symb_id) + 1 << ";" << endl
<< structname << "lag = -1;" << endl;
}
catch (...)
{
// case when there is no aux var for the variable
output << structname << var_field << " = "<< symbol_table.getTypeSpecificID(growth_symb_id) + 1 << ";" << endl
<< structname << "lag = " << growth_lag << ";" << endl;
}
}
}
else
output << structname << "endo_id = 0;" << endl
<< structname << "exo_id = 0;" << endl
<< structname << "lag = 0;" << endl;
output << structname << "param_id = "
<< (param_id == -1 ? 0 : symbol_table.getTypeSpecificID(param_id) + 1) << ";" << endl
<< structname << "constant = " << constant << ";" << endl;
}
growth_info_helper("M_.pac." + name + ".growth_linear_comb", growth_info.at(name));
}
}
@ -1160,6 +1373,34 @@ PacModelTable::writeOutput(const string &basename, ostream &output) const
output << "];" << endl;
}
}
for (auto &[name, val] : target_info)
{
int component_idx = 1;
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
string fieldname = "M_.pac." + name + ".components(" + to_string(component_idx) + ")";
output << fieldname << ".aux_id = " << symbol_table.getTypeSpecificID(auxname) + 1 << ";" << endl
<< fieldname << ".endo_var = " << symbol_table.getTypeSpecificID(dynamic_cast<VariableNode *>(component)->symb_id) + 1 << ";" << endl
<< fieldname << ".kind = '" << kindToString(kind) << "';" << endl
<< fieldname << ".h_param_indices = [";
for (int id : h_indices)
output << symbol_table.getTypeSpecificID(id) + 1 << " ";
output << "];" << endl
<< fieldname << ".coeff_str = '";
coeff->writeJsonOutput(output, {}, {}, true);
output << "';" << endl;
if (growth_component)
{
output << fieldname << ".growth_neutrality_param_index = " << symbol_table.getTypeSpecificID(growth_neutrality_param) + 1 << ";" << endl
<< fieldname << ".growth_str = '";
original_growth_component->writeJsonOutput(output, {}, {}, true);
output << "';" << endl;
growth_info_helper(fieldname + ".growth_linear_comb", growth_component_info);
}
component_idx++;
}
}
}
void
@ -1167,6 +1408,8 @@ PacModelTable::writeJsonOutput(ostream &output) const
{
for (const auto &name : names)
{
/* The calling method has already added a comma, so dont output one for
the first statement */
if (name != *names.begin())
output << ", ";
output << R"({"statementName": "pac_model",)"
@ -1181,6 +1424,31 @@ PacModelTable::writeJsonOutput(ostream &output) const
}
output << "}" << endl;
}
for (auto &[name, val] : target_info)
{
output << R"(, {"statementName": "pac_target_info", "model_name": ")" << name
<< R"(", "target": ")";
get<0>(val)->writeJsonOutput(output, {}, {}, true);
output << R"(", "auxname_target_nonstationary": ")" << get<1>(val)
<< R"(", "components": [)";
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
if (component != get<0>(get<2>(val).front()))
output << ", ";
output << R"({"component": ")";
component->writeJsonOutput(output, {}, {}, true);
output << R"(", "auxname": ")" << auxname
<< R"(", "kind": ")" << kindToString(kind);
if (growth_component)
{
output << R"(", "growth_str": ")";
original_growth_component->writeJsonOutput(output, {}, {}, true);
}
output << R"("})";
}
output << "]}" << endl;
}
}
int
@ -1188,3 +1456,75 @@ PacModelTable::pacEquationMaxLag(const string &name_arg) const
{
return get<2>(equation_info.at(name_arg)).size();
}
string
PacModelTable::kindToString(PacTargetKind kind)
{
switch (kind)
{
case PacTargetKind::unspecified:
cerr << "Internal error: kind should not be unspecified" << endl;
exit(EXIT_FAILURE);
case PacTargetKind::ll:
return "ll";
case PacTargetKind::dl:
return "dl";
case PacTargetKind::dd:
return "dd";
}
// Silent GCC warning
assert(false);
}
void
PacModelTable::setTargetExpr(const string &name_arg, expr_t target)
{
get<0>(target_info[name_arg]) = target;
}
void
PacModelTable::setTargetAuxnameNonstationary(const string &name_arg, string auxname)
{
get<1>(target_info[name_arg]) = move(auxname);
}
void
PacModelTable::addTargetComponent(const string &name_arg, target_component_t component)
{
get<7>(component) = get<1>(component); // original_growth = growth
get<2>(target_info[name_arg]).emplace_back(move(component));
}
void
PacModelTable::writeTargetCoefficientsFile(const string &basename) const
{
if (target_info.empty())
return;
string filename = DataTree::packageDir(basename) + "/pac_target_coefficients.m";
ofstream output;
output.open(filename, ios::out | ios::binary);
if (!output.is_open())
{
cerr << "ERROR: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE);
}
output << "function coeffs = pac_target_coefficients(model_name, params)" << endl;
for (auto &[model_name, val] : target_info)
{
output << " if strcmp(model_name, '" << model_name << "')" << endl
<< " coeffs = NaN(" << get<2>(val).size() << ",1);" << endl;
int i = 1;
for (auto &[component, growth_component, auxname, kind, coeff, growth_neutrality_param, h_indices, original_growth_component, growth_component_info] : get<2>(val))
{
output << " coeffs(" << i++ << ") = ";
coeff->writeOutput(output, ExprNodeOutputType::matlabDynamicModel);
output << ";" << endl;
}
output << " return" << endl
<< " end" << endl;
}
output << " error([ 'Unknown PAC model: ' model_name ])" << endl
<< "end" << endl;
output.close();
}

View File

@ -197,12 +197,15 @@ private:
set<string> names;
map<string, string> aux_model_name;
map<string, string> discount;
// The growth expressions belong to the main dynamic_model from the ModFile instance
/* The growth expressions belong to the main dynamic_model from the ModFile
instance. The growth expression is necessarily nullptr for a model with a
pac_target_info block. */
map<string, expr_t> growth, original_growth;
/* Information about the structure of growth expressions (which must be a
linear combination of variables).
Each tuple represents a term: (endo_id, lag, param_id, constant) */
map<string, vector<tuple<int, int, int, double>>> growth_info;
using growth_info_t = vector<tuple<int, int, int, double>>;
map<string, growth_info_t> growth_info;
/* Stores the name of the PAC equation associated to the model.
pac_model_name eq_name */
@ -214,6 +217,8 @@ private:
pac_expectation value
- in the MCE case, this auxiliary represents Z (i.e. without the growth
correction term)
Note that this structure is not used in the presence of the
pac_target_info block.
pac_model_name symb_id */
map<string, int> aux_var_symb_ids;
/* Stores symb_ids for auxiliary parameters created for the expression
@ -221,10 +226,13 @@ private:
neutrality correction):
- in the backward case, contains the h parameters
- in the MCE case, contains the α parameters
Note that this structure is not used in the presence of the
pac_target_info block.
pac_model_name symb_ids */
map<string, vector<int>> aux_param_symb_ids;
/* Stores indices for growth neutrality parameters
pac_model_name growth_neutrality_param_index */
pac_model_name growth_neutrality_param_index.
This map is not used for PAC models with a pac_target_info block. */
map<string, int> growth_neutrality_params;
// Stores LHS vars (only for backward PAC models)
@ -243,8 +251,21 @@ public:
private:
equation_info_t equation_info;
public:
/* (component variable/expr, growth, auxname, kind, coeff. in the linear
combination, growth_param ID possibly equal to -1, vector of h parameters,
original_growth, growth_info) */
using target_component_t = tuple<expr_t, expr_t, string, PacTargetKind, expr_t, int, vector<int>, expr_t, growth_info_t>;
private:
// pac_model_name → (target variable/expr, auxname_target_nonstationary, target components)
map<string, tuple<expr_t, string, vector<target_component_t>>> target_info;
int pacEquationMaxLag(const string &name_arg) const;
// Return a text representation of a kind (but fails on “unspecified” kind value)
static string kindToString(PacTargetKind kind);
public:
explicit PacModelTable(SymbolTable &symbol_table_arg);
void addPacModel(string name_arg, string aux_model_name_arg, string discount_arg, expr_t growth_arg);
@ -255,11 +276,20 @@ public:
// Called by DynamicModel::substituteDiff()
void substituteDiffNodesInGrowth(const lag_equivalence_table_t &diff_nodes, ExprNode::subst_table_t &diff_subst_table, vector<BinaryOpNode *> &neweqs);
// Must be called after substituteDiffNodesInGrowth()
void transformPass(ExprNode::subst_table_t &diff_subst_table,
void transformPass(const lag_equivalence_table_t &unary_ops_nodes,
ExprNode::subst_table_t &unary_ops_subst_table,
const lag_equivalence_table_t &diff_nodes,
ExprNode::subst_table_t &diff_subst_table,
DynamicModel &dynamic_model, const VarModelTable &var_model_table,
const TrendComponentModelTable &trend_component_model_table);
void writeOutput(const string &basename, ostream &output) const;
void writeJsonOutput(ostream &output) const;
void setTargetExpr(const string &name_arg, expr_t target);
void setTargetAuxnameNonstationary(const string &name_arg, string auxname);
/* Only the first four elements of the tuple are expected to be set by the
caller. The other ones will be filled by this class. */
void addTargetComponent(const string &name_arg, target_component_t component);
void writeTargetCoefficientsFile(const string &basename) const;
};

View File

@ -377,6 +377,7 @@ SymbolTable::writeOutput(ostream &output) const noexcept(false)
break;
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
break;
case AuxVarType::diff:
case AuxVarType::diffLag:
@ -687,6 +688,24 @@ SymbolTable::addPacExpectationAuxiliaryVar(const string &name, expr_t expr_arg)
return symb_id;
}
int
SymbolTable::addPacTargetNonstationaryAuxiliaryVar(const string &name, expr_t expr_arg)
{
int symb_id;
try
{
symb_id = addSymbol(name, SymbolType::endogenous);
}
catch (AlreadyDeclaredException &e)
{
cerr << "ERROR: the variable/parameter '" << name << "' conflicts with a variable that will be generated for a 'pac_target_nonstationary' expression. Please rename it." << endl;
exit(EXIT_FAILURE);
}
aux_vars.emplace_back(symb_id, AuxVarType::pacTargetNonstationary, 0, 0, 0, 0, expr_arg, "");
return symb_id;
}
int
SymbolTable::searchAuxiliaryVars(int orig_symb_id, int orig_lead_lag) const noexcept(false)
{
@ -1004,6 +1023,7 @@ SymbolTable::writeJsonOutput(ostream &output) const
break;
case AuxVarType::expectation:
case AuxVarType::pacExpectation:
case AuxVarType::pacTargetNonstationary:
break;
case AuxVarType::diff:
case AuxVarType::diffLag:

View File

@ -53,7 +53,8 @@ enum class AuxVarType
diffLag = 9, //!< Variable for timing between Diff operators (lag)
unaryOp = 10, //!< Variable for allowing the undiff operator to work when diff was taken of unary op, eg diff(log(x))
diffLead = 11, //!< Variable for timing between Diff operators (lead)
pacExpectation = 12 //!< Variable created for the substitution of the pac_expectation operator
pacExpectation = 12, //!< Variable created for the substitution of the pac_expectation operator
pacTargetNonstationary = 13 //!< Variable created for the substitution of the pac_target_nonstationary operator
};
//! Information on some auxiliary variables
@ -337,6 +338,8 @@ public:
int addUnaryOpAuxiliaryVar(int index, expr_t expr_arg, string unary_op, int orig_symb_id = -1, int orig_lag = 0) noexcept(false);
//! An auxiliary variable for a pac_expectation operator
int addPacExpectationAuxiliaryVar(const string &name, expr_t expr_arg);
//! An auxiliary variable for a pac_target_nonstationary operator
int addPacTargetNonstationaryAuxiliaryVar(const string &name, expr_t expr_arg);
//! Returns the number of auxiliary variables
int
AuxVarsSize() const