New “add” and “multiply” keywords in “shocks(learnt_in=…)” block

fix-tolerance-parameters
Sébastien Villemot 2022-04-26 15:21:45 +02:00
parent dbe14ecfd4
commit 76a16a69a8
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
6 changed files with 135 additions and 18 deletions

View File

@ -175,7 +175,7 @@ class ParsingDriver;
%token HETEROSKEDASTIC_FILTER TIME_SHIFT STRUCTURAL TERMINAL_STEADY_STATE_AS_GUESS_VALUE CONSTANT_SIMULATION_LENGTH
%token SURPRISE OCCBIN_CONSTRAINTS
%token PAC_TARGET_INFO COMPONENT TARGET AUXNAME AUXNAME_TARGET_NONSTATIONARY PAC_TARGET_NONSTATIONARY
%token <string> KIND LL DL DD
%token <string> KIND LL DL DD ADD MULTIPLY
/* 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
@ -1152,7 +1152,11 @@ shock_elem : det_shock_elem
;
det_shock_elem : VAR symbol ';' PERIODS period_list ';' VALUES value_list ';'
{ driver.add_det_shock($2, $5, $8, false); }
{ driver.add_det_shock($2, $5, $8, ParsingDriver::DetShockType::standard); }
| VAR symbol ';' PERIODS period_list ';' ADD value_list ';'
{ driver.add_det_shock($2, $5, $8, ParsingDriver::DetShockType::add); }
| VAR symbol ';' PERIODS period_list ';' MULTIPLY value_list ';'
{ driver.add_det_shock($2, $5, $8, ParsingDriver::DetShockType::multiply); }
;
det_shock_list : det_shock_list det_shock_elem
@ -3207,7 +3211,7 @@ conditional_forecast_paths_shock_list : conditional_forecast_paths_shock_elem
;
conditional_forecast_paths_shock_elem : VAR symbol ';' PERIODS period_list ';' VALUES value_list ';'
{ driver.add_det_shock($2, $5, $8, true); }
{ driver.add_det_shock($2, $5, $8, ParsingDriver::DetShockType::conditional_forecast); }
;
steady_state_model : STEADY_STATE_MODEL ';' { driver.begin_steady_state_model(); }
@ -4284,6 +4288,8 @@ symbol : NAME
| LL
| DL
| DD
| ADD
| MULTIPLY
;
%%

View File

@ -770,6 +770,14 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK>corr {return token::CORR;}
<DYNARE_BLOCK>periods {return token::PERIODS;}
<DYNARE_BLOCK>scales {return token::SCALES;}
<DYNARE_BLOCK>add {
yylval->build<string>(yytext);
return token::ADD;
}
<DYNARE_BLOCK>multiply {
yylval->build<string>(yytext);
return token::MULTIPLY;
}
<DYNARE_STATEMENT,DYNARE_BLOCK>cutoff {return token::CUTOFF;}
<DYNARE_STATEMENT,DYNARE_BLOCK>mfs {return token::MFS;}
<DYNARE_STATEMENT,DYNARE_BLOCK>balanced_growth_test_tol {return token::BALANCED_GROWTH_TEST_TOL;}

View File

@ -841,6 +841,10 @@ ParsingDriver::end_shocks(bool overwrite)
mod_file->addStatement(make_unique<ShocksStatement>(overwrite, det_shocks, var_shocks, std_shocks,
covar_shocks, corr_shocks, mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("shocks: 'add' keyword not allowed unless 'learnt_in' option is passed");
if (!learnt_shocks_multiply.empty())
error("shocks: 'multiply' keyword not allowed unless 'learnt_in' option is passed");
var_shocks.clear();
std_shocks.clear();
covar_shocks.clear();
@ -852,6 +856,10 @@ ParsingDriver::end_mshocks(bool overwrite)
{
mod_file->addStatement(make_unique<MShocksStatement>(overwrite, det_shocks, mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("mshocks: 'add' keyword not allowed");
if (!learnt_shocks_multiply.empty())
error("mshocks: 'multiply' keyword not allowed");
}
void
@ -859,6 +867,10 @@ ParsingDriver::end_shocks_surprise(bool overwrite)
{
mod_file->addStatement(make_unique<ShocksSurpriseStatement>(overwrite, det_shocks, mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("shocks(surprise): 'add' keyword not allowed");
if (!learnt_shocks_multiply.empty())
error("shocks(surprise): 'multiply' keyword not allowed");
}
void
@ -871,8 +883,35 @@ ParsingDriver::end_shocks_learnt_in(const string &learnt_in_period, bool overwri
for (auto [period1, period2, expr] : vals)
if (period1 < learnt_in_period_int)
error("shocks: for variable " + mod_file->symbol_table.getName(symb_id) + ", shock period (" + to_string(period1) + ") is earlier than the period in which the shock is learnt (" + learnt_in_period + ")");
mod_file->addStatement(make_unique<ShocksLearntInStatement>(learnt_in_period_int, overwrite, det_shocks, mod_file->symbol_table));
// Aggregate the three types of shocks
ShocksLearntInStatement::learnt_shocks_t learnt_shocks;
for (const auto &[id, v] : det_shocks)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::level, period1, period2, value);
learnt_shocks[id] = v2;
}
for (const auto &[id, v] : learnt_shocks_add)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::add, period1, period2, value);
learnt_shocks[id] = v2;
}
for (const auto &[id, v] : learnt_shocks_multiply)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiply, period1, period2, value);
learnt_shocks[id] = v2;
}
mod_file->addStatement(make_unique<ShocksLearntInStatement>(learnt_in_period_int, overwrite, learnt_shocks, mod_file->symbol_table));
det_shocks.clear();
learnt_shocks_add.clear();
learnt_shocks_multiply.clear();
}
void
@ -885,16 +924,28 @@ ParsingDriver::end_heteroskedastic_shocks(bool overwrite)
}
void
ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool conditional_forecast)
ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, DetShockType type)
{
if (conditional_forecast)
check_symbol_is_endogenous(var);
else
check_symbol_is_exogenous(var, true);
switch (type)
{
case DetShockType::conditional_forecast:
check_symbol_is_endogenous(var);
break;
case DetShockType::standard:
// Allow exo_det, for stochastic context
check_symbol_is_exogenous(var, true);
break;
case DetShockType::add:
case DetShockType::multiply:
check_symbol_is_exogenous(var, false);
break;
}
int symb_id = mod_file->symbol_table.getID(var);
if (det_shocks.find(symb_id) != det_shocks.end())
if (det_shocks.find(symb_id) != det_shocks.end()
|| learnt_shocks_add.find(symb_id) != learnt_shocks_add.end()
|| learnt_shocks_multiply.find(symb_id) != learnt_shocks_multiply.end())
error("shocks/conditional_forecast_paths: variable " + var + " declared twice");
if (periods.size() != values.size())
@ -905,7 +956,19 @@ ParsingDriver::add_det_shock(const string &var, const vector<pair<int, int>> &pe
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i].first, periods[i].second, values[i]);
det_shocks[symb_id] = v;
switch (type)
{
case DetShockType::standard:
case DetShockType::conditional_forecast:
det_shocks[symb_id] = v;
break;
case DetShockType::add:
learnt_shocks_add[symb_id] = v;
break;
case DetShockType::multiply:
learnt_shocks_multiply[symb_id] = v;
break;
}
}
void
@ -2435,6 +2498,10 @@ ParsingDriver::conditional_forecast_paths()
{
mod_file->addStatement(make_unique<ConditionalForecastPathsStatement>(det_shocks, mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("conditional_forecast_paths: 'add' keyword not allowed");
if (!learnt_shocks_multiply.empty())
error("conditional_forecast_paths: 'multiply' keyword not allowed");
}
void

View File

@ -150,8 +150,11 @@ private:
//! Temporary storage of covariances from optim_weights
OptimWeightsStatement::covar_weights_t covar_weights;
/* Temporary storage for deterministic shocks. Also used for
conditional_forecast paths and for surprise shocks. */
conditional_forecast paths, for shocks(surprise), and shocks(learnt_in=)
(for the latter, only used for shocks declared in level through values). */
ShocksStatement::det_shocks_t det_shocks;
// Temporary storage for shocks declared with “add” and “multiply” in shocks(learnt_in=…)
ShocksStatement::det_shocks_t learnt_shocks_add, learnt_shocks_multiply;
//! Temporary storage for variances of shocks
ShocksStatement::var_and_std_shocks_t var_shocks;
//! Temporary storage for standard errors of shocks
@ -455,7 +458,14 @@ public:
void end_heteroskedastic_shocks(bool overwrite);
/* Adds a deterministic shock, a path element inside a
conditional_forecast_paths block, or a surprise shock */
void add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool conditional_forecast);
enum class DetShockType
{
standard,
add, // for “add” in “shocks(learnt_in)”
multiply, // for “multiply” in “shocks(learnt_in)”
conditional_forecast
};
void add_det_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, DetShockType type);
//! Adds a heteroskedastic shock (either values or scales)
void add_heteroskedastic_shock(const string &var, const vector<pair<int, int>> &periods, const vector<expr_t> &values, bool scales);
//! Adds a std error shock

View File

@ -492,7 +492,7 @@ ShocksSurpriseStatement::writeJsonOutput(ostream &output) const
}
ShocksLearntInStatement::ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
AbstractShocksStatement::det_shocks_t learnt_shocks_arg,
learnt_shocks_t learnt_shocks_arg,
const SymbolTable &symbol_table_arg) :
learnt_in_period{learnt_in_period_arg}, overwrite{overwrite_arg},
learnt_shocks{move(learnt_shocks_arg)}, symbol_table{symbol_table_arg}
@ -505,6 +505,21 @@ ShocksLearntInStatement::checkPass(ModFileStructure &mod_file_struct, WarningCon
mod_file_struct.shocks_learnt_in_present = true;
}
string
ShocksLearntInStatement::typeToString(LearntShockType type)
{
switch (type)
{
case LearntShockType::level:
return "level";
case LearntShockType::add:
return "add";
case LearntShockType::multiply:
return "multiply";
}
exit(EXIT_FAILURE); // Silence GCC warning
}
void
ShocksLearntInStatement::writeOutput(ostream &output, const string &basename, bool minimal_workspace) const
{
@ -516,11 +531,12 @@ ShocksLearntInStatement::writeOutput(ostream &output, const string &basename, bo
output << "M_.learnt_shocks = [ M_.learnt_shocks;" << endl;
for (const auto &[id, shock_vec] : learnt_shocks)
{
for (const auto &[period1, period2, value] : shock_vec)
for (const auto &[type, period1, period2, value] : shock_vec)
{
output << "struct('learnt_in'," << learnt_in_period
<< ",'exo_id'," << symbol_table.getTypeSpecificID(id)+1
<< ",'periods'," << period1 << ":" << period2
<< ",'type','" << typeToString(type) << "'"
<< ",'value',";
value->writeOutput(output);
output << ");" << endl;
@ -544,11 +560,12 @@ ShocksLearntInStatement::writeJsonOutput(ostream &output) const
<< R"("values": [)";
for (auto it1 = it->second.begin(); it1 != it->second.end(); ++it1)
{
auto [period1, period2, value] = *it1;
auto [type, period1, period2, value] = *it1;
if (it1 != it->second.begin())
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("type": ")" << typeToString(type) << R"(", )"
<< R"("value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";

View File

@ -115,12 +115,21 @@ public:
const int learnt_in_period;
//! Does this "shocks(learnt_in=…)" statement replace the previous ones?
const bool overwrite;
const AbstractShocksStatement::det_shocks_t learnt_shocks;
enum class LearntShockType
{
level,
add,
multiply
};
// The tuple is (type, period1, period2, value)
using learnt_shocks_t = map<int, vector<tuple<LearntShockType, int, int, expr_t>>>;
const learnt_shocks_t learnt_shocks;
private:
const SymbolTable &symbol_table;
static string typeToString(LearntShockType type);
public:
ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
AbstractShocksStatement::det_shocks_t learnt_shocks_arg,
learnt_shocks_t learnt_shocks_arg,
const SymbolTable &symbol_table_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override;