diff --git a/src/ComputingTasks.cc b/src/ComputingTasks.cc index 78702e21bae627e11fef7e7fae5405e2c6fbac5f..7d781ef45322a679f9f47cca7a38d06e5f5923a9 100644 --- a/src/ComputingTasks.cc +++ b/src/ComputingTasks.cc @@ -63,7 +63,7 @@ void SteadyStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "steady")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -95,7 +95,7 @@ void CheckStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "check")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -120,7 +120,7 @@ void ModelInfoStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "model_info")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -146,14 +146,13 @@ SimulStatement::writeOutput(ostream &output, [[maybe_unused]] const string &base { // Translate the “datafile” option into “initval_file” (see dynare#1663) auto options_list_new = options_list; // Need a copy, because of const - if (auto it = options_list_new.string_options.find("datafile"); - it != options_list_new.string_options.end()) + if (auto opt = options_list_new.get_if<OptionsList::StringVal>("datafile")) { output << "options_.initval_file = true;" << endl << "options_initvalf = struct();" << endl - << "options_initvalf.datafile = '" << it->second << "';" << endl + << "options_initvalf.datafile = '" << *opt << "';" << endl << "oo_.initval_series = histvalf_initvalf('INITVALF', M_, options_initvalf);" << endl; - options_list_new.string_options.erase(it); + options_list_new.erase("datafile"); } options_list_new.writeOutput(output); output << "perfect_foresight_setup;" << endl @@ -164,7 +163,7 @@ void SimulStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "simul")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -182,14 +181,13 @@ PerfectForesightSetupStatement::writeOutput(ostream &output, [[maybe_unused]] co [[maybe_unused]] bool minimal_workspace) const { auto options_list_new = options_list; // Need a copy, because of const - if (auto it = options_list_new.string_options.find("datafile"); - it != options_list_new.string_options.end()) + if (auto opt = options_list_new.get_if<OptionsList::StringVal>("datafile")) { output << "options_.initval_file = true;" << endl << "options_initvalf = struct();" << endl - << "options_initvalf.datafile = '" << it->second << "';" << endl + << "options_initvalf.datafile = '" << *opt << "';" << endl << "oo_.initval_series = histvalf_initvalf('INITVALF', M_, options_initvalf);" << endl; - options_list_new.string_options.erase(it); + options_list_new.erase("datafile"); } options_list_new.writeOutput(output); output << "perfect_foresight_setup;" << endl; @@ -199,7 +197,7 @@ void PerfectForesightSetupStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "perfect_foresight_setup")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -231,7 +229,7 @@ void PerfectForesightSolverStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "perfect_foresight_solver")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -257,7 +255,7 @@ void PerfectForesightWithExpectationErrorsSetupStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "perfect_foresight_with_expectation_errors_setup")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -290,7 +288,7 @@ void PerfectForesightWithExpectationErrorsSolverStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "perfect_foresight_with_expectation_errors_solver")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -309,10 +307,10 @@ void PriorPosteriorFunctionStatement::checkPass([[maybe_unused]] ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings) { - if (auto it2 = options_list.string_options.find("function"); - it2 == options_list.string_options.end() || it2->second.empty()) + if (auto opt = options_list.get_if<OptionsList::StringVal>("function"); + !opt || opt->empty()) { - cerr << "ERROR: both the prior_function and posterior_function commands require the 'function' argument" + cerr << "ERROR: both the 'prior_function' and 'posterior_function' commands require the 'function' option" << endl; exit(EXIT_FAILURE); } @@ -326,7 +324,7 @@ PriorPosteriorFunctionStatement::writeOutput(ostream &output, [[maybe_unused]] c string type = prior_func ? "prior" : "posterior"; output << "oo_ = execute_prior_posterior_function(" - << "'" << options_list.string_options.find("function")->second << "', " + << "'" << options_list.get<OptionsList::StringVal>("function") << "', " << "M_, options_, oo_, estim_params_, bayestopt_, dataset_, dataset_info, " << "'" << type << "');" << endl; } @@ -336,7 +334,7 @@ PriorPosteriorFunctionStatement::writeJsonOutput(ostream &output) const { string type = prior_func ? "prior" : "posterior"; output << R"({"statementName": "prior_posterior_function", "type": ")" << type << R"(")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -358,24 +356,22 @@ StochSimulStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsoli mod_file_struct.stoch_simul_present = true; // Fill in option_order of mod_file_struct - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) - mod_file_struct.order_option = max(mod_file_struct.order_option, stoi(it->second)); + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) + mod_file_struct.order_option = max(mod_file_struct.order_option, stoi(*opt)); // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Option k_order_solver (implicit when order >= 3) - if (auto it = options_list.num_options.find("k_order_solver"); - (it != options_list.num_options.end() && it->second == "true") - || mod_file_struct.order_option >= 3) + if (auto opt = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt && *opt == "true") || mod_file_struct.order_option >= 3) mod_file_struct.k_order_solver = true; - if (bool hp = options_list.num_options.contains("hp_filter"), - bandpass = options_list.num_options.contains("bandpass.indicator"), - one_sided_hp = options_list.num_options.contains("one_sided_hp_filter"); + if (bool hp = options_list.contains("hp_filter"), + bandpass = options_list.contains("bandpass.indicator"), + one_sided_hp = options_list.contains("one_sided_hp_filter"); (hp && bandpass) || (hp && one_sided_hp) || (bandpass && one_sided_hp)) { cerr << "ERROR: stoch_simul: can only use one of hp, one-sided hp, and bandpass filters" @@ -399,10 +395,9 @@ StochSimulStatement::writeOutput(ostream &output, [[maybe_unused]] const string [[maybe_unused]] bool minimal_workspace) const { // Ensure that order 3 implies k_order (#844) - if (auto it = options_list.num_options.find("order"), - it1 = options_list.num_options.find("k_order_solver"); - (it1 != options_list.num_options.end() && it1->second == "true") - || (it != options_list.num_options.end() && stoi(it->second) >= 3)) + if (auto opt1 = options_list.get_if<OptionsList::NumVal>("order"), + opt2 = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt2 && *opt2 == "true") || (opt1 && stoi(*opt1) >= 3)) output << "options_.k_order_solver = true;" << endl; options_list.writeOutput(output); @@ -414,7 +409,7 @@ void StochSimulStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "stoch_simul")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -463,7 +458,7 @@ void ForecastStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "forecast")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -490,10 +485,9 @@ RamseyModelStatement::checkPass(ModFileStructure &mod_file_struct, /* Fill in option_order of mod_file_struct Since ramsey model needs one further order of derivation (for example, for 1st order approximation, it needs 2nd derivatives), we add 1 to the order declared by user */ - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order > 2) { cerr << "ERROR: ramsey_model: order > 2 is not implemented" << endl; @@ -503,20 +497,18 @@ RamseyModelStatement::checkPass(ModFileStructure &mod_file_struct, } // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Option k_order_solver (implicit when order >= 3) - if (auto it = options_list.num_options.find("k_order_solver"); - (it != options_list.num_options.end() && it->second == "true") - || mod_file_struct.order_option >= 3) + if (auto opt = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt && *opt == "true") || mod_file_struct.order_option >= 3) mod_file_struct.k_order_solver = true; // Fill list of instruments - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - mod_file_struct.instruments = it->second; + if (auto opt = options_list.get_if<OptionsList::SymbolListVal>("instruments")) + mod_file_struct.instruments = *opt; } void @@ -528,10 +520,9 @@ RamseyModelStatement::writeOutput(ostream &output, [[maybe_unused]] const string // It should probably rather be a M_ field, but we leave it in options_ for historical reason // Ensure that order 3 implies k_order (#844) - if (auto it = options_list.num_options.find("order"), - it1 = options_list.num_options.find("k_order_solver"); - (it1 != options_list.num_options.end() && it1->second == "true") - || (it != options_list.num_options.end() && stoi(it->second) >= 3)) + if (auto opt1 = options_list.get_if<OptionsList::NumVal>("order"), + opt2 = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt2 && *opt2 == "true") || (opt1 && stoi(*opt1) >= 3)) output << "options_.k_order_solver = true;" << endl; output << "options_.ramsey_policy = true;" << endl; @@ -542,7 +533,7 @@ void RamseyModelStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ramsey_model")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -657,10 +648,9 @@ RamseyPolicyStatement::checkPass(ModFileStructure &mod_file_struct, WarningConso /* Fill in option_order of mod_file_struct Since ramsey policy needs one further order of derivation (for example, for 1st order approximation, it needs 2nd derivatives), we add 1 to the order declared by user */ - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order > 2) { cerr << "ERROR: ramsey_policy: order > 2 is not implemented" << endl; @@ -670,20 +660,18 @@ RamseyPolicyStatement::checkPass(ModFileStructure &mod_file_struct, WarningConso } // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Option k_order_solver (implicit when order >= 3) - if (auto it = options_list.num_options.find("k_order_solver"); - (it != options_list.num_options.end() && it->second == "true") - || mod_file_struct.order_option >= 3) + if (auto opt = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt && *opt == "true") || mod_file_struct.order_option >= 3) mod_file_struct.k_order_solver = true; // Fill list of instruments - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - mod_file_struct.instruments = it->second; + if (auto opt = options_list.get_if<OptionsList::SymbolListVal>("instruments")) + mod_file_struct.instruments = *opt; try { @@ -701,10 +689,9 @@ RamseyPolicyStatement::writeOutput(ostream &output, [[maybe_unused]] const strin [[maybe_unused]] bool minimal_workspace) const { // Ensure that order 3 implies k_order (#844) - if (auto it = options_list.num_options.find("order"), - it1 = options_list.num_options.find("k_order_solver"); - (it1 != options_list.num_options.end() && it1->second == "true") - || (it != options_list.num_options.end() && stoi(it->second) >= 3)) + if (auto opt1 = options_list.get_if<OptionsList::NumVal>("order"), + opt2 = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt2 && *opt2 == "true") || (opt1 && stoi(*opt1) >= 3)) output << "options_.k_order_solver = true;" << endl; options_list.writeOutput(output); @@ -716,7 +703,7 @@ void RamseyPolicyStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ramsey_policy")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -746,7 +733,7 @@ EvaluatePlannerObjectiveStatement::writeOutput(ostream &output, void EvaluatePlannerObjectiveStatement::writeJsonOutput(ostream &output) const { - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -768,7 +755,7 @@ DiscretionaryPolicyStatement::checkPass(ModFileStructure &mod_file_struct, Warni { mod_file_struct.discretionary_policy_present = true; - if (!options_list.symbol_list_options.contains("instruments")) + if (!options_list.contains("instruments")) { cerr << "ERROR: discretionary_policy: the instruments option is required." << endl; exit(EXIT_FAILURE); @@ -777,10 +764,9 @@ DiscretionaryPolicyStatement::checkPass(ModFileStructure &mod_file_struct, Warni /* Fill in option_order of mod_file_struct Since discretionary policy needs one further order of derivation (for example, for 1st order approximation, it needs 2nd derivatives), we add 1 to the order declared by user */ - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order > 1) { cerr << "ERROR: discretionary_policy: order > 1 is not yet implemented" << endl; @@ -790,20 +776,18 @@ DiscretionaryPolicyStatement::checkPass(ModFileStructure &mod_file_struct, Warni } // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Option k_order_solver (implicit when order >= 3) - if (auto it = options_list.num_options.find("k_order_solver"); - (it != options_list.num_options.end() && it->second == "true") - || mod_file_struct.order_option >= 3) + if (auto opt = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt && *opt == "true") || mod_file_struct.order_option >= 3) mod_file_struct.k_order_solver = true; // Fill list of instruments - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - mod_file_struct.instruments = it->second; + if (auto opt = options_list.get_if<OptionsList::SymbolListVal>("instruments")) + mod_file_struct.instruments = *opt; try { @@ -821,10 +805,9 @@ DiscretionaryPolicyStatement::writeOutput(ostream &output, [[maybe_unused]] cons [[maybe_unused]] bool minimal_workspace) const { // Ensure that order 3 implies k_order (#844) - if (auto it = options_list.num_options.find("order"), - it1 = options_list.num_options.find("k_order_solver"); - (it1 != options_list.num_options.end() && it1->second == "true") - || (it != options_list.num_options.end() && stoi(it->second) >= 3)) + if (auto opt1 = options_list.get_if<OptionsList::NumVal>("order"), + opt2 = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt2 && *opt2 == "true") || (opt1 && stoi(*opt1) >= 3)) output << "options_.k_order_solver = true;" << endl; options_list.writeOutput(output); @@ -836,7 +819,7 @@ void DiscretionaryPolicyStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "discretionary_policy")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -866,7 +849,7 @@ void OccbinSetupStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "occbin_setup")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -891,7 +874,7 @@ void OccbinSolverStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "occbin_solver")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -916,7 +899,7 @@ void OccbinWriteRegimesStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "occbin_write_regimes_xls")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -944,7 +927,7 @@ void OccbinGraphStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "occbin_graph")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -972,10 +955,9 @@ EstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsoli mod_file_struct.estimation_present = true; // Fill in option_order of mod_file_struct - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order > 2) mod_file_struct.k_order_solver = true; @@ -984,30 +966,30 @@ EstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsoli } // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Fill in mod_file_struct.estimation_analytic_derivation - if (auto it = options_list.num_options.find("analytic_derivation"); - it != options_list.num_options.end() && it->second == "1") + if (auto opt = options_list.get_if<OptionsList::NumVal>("analytic_derivation"); + opt && *opt == "1") mod_file_struct.estimation_analytic_derivation = true; - if (auto it = options_list.num_options.find("dsge_var"); - it != options_list.num_options.end()) - // Fill in mod_file_struct.dsge_var_calibrated - mod_file_struct.dsge_var_calibrated = it->second; - - // Fill in mod_file_struct.dsge_var_estimated - if (options_list.string_options.contains("dsge_var")) - mod_file_struct.dsge_var_estimated = true; + if (options_list.contains("dsge_var")) + options_list.visit("dsge_var", [&]<class T>(const T &v) + { + if constexpr(is_same_v<T, OptionsList::StringVal>) + mod_file_struct.dsge_var_estimated = true; + else if constexpr(is_same_v<T, OptionsList::NumVal>) + mod_file_struct.dsge_var_calibrated = v; + }); // Fill in mod_file_struct.bayesian_irf_present - if (auto it = options_list.num_options.find("bayesian_irf"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("bayesian_irf"); + opt && *opt == "true") mod_file_struct.bayesian_irf_present = true; - if (options_list.num_options.contains("dsge_varlag")) + if (options_list.contains("dsge_varlag")) if (mod_file_struct.dsge_var_calibrated.empty() && !mod_file_struct.dsge_var_estimated) { @@ -1023,30 +1005,30 @@ EstimationStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsoli exit(EXIT_FAILURE); } - if (!options_list.string_options.contains("datafile") + if (!options_list.contains("datafile") && !mod_file_struct.estimation_data_statement_present) { cerr << "ERROR: The estimation statement requires a data file to be supplied via the datafile option." << endl; exit(EXIT_FAILURE); } - if (options_list.string_options.contains("mode_file") + if (options_list.contains("mode_file") && mod_file_struct.estim_params_use_calib) { cerr << "ERROR: The mode_file option of the estimation statement is incompatible with the use_calibration option of the estimated_params_init block." << endl; exit(EXIT_FAILURE); } - if (auto it = options_list.num_options.find("mh_tune_jscale.status"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("mh_tune_jscale.status"); + opt && *opt == "true") { - if (options_list.num_options.find("mh_jscale") != options_list.num_options.end()) - { - cerr << "ERROR: The mh_tune_jscale and mh_jscale options of the estimation statement are incompatible." << endl; - exit(EXIT_FAILURE); - } + if (options_list.contains("mh_jscale")) + { + cerr << "ERROR: The mh_tune_jscale and mh_jscale options of the estimation statement are incompatible." << endl; + exit(EXIT_FAILURE); + } } - else if (options_list.num_options.contains("mh_tune_jscale.guess")) + else if (options_list.contains("mh_tune_jscale.guess")) { cerr << "ERROR: The option mh_tune_guess in estimation statement cannot be used without option mh_tune_jscale." << endl; exit(EXIT_FAILURE); @@ -1087,19 +1069,20 @@ EstimationStatement::writeOutput(ostream &output, [[maybe_unused]] const string options_list.writeOutput(output); // Special treatment for order option and particle filter - if (auto it = options_list.num_options.find("order"); - it == options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order"); + !opt) output << "options_.order = 1;" << endl; - else if (stoi(it->second) >= 2) + else if (int order {stoi(*opt)}; + order >= 2) { output << "options_.particle.status = true;" << endl; - if (stoi(it->second) > 2) + if (order > 2) output << "options_.k_order_solver = true;" << endl; } // Do not check for the steady state in diffuse filter mode (#400) - if (auto it = options_list.num_options.find("diffuse_filter"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("diffuse_filter"); + opt && *opt == "true") output << "options_.steadystate.nocheck = true;" << endl; symbol_list.writeOutput("var_list_", output); @@ -1110,7 +1093,7 @@ void EstimationStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "estimation")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -1132,8 +1115,8 @@ void DynareSensitivityStatement::checkPass(ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings) { - if (auto it = options_list.num_options.find("identification"); - it != options_list.num_options.end() && it->second == "1") + if (auto opt = options_list.get_if<OptionsList::NumVal>("identification"); + opt && *opt == "1") { mod_file_struct.identification_present = true; // The following triggers 3rd order derivatives, see preprocessor#40 @@ -1151,16 +1134,14 @@ DynareSensitivityStatement::writeOutput(ostream &output, [[maybe_unused]] const /* Ensure that nograph, nodisplay and graph_format are also set in top-level options_. \todo factorize this code between identification and dynare_sensitivity, - and provide a generic mechanism for this situation (maybe using regexps) */ - if (auto it = options_list.num_options.find("nodisplay"); - it != options_list.num_options.end()) - output << "options_.nodisplay = " << it->second << ";" << endl; - if (auto it = options_list.num_options.find("nograph"); - it != options_list.num_options.end()) - output << "options_.nograph = " << it->second << ";" << endl; - if (auto it = options_list.symbol_list_options.find("graph_format"); - it != options_list.symbol_list_options.end()) - it->second.writeOutput("options_.graph_format", output); + and provide a generic mechanism for this situation (maybe using regexps). + graph_format can then be turned into a VecCellStrVal. */ + if (auto opt = options_list.get_if<OptionsList::NumVal>("nodisplay")) + output << "options_.nodisplay = " << *opt << ";" << endl; + if (auto opt = options_list.get_if<OptionsList::NumVal>("nograph")) + output << "options_.nograph = " << *opt << ";" << endl; + if (auto opt = options_list.get_if<OptionsList::SymbolListVal>("graph_format")) + opt->writeOutput("options_.graph_format", output); output << "dynare_sensitivity(options_gsa);" << endl; } @@ -1169,7 +1150,7 @@ void DynareSensitivityStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "dynare_sensitivity")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2178,19 +2159,17 @@ OsrStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation mod_file_struct.osr_present = true; // Fill in option_order of mod_file_struct - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) - mod_file_struct.order_option = max(mod_file_struct.order_option, stoi(it->second)); + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) + mod_file_struct.order_option = max(mod_file_struct.order_option, stoi(*opt)); // Fill in mod_file_struct.partial_information - if (auto it = options_list.num_options.find("partial_information"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("partial_information"); + opt && *opt == "true") mod_file_struct.partial_information = true; // Option k_order_solver (implicit when order >= 3) - if (auto it = options_list.num_options.find("k_order_solver"); - (it != options_list.num_options.end() && it->second == "true") - || mod_file_struct.order_option >= 3) + if (auto opt = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt && *opt == "true") || mod_file_struct.order_option >= 3) mod_file_struct.k_order_solver = true; try @@ -2209,10 +2188,9 @@ OsrStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basena [[maybe_unused]] bool minimal_workspace) const { // Ensure that order 3 implies k_order (#844) - if (auto it = options_list.num_options.find("order"), - it1 = options_list.num_options.find("k_order_solver"); - (it1 != options_list.num_options.end() && it1->second == "true") - || (it != options_list.num_options.end() && stoi(it->second) >= 3)) + if (auto opt1 = options_list.get_if<OptionsList::NumVal>("order"), + opt2 = options_list.get_if<OptionsList::NumVal>("k_order_solver"); + (opt2 && *opt2 == "true") || (opt1 && stoi(*opt1) >= 3)) output << "options_.k_order_solver = true;" << endl; options_list.writeOutput(output); @@ -2224,7 +2202,7 @@ void OsrStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "osr")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2444,7 +2422,7 @@ ModelComparisonStatement::writeJsonOutput(ostream &output) const if (!filename_list.empty()) output << "}"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2539,7 +2517,7 @@ void BVARDensityStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "bvar_density")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2572,7 +2550,7 @@ void BVARForecastStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "bvar_forecast")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2604,7 +2582,7 @@ void SBVARStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "sbvar")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2623,9 +2601,9 @@ MSSBVAREstimationStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.bvar_present = true; - if (!options_list.num_options.contains("ms.create_init") - && (!options_list.string_options.contains("datafile") - || !options_list.num_options.contains("ms.initial_year"))) + if (!options_list.contains("ms.create_init") + && (!options_list.contains("datafile") + || !options_list.contains("ms.initial_year"))) { cerr << "ERROR: If you do not pass no_create_init to ms_estimation, " << "you must pass the datafile and initial_year options." << endl; @@ -2647,7 +2625,7 @@ void MSSBVAREstimationStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_estimation")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2675,9 +2653,9 @@ MSSBVARSimulationStatement::writeOutput(ostream &output, [[maybe_unused]] const options_list.writeOutput(output); // Redeclare drop option if necessary - if ((options_list.num_options.contains("ms.mh_replic") - || options_list.num_options.contains("ms.thinning_factor")) - && !options_list.num_options.contains("ms.drop")) + if ((options_list.contains("ms.mh_replic") + || options_list.contains("ms.thinning_factor")) + && !options_list.contains("ms.drop")) output << "options_.ms.drop = 0.1*options_.ms.mh_replic*options_.ms.thinning_factor;" << endl; output << "[options_, oo_] = ms_simulation(M_, options_, oo_);" << endl; @@ -2687,7 +2665,7 @@ void MSSBVARSimulationStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_simulation")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2720,7 +2698,7 @@ void MSSBVARComputeMDDStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_compute_mdd")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2739,8 +2717,8 @@ MSSBVARComputeProbabilitiesStatement::checkPass(ModFileStructure &mod_file_struc { mod_file_struct.bvar_present = true; - if (options_list.num_options.contains("ms.real_time_smoothed_probabilities") - && options_list.num_options.contains("ms.filtered_probabilities")) + if (options_list.contains("ms.real_time_smoothed_probabilities") + && options_list.contains("ms.filtered_probabilities")) { cerr << "ERROR: You may only pass one of real_time_smoothed " << "and filtered_probabilities to ms_compute_probabilities." << endl; @@ -2762,7 +2740,7 @@ void MSSBVARComputeProbabilitiesStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_compute_probabilities")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2783,9 +2761,9 @@ MSSBVARIrfStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsoli { mod_file_struct.bvar_present = true; - if (bool regime_present = options_list.num_options.contains("ms.regime"), - regimes_present = options_list.num_options.contains("ms.regimes"), - filtered_probabilities_present = options_list.num_options.contains("ms.filtered_probabilities"); + if (bool regime_present = options_list.contains("ms.regime"), + regimes_present = options_list.contains("ms.regimes"), + filtered_probabilities_present = options_list.contains("ms.filtered_probabilities"); (filtered_probabilities_present && regime_present) || (filtered_probabilities_present && regimes_present) || (regimes_present && regime_present)) @@ -2820,7 +2798,7 @@ void MSSBVARIrfStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_irf")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2844,8 +2822,8 @@ MSSBVARForecastStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.bvar_present = true; - if (options_list.num_options.contains("ms.regimes") - && options_list.num_options.contains("ms.regime")) + if (options_list.contains("ms.regimes") + && options_list.contains("ms.regime")) { cerr << "ERROR: You may only pass one of regime and regimes to ms_forecast" << endl; exit(EXIT_FAILURE); @@ -2865,7 +2843,7 @@ void MSSBVARForecastStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_forecast")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2884,9 +2862,9 @@ MSSBVARVarianceDecompositionStatement::checkPass(ModFileStructure &mod_file_stru { mod_file_struct.bvar_present = true; - if (bool regime_present = options_list.num_options.contains("ms.regime"), - regimes_present = options_list.num_options.contains("ms.regimes"), - filtered_probabilities_present = options_list.num_options.contains("ms.filtered_probabilities"); + if (bool regime_present = options_list.contains("ms.regime"), + regimes_present = options_list.contains("ms.regimes"), + filtered_probabilities_present = options_list.contains("ms.filtered_probabilities"); (filtered_probabilities_present && regime_present) || (filtered_probabilities_present && regimes_present) || (regimes_present && regime_present)) @@ -2911,7 +2889,7 @@ void MSSBVARVarianceDecompositionStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "ms_sbvar_variance_decomposition")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -2922,8 +2900,8 @@ MSSBVARVarianceDecompositionStatement::writeJsonOutput(ostream &output) const IdentificationStatement::IdentificationStatement(OptionsList options_list_arg) : options_list{move(options_list_arg)} { - if (auto it = options_list.num_options.find("max_dim_cova_group"); - it != options_list.num_options.end() && stoi(it->second) == 0) + if (auto opt = options_list.get_if<OptionsList::NumVal>("max_dim_cova_group"); + opt && stoi(*opt) == 0) { cerr << "ERROR: The max_dim_cova_group option to identification only accepts integers > 0." << endl; exit(EXIT_FAILURE); @@ -2936,10 +2914,9 @@ IdentificationStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.identification_present = true; - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order < 1 || order > 3) { cerr << "ERROR: the order option of identification command must be between 1 and 3" << endl; @@ -2962,16 +2939,14 @@ IdentificationStatement::writeOutput(ostream &output, [[maybe_unused]] const str /* Ensure that nograph, nodisplay and graph_format are also set in top-level options_. \todo factorize this code between identification and dynare_sensitivity, - and provide a generic mechanism for this situation (maybe using regexps) */ - if (auto it = options_list.num_options.find("nodisplay"); - it != options_list.num_options.end()) - output << "options_.nodisplay = " << it->second << ";" << endl; - if (auto it = options_list.num_options.find("nograph"); - it != options_list.num_options.end()) - output << "options_.nograph = " << it->second << ";" << endl; - if (auto it = options_list.symbol_list_options.find("graph_format"); - it != options_list.symbol_list_options.end()) - it->second.writeOutput("options_.graph_format", output); + and provide a generic mechanism for this situation (maybe using regexps). + graph_format can then be turned into a VecCellStrVal. */ + if (auto opt = options_list.get_if<OptionsList::NumVal>("nodisplay")) + output << "options_.nodisplay = " << *opt << ";" << endl; + if (auto opt = options_list.get_if<OptionsList::NumVal>("nograph")) + output << "options_.nograph = " << *opt << ";" << endl; + if (auto opt = options_list.get_if<OptionsList::SymbolListVal>("graph_format")) + opt->writeOutput("options_.graph_format", output); output << "dynare_identification(options_ident);" << endl; } @@ -2980,7 +2955,7 @@ void IdentificationStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "identification")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3083,8 +3058,8 @@ ShockDecompositionStatement::ShockDecompositionStatement(SymbolList symbol_list_ void ShockDecompositionStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) { - if (auto it = options_list.num_options.find("shock_decomp.with_epilogue"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("shock_decomp.with_epilogue"); + opt && *opt == "true") mod_file_struct.with_epilogue_option = true; try @@ -3111,7 +3086,7 @@ void ShockDecompositionStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "shock_decomposition")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3136,8 +3111,8 @@ RealtimeShockDecompositionStatement::RealtimeShockDecompositionStatement(SymbolL void RealtimeShockDecompositionStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) { - if (auto it = options_list.num_options.find("shock_decomp.with_epilogue"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("shock_decomp.with_epilogue"); + opt && *opt == "true") mod_file_struct.with_epilogue_option = true; try @@ -3165,7 +3140,7 @@ void RealtimeShockDecompositionStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "realtime_shock_decomposition")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3216,7 +3191,7 @@ void PlotShockDecompositionStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "plot_shock_decomposition")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3241,8 +3216,8 @@ InitialConditionDecompositionStatement::InitialConditionDecompositionStatement(S void InitialConditionDecompositionStatement::checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) { - if (auto it = options_list.num_options.find("initial_condition_decomp.with_epilogue"); - it != options_list.num_options.end() && it->second == "true") + if (auto opt = options_list.get_if<OptionsList::NumVal>("initial_condition_decomp.with_epilogue"); + opt && *opt == "true") mod_file_struct.with_epilogue_option = true; try @@ -3271,7 +3246,7 @@ void InitialConditionDecompositionStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "initial_condition_decomposition")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3341,7 +3316,7 @@ void ConditionalForecastStatement::checkPass([[maybe_unused]] ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings) { - if (!options_list.string_options.contains("parameter_set")) + if (!options_list.contains("parameter_set")) { cerr << "ERROR: You must pass the `parameter_set` option to conditional_forecast" << endl; exit(EXIT_FAILURE); @@ -3360,7 +3335,7 @@ void ConditionalForecastStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "conditional_forecast")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3568,14 +3543,11 @@ SvarIdentificationStatement::writeJsonOutput(ostream &output) const MarkovSwitchingStatement::MarkovSwitchingStatement(OptionsList options_list_arg) : options_list{move(options_list_arg)} { - if (auto it_num = options_list.vector_of_vector_value_options.find("ms.restrictions"); - it_num != options_list.vector_of_vector_value_options.end()) + if (auto opt = options_list.get_if<vector<vector<string>>>("ms.restrictions")) { - auto it_num_regimes = options_list.num_options.find("ms.number_of_regimes"); - assert(it_num_regimes != options_list.num_options.end()); - auto num_regimes = stoi(it_num_regimes->second); + int num_regimes {stoi(options_list.get<OptionsList::NumVal>("ms.number_of_regimes"))}; - for (const vector<string> &restriction : it_num->second) + for (const vector<string> &restriction : *opt) { if (restriction.size() != 3) { @@ -3626,9 +3598,7 @@ void MarkovSwitchingStatement::checkPass(ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings) { - auto itChain = options_list.num_options.find("ms.chain"); - assert(itChain != options_list.num_options.end()); - int chainNumber = stoi(itChain->second); + int chainNumber {stoi(options_list.get<OptionsList::NumVal>("ms.chain"))}; if (++mod_file_struct.last_markov_switching_chain != chainNumber) { cerr << "ERROR: The markov_switching chain option takes consecutive integers " @@ -3636,11 +3606,9 @@ MarkovSwitchingStatement::checkPass(ModFileStructure &mod_file_struct, exit(EXIT_FAILURE); } - if (options_list.vector_of_vector_value_options.contains("ms.restrictions")) + if (options_list.contains("ms.restrictions")) { - auto it_num_regimes = options_list.num_options.find("ms.number_of_regimes"); - assert(it_num_regimes != options_list.num_options.end()); - auto num_regimes = stoi(it_num_regimes->second); + int num_regimes {stoi(options_list.get<OptionsList::NumVal>("ms.number_of_regimes"))}; vector col_trans_prob_sum(num_regimes, 0.0); vector row_trans_prob_sum(num_regimes, 0.0); vector all_restrictions_in_row(num_regimes, true); @@ -3694,7 +3662,7 @@ MarkovSwitchingStatement::checkPass(ModFileStructure &mod_file_struct, } } - if (options_list.symbol_list_options.contains("ms.parameters")) + if (options_list.contains("ms.parameters")) mod_file_struct.ms_dsge_present = true; } @@ -3702,37 +3670,44 @@ void MarkovSwitchingStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename, [[maybe_unused]] bool minimal_workspace) const { - auto itChain = options_list.num_options.find("ms.chain"); - assert(itChain != options_list.num_options.end()); + string chainNumber {options_list.get<OptionsList::NumVal>("ms.chain")}; - assert(options_list.num_options.contains("ms.duration") - || options_list.vector_value_options.contains("ms.duration")); - - bool isDurationAVec = options_list.vector_value_options.contains("ms.duration"); + assert(options_list.contains("ms.duration")); output << "options_.ms.duration = "; - if (isDurationAVec) - { - output << "["; - auto &v = options_list.vector_value_options.at("ms.duration"); - for (bool printed_something{false}; - const auto &it : v) - { - if (exchange(printed_something, true)) - output << ", "; - output << it; - } - output << "]"; - } - else - output << options_list.num_options.at("ms.duration"); + bool isDurationAVec { options_list.visit("ms.duration", + [&]<class T>(const T &v) -> bool + { + if constexpr(is_same_v<T, OptionsList::VecValueVal>) + { + output << "["; + for (bool printed_something{false}; + const auto &it : v) + { + if (exchange(printed_something, true)) + output << ", "; + output << it; + } + output << "]"; + return true; + } + else if constexpr(is_same_v<T, OptionsList::NumVal>) + { + output << v; + return false; + } + else + { + cerr << "MarkovSwitchingStatement::writeOutput: incorrect value type for 'ms.duration' option" << endl; + exit(EXIT_FAILURE); + } + }) }; output << ";" << endl; - auto itNOR = options_list.num_options.find("ms.number_of_regimes"); - assert(itNOR != options_list.num_options.end()); - for (int i = 0; i < stoi(itNOR->second); i++) + int NOR {stoi(options_list.get<OptionsList::NumVal>("ms.number_of_regimes"))}; + for (int i {0}; i < NOR; i++) { - output << "options_.ms.ms_chain(" << itChain->second << ").regime(" + output << "options_.ms.ms_chain(" << chainNumber << ").regime(" << i+1 << ").duration = options_.ms.duration"; if (isDurationAVec) output << "(" << i+1 << ")"; @@ -3741,7 +3716,7 @@ MarkovSwitchingStatement::writeOutput(ostream &output, [[maybe_unused]] const st for (int restrictions_index{0}; const auto &[regimes, prob] : restriction_map) - output << "options_.ms.ms_chain(" << itChain->second << ").restrictions(" + output << "options_.ms.ms_chain(" << chainNumber << ").restrictions(" << ++restrictions_index << ") = {[" << regimes.first << ", " << regimes.second << ", " << prob << "]};" << endl; } @@ -3750,7 +3725,7 @@ void MarkovSwitchingStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "markov_switching")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3782,9 +3757,9 @@ void SvarStatement::checkPass([[maybe_unused]] ModFileStructure &mod_file_struct, [[maybe_unused]] WarningConsolidation &warnings) { - bool has_coefficients = options_list.string_options.contains("ms.coefficients"), - has_variances = options_list.string_options.contains("ms.variances"), - has_constants = options_list.string_options.contains("ms.constants"); + bool has_coefficients = options_list.contains("ms.coefficients"), + has_variances = options_list.contains("ms.variances"), + has_constants = options_list.contains("ms.constants"); assert((has_coefficients && !has_variances && !has_constants) || (!has_coefficients && has_variances && !has_constants) || (!has_coefficients && !has_variances && has_constants)); @@ -3794,33 +3769,28 @@ void SvarStatement::writeOutput(ostream &output, [[maybe_unused]] const string &basename, [[maybe_unused]] bool minimal_workspace) const { - auto it = options_list.num_options.find("ms.chain"); - assert(it != options_list.num_options.end()); - output << "options_.ms.ms_chain(" << it->second << ")"; + output << "options_.ms.ms_chain(" << options_list.get<OptionsList::NumVal>("ms.chain") << ")"; - if (auto it0 = options_list.string_options.find("ms.coefficients"); - it0 != options_list.string_options.end()) - output << "." << it0->second; - else if (auto it1 = options_list.string_options.find("ms.variances"); - it1 != options_list.string_options.end()) - output << "." << it1->second; + if (auto opt1 = options_list.get_if<OptionsList::StringVal>("ms.coefficients")) + output << "." << *opt1; + else if (auto opt2 = options_list.get_if<OptionsList::StringVal>("ms.variances")) + output << "." << *opt2; else - output << "." << options_list.string_options.find("ms.constants")->second; + output << "." << options_list.get<OptionsList::StringVal>("ms.constants"); output << ".equations = "; - if (auto itv = options_list.vector_int_options.find("ms.equations"); - itv != options_list.vector_int_options.end()) + if (auto opt = options_list.get_if<vector<int>>("ms.equations")) { - assert(itv->second.size() >= 1); - if (itv->second.size() > 1) + assert(opt->size() >= 1); + if (opt->size() > 1) { output << "["; - for (int viit : itv->second) + for (int viit : *opt) output << viit << ";"; output << "];" << endl; } else - output << itv->second.front() << ";" << endl; + output << opt->front() << ";" << endl; } else output << "'ALL';" << endl; @@ -3830,7 +3800,7 @@ void SvarStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "svar")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3868,7 +3838,7 @@ void SetTimeStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "set_time")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -3887,16 +3857,15 @@ EstimationDataStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.estimation_data_statement_present = true; - if (auto it = options_list.num_options.find("nobs"); - it != options_list.num_options.end()) - if (stoi(it->second) <= 0) + if (auto opt = options_list.get_if<OptionsList::NumVal>("nobs")) + if (stoi(*opt) <= 0) { cerr << "ERROR: The nobs option of the data statement only accepts positive integers." << endl; exit(EXIT_FAILURE); } - bool has_file = options_list.string_options.contains("file"), - has_series = options_list.string_options.contains("series"); + bool has_file = options_list.contains("file"), + has_series = options_list.contains("series"); if (!has_file && !has_series) { cerr << "ERROR: The file or series option must be passed to the data statement." << endl; @@ -3920,7 +3889,7 @@ void EstimationDataStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "estimation_data")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -4143,22 +4112,17 @@ JointPriorStatement::checkPass([[maybe_unused]] ModFileStructure &mod_file_struc exit(EXIT_FAILURE); } - if (!options_list.num_options.contains("mean") - && !options_list.vector_value_options.contains("mean") - && !options_list.num_options.contains("mode")) + if (!options_list.contains("mean") && !options_list.contains("mode")) { cerr << "ERROR: You must pass at least one of mean and mode to the prior statement." << endl; exit(EXIT_FAILURE); } - if (auto it = options_list.vector_value_options.find("domain"); - it != options_list.vector_value_options.end()) + if (auto opt = options_list.get_if<OptionsList::VecValueVal>("domain"); + opt && opt->size() != 4) { - if (it->second.size() != 4) - { - cerr << "ERROR: You must pass exactly four values to the domain option." << endl; - exit(EXIT_FAILURE); - } + cerr << "ERROR: You must pass exactly four values to the domain option." << endl; + exit(EXIT_FAILURE); } } @@ -4212,43 +4176,49 @@ void JointPriorStatement::writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const { output << lhs_field << "." << field << " = {"; - if (auto it = options_list.num_options.find(field); - it != options_list.num_options.end()) - output << it->second; - else if (auto it = options_list.vector_value_options.find(field); - it != options_list.vector_value_options.end()) - { - output << "["; - for (bool printed_something{false}; - const auto &it2 : it->second) - { - if (exchange(printed_something, true)) - output << ", "; - output << it2; - } - output << "]"; - } - else if (auto it = options_list.vector_of_vector_value_options.find(field); - it != options_list.vector_of_vector_value_options.end()) - { - output << "{"; - for (bool printed_something{false}; - const auto &it2 : it->second) - { - if (exchange(printed_something, true)) - output << ", "; - output << "["; - for (bool printed_something2{false}; - const auto &it3 : it2) - { - if (exchange(printed_something2, true)) - output << ", "; - output << it3; - } - output << "]"; - } - output << "}"; - } + if (options_list.contains(field)) + options_list.visit(field, [&]<class T>(const T &v) + { + if constexpr(is_same_v<T, OptionsList::NumVal>) + output << v; + else if constexpr(is_same_v<T, OptionsList::VecValueVal>) + { + output << "["; + for (bool printed_something{false}; + const auto &it2 : v) + { + if (exchange(printed_something, true)) + output << ", "; + output << it2; + } + output << "]"; + } + else if constexpr(is_same_v<T, vector<vector<string>>>) + { + output << "{"; + for (bool printed_something{false}; + const auto &it2 : v) + { + if (exchange(printed_something, true)) + output << ", "; + output << "["; + for (bool printed_something2{false}; + const auto &it3 : it2) + { + if (exchange(printed_something2, true)) + output << ", "; + output << it3; + } + output << "]"; + } + output << "}"; + } + else + { + cerr << "JointPriorStatement::writeOutputHelper: unhandled alternative" << endl; + exit(EXIT_FAILURE); + } + }); else output << "{}"; output << "};" << endl; @@ -4268,7 +4238,7 @@ JointPriorStatement::writeJsonOutput(ostream &output) const } output << "]"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -4331,29 +4301,24 @@ BasicPriorStatement::checkPass([[maybe_unused]] ModFileStructure &mod_file_struc exit(EXIT_FAILURE); } - if (!options_list.num_options.contains("mean") - && !options_list.vector_value_options.contains("mean") - && !options_list.num_options.contains("mode")) + if (!options_list.contains("mean") && !options_list.contains("mode")) { cerr << "ERROR: You must pass at least one of mean and mode to the prior statement." << endl; exit(EXIT_FAILURE); } - if (bool has_stdev = options_list.num_options.contains("stdev"); + if (bool has_stdev = options_list.contains("stdev"); (!has_stdev && !variance) || (has_stdev && variance)) { cerr << "ERROR: You must pass exactly one of stdev and variance to the prior statement." << endl; exit(EXIT_FAILURE); } - if (auto it = options_list.vector_value_options.find("domain"); - it != options_list.vector_value_options.end()) + if (auto opt = options_list.get_if<OptionsList::VecValueVal>("domain"); + opt && opt->size() != 2) { - if (it->second.size() != 2) - { - cerr << "ERROR: You must pass exactly two values to the domain option." << endl; - exit(EXIT_FAILURE); - } + cerr << "ERROR: You must pass exactly two values to the domain option." << endl; + exit(EXIT_FAILURE); } } @@ -4403,9 +4368,13 @@ BasicPriorStatement::writeCommonOutput(ostream &output, const string &lhs_field) void BasicPriorStatement::writeCommonOutputHelper(ostream &output, const string &field, const string &lhs_field) const { - if (auto itn = options_list.num_options.find(field); - itn != options_list.num_options.end()) - output << lhs_field << "." << field << " = "<< itn->second << ";" << endl; + if (options_list.contains(field)) + options_list.visit(field, [&]<class T>(const T &v) + { + if constexpr(is_same_v<T, OptionsList::NumVal>) + output << lhs_field << "." << field << " = "<< v << ";" << endl; + // TODO: handle other variant types + }); } void @@ -4435,7 +4404,7 @@ BasicPriorStatement::writeJsonPriorOutput(ostream &output) const variance->writeJsonOutput(output, {}, {}); output << R"(")"; } - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -4744,9 +4713,13 @@ BasicOptionsStatement::writeCommonOutput(ostream &output, const string &lhs_fiel void BasicOptionsStatement::writeCommonOutputHelper(ostream &output, const string &field, const string &lhs_field) const { - if (auto itn = options_list.num_options.find(field); - itn != options_list.num_options.end()) - output << lhs_field << "." << field << " = " << itn->second << ";" << endl; + if (options_list.contains(field)) + options_list.visit(field, [&]<class T>(const T &v) + { + if constexpr(is_same_v<T, OptionsList::NumVal>) + output << lhs_field << "." << field << " = "<< v << ";" << endl; + // TODO: handle other variant types + }); } void @@ -4769,7 +4742,7 @@ BasicOptionsStatement::writeJsonOptionsOutput(ostream &output) const output << R"(, "name": ")" << name << R"(")"; if (!subsample_name.empty()) output << R"(, "subsample_name": ")" << subsample_name << R"(")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5029,7 +5002,7 @@ CalibSmootherStatement::writeOutput(ostream &output, [[maybe_unused]] const stri [[maybe_unused]] bool minimal_workspace) const { options_list.writeOutput(output); - if (!options_list.string_options.contains("parameter_set")) + if (!options_list.contains("parameter_set")) output << "options_.parameter_set = 'calibration';" << endl; symbol_list.writeOutput("var_list_", output); output << "options_.smoother = true;" << endl @@ -5041,7 +5014,7 @@ void CalibSmootherStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "calib_smoother")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5065,7 +5038,7 @@ ExtendedPathStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.extended_path_present = true; - if (!options_list.num_options.contains("periods")) + if (!options_list.contains("periods")) { cerr << "ERROR: the 'periods' option of 'extended_path' is mandatory" << endl; exit(EXIT_FAILURE); @@ -5077,20 +5050,20 @@ ExtendedPathStatement::writeOutput(ostream &output, [[maybe_unused]] const strin [[maybe_unused]] bool minimal_workspace) const { // Beware: options do not have the same name in the interface and in the M code... + string periods {options_list.get<OptionsList::NumVal>("periods")}; - for (const auto &num_option : options_list.num_options) - if (num_option.first != "periods") - output << "options_." << num_option.first << " = " << num_option.second << ";" << endl; + OptionsList options_list_new {options_list}; + options_list_new.erase("periods"); + options_list_new.writeOutput(output); - output << "extended_path([], " << options_list.num_options.find("periods")->second - << ", [], options_, M_, oo_);" << endl; + output << "extended_path([], " << periods << ", [], options_, M_, oo_);" << endl; } void ExtendedPathStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "extended_path")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5128,7 +5101,7 @@ void Smoother2histvalStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "smoother_2_histval")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5147,10 +5120,9 @@ MethodOfMomentsStatement::checkPass(ModFileStructure &mod_file_struct, { mod_file_struct.mom_estimation_present = true; // Fill in option_order of mod_file_struct - if (auto it = options_list.num_options.find("order"); - it != options_list.num_options.end()) + if (auto opt = options_list.get_if<OptionsList::NumVal>("order")) { - int order = stoi(it->second); + int order = stoi(*opt); if (order > 2) mod_file_struct.k_order_solver = true; @@ -5159,41 +5131,41 @@ MethodOfMomentsStatement::checkPass(ModFileStructure &mod_file_struct, mod_file_struct.order_option = max(mod_file_struct.order_option, order); } - if (!options_list.string_options.contains("datafile")) - { - cerr << "ERROR: The method_of_moments statement requires a data file to be supplied via the datafile option." << endl; - exit(EXIT_FAILURE); - } + if (!options_list.contains("datafile")) + { + cerr << "ERROR: The method_of_moments statement requires a data file to be supplied via the datafile option." << endl; + exit(EXIT_FAILURE); + } - if (!options_list.string_options.contains("mom.mom_method")) - { - cerr << "ERROR: The method_of_moments statement requires a method to be supplied via the mom_method option. Possible values are GMM or SMM." << endl; - exit(EXIT_FAILURE); - } + if (!options_list.contains("mom.mom_method")) + { + cerr << "ERROR: The method_of_moments statement requires a method to be supplied via the mom_method option. Possible values are GMM or SMM." << endl; + exit(EXIT_FAILURE); + } - if (auto it = options_list.string_options.find("mom.mom_method"); - it != options_list.string_options.end() && it->second == "GMM") - mod_file_struct.GMM_present = true; + if (auto opt = options_list.get_if<OptionsList::StringVal>("mom.mom_method"); + opt && *opt == "GMM") + mod_file_struct.GMM_present = true; - if (auto it = options_list.num_options.find("mom.analytic_standard_errors"); - it != options_list.num_options.end() && it->second == "true") - mod_file_struct.analytic_standard_errors_present = true; + if (auto opt = options_list.get_if<OptionsList::NumVal>("mom.analytic_standard_errors"); + opt && *opt == "true") + mod_file_struct.analytic_standard_errors_present = true; - if (!mod_file_struct.GMM_present && mod_file_struct.analytic_standard_errors_present) - { - cerr << "ERROR: The analytic_standard_errors statement requires the GMM option." << endl; - exit(EXIT_FAILURE); - } - - if (auto it = options_list.num_options.find("mom.analytic_jacobian"); - it != options_list.num_options.end() && it->second == "true") - mod_file_struct.analytic_jacobian_present = true; + if (!mod_file_struct.GMM_present && mod_file_struct.analytic_standard_errors_present) + { + cerr << "ERROR: The analytic_standard_errors statement requires the GMM option." << endl; + exit(EXIT_FAILURE); + } - if (!mod_file_struct.GMM_present && mod_file_struct.analytic_jacobian_present) - { - cerr << "ERROR: The analytic_jacobian statement requires the GMM option." << endl; - exit(EXIT_FAILURE); - } + if (auto opt = options_list.get_if<OptionsList::NumVal>("mom.analytic_jacobian"); + opt && *opt == "true") + mod_file_struct.analytic_jacobian_present = true; + + if (!mod_file_struct.GMM_present && mod_file_struct.analytic_jacobian_present) + { + cerr << "ERROR: The analytic_jacobian statement requires the GMM option." << endl; + exit(EXIT_FAILURE); + } } void @@ -5209,7 +5181,7 @@ void MethodOfMomentsStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "method_of_moments")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5255,7 +5227,7 @@ void GenerateIRFsStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "generate_irfs")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -5492,7 +5464,7 @@ void ResidStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "resid")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); diff --git a/src/ComputingTasks.hh b/src/ComputingTasks.hh index 1cb72657dabe589a52489f65509b0e2a74b07d18..fd2231b9ffa3490cff03427035a7e9c14b38dde2 100644 --- a/src/ComputingTasks.hh +++ b/src/ComputingTasks.hh @@ -1004,13 +1004,13 @@ private: const vector<string> joint_parameters; const PriorDistributions prior_shape; const OptionsList options_list; + void writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const; public: JointPriorStatement(vector<string> joint_parameters_arg, PriorDistributions prior_shape_arg, OptionsList options_list_arg); void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override; void writeOutput(ostream &output, const string &basename, bool minimal_workspace) const override; - void writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const; void writeJsonOutput(ostream &output) const override; }; diff --git a/src/NumericalInitialization.cc b/src/NumericalInitialization.cc index 0fc2d557f25ec46b134e7b140ad5e61ae7df7fd8..dde5a7419aef4eebe19d53ada942d110768666ad 100644 --- a/src/NumericalInitialization.cc +++ b/src/NumericalInitialization.cc @@ -497,7 +497,7 @@ void InitvalFileStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "initval_file")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); @@ -526,7 +526,7 @@ void HistvalFileStatement::writeJsonOutput(ostream &output) const { output << R"({"statementName": "histval_file")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); diff --git a/src/ParsingDriver.cc b/src/ParsingDriver.cc index 39110bfb6f9cc1f51576e8d03866318c2145526e..7dc78f0dac47b99c8465f9035c93c1748960ade4 100644 --- a/src/ParsingDriver.cc +++ b/src/ParsingDriver.cc @@ -1365,43 +1365,43 @@ ParsingDriver::steady() void ParsingDriver::option_num(string name_option, string opt1, string opt2) { - if (options_list.paired_num_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); - options_list.paired_num_options[move(name_option)] = { move(opt1), move(opt2) }; + options_list.set(move(name_option), pair{move(opt1), move(opt2)}); } void ParsingDriver::option_num(string name_option, string opt) { - if (options_list.num_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); - options_list.num_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::NumVal{move(opt)}); } void ParsingDriver::option_str(string name_option, string opt) { - if (options_list.string_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); - options_list.string_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::StringVal{move(opt)}); } void ParsingDriver::option_date(string name_option, string opt) { - if (options_list.date_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); - options_list.date_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::DateVal{move(opt)}); } void ParsingDriver::option_symbol_list(string name_option, vector<string> symbol_list) { - if (options_list.symbol_list_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (name_option == "irf_shocks") @@ -1418,67 +1418,67 @@ ParsingDriver::option_symbol_list(string name_option, vector<string> symbol_list if (mod_file->symbol_table.getType(it) != SymbolType::parameter) error("Variables passed to the parameters option of the markov_switching statement must be parameters. Caused by: " + it); - options_list.symbol_list_options[move(name_option)] = move(symbol_list); + options_list.set(move(name_option), OptionsList::SymbolListVal{move(symbol_list)}); } void ParsingDriver::option_vec_int(string name_option, vector<int> opt) { - if (options_list.vector_int_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (opt.empty()) error("option " + name_option + " was passed an empty vector."); - options_list.vector_int_options[move(name_option)] = move(opt); + options_list.set(move(name_option), move(opt)); } void ParsingDriver::option_vec_str(string name_option, vector<string> opt) { - if (options_list.vector_str_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (opt.empty()) error("option " + name_option + " was passed an empty vector."); - options_list.vector_str_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::VecStrVal{move(opt)}); } void ParsingDriver::option_vec_cellstr(string name_option, vector<string> opt) { - if (options_list.vector_cellstr_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (opt.empty()) error("option " + name_option + " was passed an empty vector."); - options_list.vector_cellstr_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::VecCellStrVal{move(opt)}); } void ParsingDriver::option_vec_value(string name_option, vector<string> opt) { - if (options_list.vector_value_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (opt.empty()) error("option " + name_option + " was passed an empty vector."); - options_list.vector_value_options[move(name_option)] = move(opt); + options_list.set(move(name_option), OptionsList::VecValueVal{move(opt)}); } void ParsingDriver::option_vec_of_vec_value(string name_option, vector<vector<string>> opt) { - if (options_list.vector_of_vector_value_options.contains(name_option)) + if (options_list.contains(name_option)) error("option " + name_option + " declared twice"); if (opt.empty()) error("option " + name_option + " was passed an empty vector."); - options_list.vector_of_vector_value_options[move(name_option)] = move(opt); + options_list.set(move(name_option), move(opt)); } void @@ -1497,8 +1497,8 @@ void ParsingDriver::stoch_simul(SymbolList symbol_list) { //make sure default order is known to preprocessor, see #49 - if (!options_list.num_options.contains("order")) - options_list.num_options["order"] = "2"; + if (!options_list.contains("order")) + options_list.set("order", OptionsList::NumVal{"2"}); symbol_list.removeDuplicates("stoch_simul", warnings); @@ -1510,44 +1510,36 @@ ParsingDriver::stoch_simul(SymbolList symbol_list) void ParsingDriver::trend_component_model() { - auto its = options_list.string_options.find("trend_component.name"); - if (its == options_list.string_options.end()) - error("You must pass the model_name option to the trend_component_model statement."); - auto &name = its->second; - - auto itvs = options_list.vector_str_options.find("trend_component.eqtags"); - if (itvs == options_list.vector_str_options.end()) - error("You must pass the eqtags option to the trend_component_model statement."); - auto &eqtags = itvs->second; - - auto itvs1 = options_list.vector_str_options.find("trend_component.targets"); - if (itvs1 == options_list.vector_str_options.end()) - error("You must pass the targets option to the trend_component_model statement."); - auto &targets = itvs1->second; + try + { + mod_file->trend_component_model_table.addTrendComponentModel(options_list.get<OptionsList::StringVal>("trend_component.name"), + options_list.get<OptionsList::VecStrVal>("trend_component.eqtags"), + options_list.get<OptionsList::VecStrVal>("trend_component.targets")); + } + catch (OptionsList::UnknownOptionException &e) + { + string name {e.name.substr(16)}; + if (name == "name") + name = "model_name"; + error("You must pass the '" + name + "' option to the 'trend_component_model' statement."); + } - mod_file->trend_component_model_table.addTrendComponentModel(move(name), move(eqtags), move(targets)); options_list.clear(); } void ParsingDriver::var_model() { - auto its = options_list.string_options.find("var.model_name"); - if (its == options_list.string_options.end()) - error("You must pass the model_name option to the var_model statement."); - auto &name = its->second; - - auto itvs = options_list.vector_str_options.find("var.eqtags"); - if (itvs == options_list.vector_str_options.end()) - error("You must pass the eqtags option to the var_model statement."); - auto &eqtags = itvs->second; - - bool structural = false; - if (auto itn = options_list.num_options.find("var.structural"); - itn != options_list.num_options.end() && itn->second == "true") - structural = true; - - mod_file->var_model_table.addVarModel(move(name), structural, move(eqtags)); + try + { + mod_file->var_model_table.addVarModel(options_list.get<OptionsList::StringVal>("var.model_name"), + options_list.get_if<OptionsList::NumVal>("var.structural").value_or(OptionsList::NumVal{"false"}) == "true", + options_list.get<OptionsList::VecStrVal>("var.eqtags")); + } + catch (OptionsList::UnknownOptionException &e) + { + error("You must pass the '" + e.name.substr(4) + "' option to the 'var_model' statement."); + } options_list.clear(); } @@ -2208,9 +2200,8 @@ ParsingDriver::ramsey_model() error("ramsey_model: the 'planner_discount' option cannot be used when the 'optimal_policy_discount_factor' parameter is explicitly declared."); // Check that instruments are declared endogenous (#72) - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - for (const auto &s : it->second.getSymbols()) + if (options_list.contains("instruments")) + for (const auto &s : options_list.get<OptionsList::SymbolListVal>("instruments").getSymbols()) check_symbol_is_endogenous(s); mod_file->addStatement(make_unique<RamseyModelStatement>(options_list)); @@ -2242,9 +2233,8 @@ ParsingDriver::ramsey_policy(vector<string> symbol_list) error("ramsey_policy: the 'planner_discount' option cannot be used when the 'optimal_policy_discount_factor' parameter is explicitly declared."); // Check that instruments are declared endogenous (#72) - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - for (const auto &s : it->second.getSymbols()) + if (options_list.contains("instruments")) + for (const auto &s : options_list.get<OptionsList::SymbolListVal>("instruments").getSymbols()) check_symbol_is_endogenous(s); mod_file->addStatement(make_unique<RamseyPolicyStatement>(move(symbol_list), options_list, @@ -2302,9 +2292,8 @@ ParsingDriver::discretionary_policy(vector<string> symbol_list) init_param("optimal_policy_discount_factor", planner_discount); // Check that instruments are declared endogenous (#72) - if (auto it = options_list.symbol_list_options.find("instruments"); - it != options_list.symbol_list_options.end()) - for (const auto &s : it->second.getSymbols()) + if (options_list.contains("instruments")) + for (const auto &s : options_list.get<OptionsList::SymbolListVal>("instruments").getSymbols()) check_symbol_is_endogenous(s); mod_file->addStatement(make_unique<DiscretionaryPolicyStatement>(move(symbol_list), options_list, @@ -2411,9 +2400,9 @@ ParsingDriver::ms_variance_decomposition() void ParsingDriver::svar() { - bool has_coefficients = options_list.string_options.contains("ms.coefficients"), - has_variances = options_list.string_options.contains("ms.variances"), - has_constants = options_list.string_options.contains("ms.constants"); + bool has_coefficients = options_list.contains("ms.coefficients"), + has_variances = options_list.contains("ms.variances"), + has_constants = options_list.contains("ms.constants"); if (!has_coefficients && !has_variances && !has_constants) error("You must pass one of 'coefficients', 'variances', or 'constants'."); @@ -2421,17 +2410,20 @@ ParsingDriver::svar() || (has_coefficients && has_constants)) error("You may only pass one of 'coefficients', 'variances', or 'constants'."); - if (auto itn = options_list.num_options.find("ms.chain"); - itn == options_list.num_options.end()) - error("A chain option must be passed to the svar statement."); - else if (stoi(itn->second) <= 0) - error("The value passed to the chain option must be greater than zero."); + try + { + if (stoi(options_list.get<OptionsList::NumVal>("ms.chain")) <= 0) + error("The value passed to the 'chain' option must be greater than zero."); + } + catch (OptionsList::UnknownOptionException &) + { + error("A 'chain' option must be passed to the 'svar' statement."); + } - if (auto itv = options_list.vector_int_options.find("ms.equations"); - itv != options_list.vector_int_options.end()) - for (int viit : itv->second) + if (options_list.contains("ms.equations")) + for (int viit : options_list.get<vector<int>>("ms.equations")) if (viit <= 0) - error("The value(s) passed to the equation option must be greater than zero."); + error("The value(s) passed to the 'equations' option must be greater than zero."); mod_file->addStatement(make_unique<SvarStatement>(options_list)); options_list.clear(); @@ -2440,20 +2432,18 @@ ParsingDriver::svar() void ParsingDriver::markov_switching() { - auto it0 = options_list.num_options.find("ms.chain"); - if (it0 == options_list.num_options.end()) - error("A chain option must be passed to the markov_switching statement."); - else if (stoi(it0->second) <= 0) - error("The value passed to the chain option must be greater than zero."); - - it0 = options_list.num_options.find("ms.number_of_regimes"); - if (it0 == options_list.num_options.end()) - error("A number_of_regimes option must be passed to the markov_switching statement."); - else if (stoi(it0->second) <= 0) - error("The value passed to the number_of_regimes option must be greater than zero."); - - if (!options_list.num_options.contains("ms.duration")) - error("A duration option must be passed to the markov_switching statement."); + try + { + if (stoi(options_list.get<OptionsList::NumVal>("ms.chain")) <= 0) + error("The value passed to the chain option must be greater than zero."); + if (stoi(options_list.get<OptionsList::NumVal>("ms.number_of_regimes")) <= 0) + error("The value passed to the number_of_regimes option must be greater than zero."); + options_list.get<OptionsList::NumVal>("ms.duration"); // Just check its presence + } + catch (OptionsList::UnknownOptionException &e) + { + error("A '" + e.name.substr(3) + "' option must be passed to the 'markov_switching' statement."); + } mod_file->addStatement(make_unique<MarkovSwitchingStatement>(options_list)); options_list.clear(); @@ -2785,24 +2775,20 @@ ParsingDriver::begin_pac_model() void ParsingDriver::pac_model() { - auto it = options_list.string_options.find("pac.model_name"); - if (it == options_list.string_options.end()) - error("You must pass the model_name option to the pac_model statement."); - auto &name = it->second; - - string aux_model_name; - it = options_list.string_options.find("pac.aux_model_name"); - if (it != options_list.string_options.end()) - aux_model_name = it->second; - - it = options_list.string_options.find("pac.discount"); - if (it == options_list.string_options.end()) - error("You must pass the discount option to the pac_model statement."); - auto &discount = it->second; - check_symbol_is_parameter(discount); + try + { + auto discount {options_list.get<OptionsList::StringVal>("pac.discount")}; + check_symbol_is_parameter(discount); + mod_file->pac_model_table.addPacModel(options_list.get<OptionsList::StringVal>("pac.model_name"), + options_list.get_if<OptionsList::StringVal>("pac.aux_model_name").value_or(OptionsList::StringVal{}), + move(discount), pac_growth, + pac_auxname, pac_kind); + } + catch (OptionsList::UnknownOptionException &e) + { + error("You must pass the '" + e.name.substr(4) + "' option to the 'pac_model' statement."); + } - mod_file->pac_model_table.addPacModel(move(name), move(aux_model_name), move(discount), pac_growth, - pac_auxname, pac_kind); options_list.clear(); parsing_pac_model = false; } @@ -3310,21 +3296,21 @@ ParsingDriver::add_graph_format(string name) void ParsingDriver::process_graph_format_option() { - options_list.symbol_list_options["graph_format"] = graph_formats; + options_list.set("graph_format", OptionsList::SymbolListVal{move(graph_formats)}); graph_formats.clear(); } void ParsingDriver::initial_condition_decomp_process_graph_format_option() { - options_list.symbol_list_options["initial_condition_decomp.graph_format"] = graph_formats; + options_list.set("initial_condition_decomp.graph_format", OptionsList::SymbolListVal{move(graph_formats)}); graph_formats.clear(); } void ParsingDriver::plot_shock_decomp_process_graph_format_option() { - options_list.symbol_list_options["plot_shock_decomp.graph_format"] = graph_formats; + options_list.set("plot_shock_decomp.graph_format", OptionsList::SymbolListVal{move(graph_formats)}); graph_formats.clear(); } @@ -3553,30 +3539,18 @@ ParsingDriver::end_init2shocks(const string &name) void ParsingDriver::var_expectation_model() { - auto it = options_list.string_options.find("variable"); - if (it == options_list.string_options.end() && !var_expectation_model_expression) - error("You must pass either the 'variable' or the 'expression' option to the var_expectation_model statement."); - if (it != options_list.string_options.end()) + try { + string v {options_list.get<OptionsList::StringVal>("variable")}; if (var_expectation_model_expression) error("You can't pass both the 'variable' or the 'expression' options to the var_expectation_model statement."); - var_expectation_model_expression = data_tree->AddVariable(mod_file->symbol_table.getID(it->second)); + var_expectation_model_expression = data_tree->AddVariable(mod_file->symbol_table.getID(v)); + } + catch (OptionsList::UnknownOptionException &) + { + if (!var_expectation_model_expression) + error("You must pass either the 'variable' or the 'expression' option to the var_expectation_model statement."); } - - it = options_list.string_options.find("auxiliary_model_name"); - if (it == options_list.string_options.end()) - error("You must pass the auxiliary_model_name option to the var_expectation_model statement."); - auto &var_model_name = it->second; - - it = options_list.string_options.find("model_name"); - if (it == options_list.string_options.end()) - error("You must pass the model_name option to the var_expectation_model statement."); - auto &model_name = it->second; - - it = options_list.num_options.find("horizon"); - if (it == options_list.num_options.end()) - error("You must pass the horizon option to the var_expectation_model statement."); - auto &horizon = it->second; if (var_expectation_model_discount) { @@ -3589,16 +3563,23 @@ ParsingDriver::var_expectation_model() else var_expectation_model_discount = data_tree->One; - int time_shift = 0; - it = options_list.num_options.find("time_shift"); - if (it != options_list.num_options.end()) - time_shift = stoi(it->second); + int time_shift { stoi(options_list.get_if<OptionsList::NumVal>("time_shift").value_or(OptionsList::NumVal{"0"})) }; if (time_shift > 0) error("The 'time_shift' option must be a non-positive integer"); - mod_file->var_expectation_model_table.addVarExpectationModel(move(model_name), var_expectation_model_expression, - move(var_model_name), move(horizon), - var_expectation_model_discount, time_shift); + try + { + mod_file->var_expectation_model_table.addVarExpectationModel(options_list.get<OptionsList::StringVal>("model_name"), + var_expectation_model_expression, + options_list.get<OptionsList::StringVal>("auxiliary_model_name"), + options_list.get<OptionsList::NumVal>("horizon"), + var_expectation_model_discount, + time_shift); + } + catch (OptionsList::UnknownOptionException &e) + { + error("You must pass the '" + e.name + "' option to the 'var_expectation_model' statement."); + } options_list.clear(); var_expectation_model_discount = nullptr; diff --git a/src/Shocks.cc b/src/Shocks.cc index 3f57c4913f4e9b8f009088831c4ee26d311e6fbc..b6539e537d665380790ced999b5c82b19932a5dd 100644 --- a/src/Shocks.cc +++ b/src/Shocks.cc @@ -741,7 +741,7 @@ void IrfCalibration::writeJsonOutput(ostream &output) const { output << R"({"statementName": "irf_calibration")"; - if (options_list.getNumberOfOptions()) + if (!options_list.empty()) { output << ", "; options_list.writeJsonOutput(output); diff --git a/src/Statement.cc b/src/Statement.cc index fbe32d7432f0bd270f804e89c7ff1ee0315307ec..10e94dcb9df793d29e8ecc772fbc00db280aa24f 100644 --- a/src/Statement.cc +++ b/src/Statement.cc @@ -184,226 +184,144 @@ OptionsList::writeOutput(ostream &output, const string &option_group) const void OptionsList::writeOutputCommon(ostream &output, const string &option_group) const { - for (const auto & [name, val] : num_options) - output << option_group << "." << name << " = " << val << ";" << endl; - - for (const auto & [name, vals] : paired_num_options) - output << option_group << "." << name << " = [" << vals.first << "; " - << vals.second << "];" << endl; - - for (const auto & [name, val] : string_options) - output << option_group << "." << name << " = '" << val << "';" << endl; - - for (const auto & [name, val] : date_options) - output << option_group << "." << name << " = " << val << ";" << endl; - - for (const auto & [name, list] : symbol_list_options) - list.writeOutput(option_group + "." + name, output); - - for (const auto & [name, vals] : vector_int_options) + for (const auto &[name, val] : options) + std::visit([&]<class T>(const T &v) { - output << option_group << "." << name << " = "; - if (vals.size() > 1) - { - output << "["; - for (int viit : vals) - output << viit << ";"; - output << "];" << endl; - } + if constexpr(is_same_v<T, SymbolListVal>) + v.writeOutput(option_group + "." + name, output); else - output << vals.front() << ";" << endl; - } - - for (const auto & [name, vals] : vector_str_options) - { - output << option_group << "." << name << " = "; - if (vals.size() > 1) - { - output << "{"; - for (const auto &viit : vals) - output << "'" << viit << "';"; - output << "};" << endl; - } - else - output << vals.front() << ";" << endl; - } - - /* vector_cellstr_options should ideally be merged into vector_str_options - only difference is treatment of vals.size==1, where vector_str_options - does not add quotes and curly brackets, i.e. allows for type conversion of - '2' into the number 2 - */ - - for (const auto & [name, vals] : vector_cellstr_options) - { - output << option_group << "." << name << " = {"; - for (const auto &viit : vals) - output << "'" << viit << "';"; - output << "};" << endl; - } - - /* For historical reason, those vectors are output as row vectors (contrary - to vectors of integers which are output as column vectors) */ - for (const auto &[name, vals] : vector_value_options) - { - output << option_group << "." << name << " = ["; - for (const auto &viit : vals) - output << viit << ","; - output << "];" << endl; - } - - // Same remark as for vectors of (floating point) values - for (const auto &[name, vec_vals] : vector_of_vector_value_options) - { - output << option_group << "." << name << " = {"; - for (const auto &vals : vec_vals) { - output << "["; - for (const auto &viit : vals) - output << viit << ","; - output << "], "; + output << option_group << "." << name << " = "; + if constexpr(is_same_v<T, NumVal> || is_same_v<T, DateVal>) + output << v; + else if constexpr(is_same_v<T, pair<string, string>>) + output << '[' << v.first << "; " << v.second << ']'; + else if constexpr(is_same_v<T, StringVal>) + output << "'" << v << "'"; + else if constexpr(is_same_v<T, vector<int>>) + { + if (v.size() > 1) + { + output << '['; + for (int it : v) + output << it << ";"; + output << ']'; + } + else + output << v.front(); + } + else if constexpr(is_same_v<T, VecStrVal>) + { + if (v.size() > 1) + { + output << '{'; + for (const auto &it : v) + output << "'" << it << "';"; + output << '}'; + } + else + output << v.front(); + } + else if constexpr(is_same_v<T, VecCellStrVal>) + { + /* VecCellStrVal should ideally be merged into VecStrVal. + only difference is treatment of v.size==1, where VecStrVal + does not add quotes and curly brackets, i.e. allows for type conversion of + '2' into the number 2 */ + output << '{'; + for (const auto &it : v) + output << "'" << it << "';"; + output << '}'; + } + else if constexpr(is_same_v<T, VecValueVal>) + { + /* For historical reason, those vectors are output as row vectors (contrary + to vectors of integers which are output as column vectors) */ + output << '['; + for (const auto &it : v) + output << it << ','; + output << ']'; + } + else if constexpr(is_same_v<T, vector<vector<string>>>) + { + // Same remark as for VecValueVal + output << '{'; + for (const auto &v2 : v) + { + output << '['; + for (const auto &it : v2) + output << it << ','; + output << "], "; + } + output << '}'; + } + else + static_assert(always_false_v<T>, "Non-exhaustive visitor!"); + output << ";" << endl; } - output << "};" << endl; - } + }, val); } void OptionsList::writeJsonOutput(ostream &output) const { - if (getNumberOfOptions() == 0) + if (empty()) return; - bool opt_written{false}; - output << R"("options": {)"; - for (const auto &[name, val] : num_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": )" << val; - opt_written = true; - } - - for (const auto &[name, vals] : paired_num_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": [)" << vals.first << ", " << vals.second << "]"; - opt_written = true; - } - - for (const auto &[name, val] : string_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": ")" << val << R"(")"; - opt_written = true; - } - - for (const auto &[name, val] : date_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": ")" << val << R"(")"; - opt_written = true; - } - - for (const auto &[name, vals] : symbol_list_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": {)"; - vals.writeJsonOutput(output); - output << "}"; - opt_written = true; - } - for (const auto &[name, vals] : vector_int_options) + for (bool opt_written {false}; + const auto &[name, val] : options) { - if (opt_written) + if (exchange(opt_written, true)) output << ", "; - output << R"(")" << name << R"(": [)"; - for (bool printed_something{false}; - int val : vals) - { - if (exchange(printed_something, true)) - output << ", "; - output << val; - } - output << "]"; - opt_written = true; - } - - for (const auto &[name, vals] : vector_str_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": [)"; - for (bool printed_something{false}; - const auto &val : vals) - { - if (exchange(printed_something, true)) - output << ", "; - output << R"(")" << val << R"(")"; - } - output << "]"; - opt_written = true; - } - - for (const auto &[name, vals] : vector_cellstr_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": [)"; - for (bool printed_something{false}; - const auto &val : vals) - { - if (exchange(printed_something, true)) - output << ", "; - output << R"(")" << val << R"(")"; - } - output << "]"; - opt_written = true; - } - - for (const auto &[name, vals] : vector_value_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": [)"; - for (bool printed_something{false}; - const auto &val : vals) - { - if (exchange(printed_something, true)) - output << ", "; - output << val; - } - output << "]"; - opt_written = true; - } - - for (const auto &[name, vec_vals] : vector_of_vector_value_options) - { - if (opt_written) - output << ", "; - output << R"(")" << name << R"(": [)"; - for (bool printed_something{false}; - const auto &vals : vec_vals) - { - if (exchange(printed_something, true)) - output << ", "; - output << "["; - for (bool printed_something2{false}; - const auto &val : vals) - { - if (exchange(printed_something2, true)) - output << ", "; - output << val; - } - output << "]"; - } - output << "]"; - opt_written = true; + output << R"(")" << name << R"(": )"; + std::visit([&]<class T>(const T &v) + { + if constexpr(is_same_v<T, NumVal> || is_same_v<T, DateVal>) + output << v; + else if constexpr(is_same_v<T, pair<string, string>>) + output << '[' << v.first << ", " << v.second << ']'; + else if constexpr(is_same_v<T, StringVal>) + output << '"' << v << '"'; + else if constexpr(is_same_v<T, SymbolListVal>) + { + output << '{'; + v.writeJsonOutput(output); + output << '}'; + } + else if constexpr(is_same_v<T, vector<int>> || is_same_v<T, VecStrVal> + || is_same_v<T, VecCellStrVal> || is_same_v<T, VecValueVal> + || is_same_v<T, vector<vector<string>>>) + { + output << '['; + for (bool printed_something{false}; + const auto &it : v) + { + if (exchange(printed_something, true)) + output << ", "; + if constexpr(is_same_v<T, vector<int>> || is_same_v<T, VecValueVal>) + output << it; + else if constexpr(is_same_v<T, VecStrVal> || is_same_v<T, VecCellStrVal>) + output << '"' << it << '"'; + else // vector<vector<string>> + { + output << '['; + for (bool printed_something2{false}; + const auto &it2 : it) + { + if (exchange(printed_something2, true)) + output << ", "; + output << it2; + } + output << ']'; + } + } + output << ']'; + } + else + static_assert(always_false_v<T>, "Non-exhaustive visitor!"); + }, val); } output << "}"; @@ -412,29 +330,23 @@ OptionsList::writeJsonOutput(ostream &output) const void OptionsList::clear() { - num_options.clear(); - paired_num_options.clear(); - string_options.clear(); - date_options.clear(); - symbol_list_options.clear(); - vector_int_options.clear(); - vector_str_options.clear(); - vector_cellstr_options.clear(); - vector_value_options.clear(); - vector_of_vector_value_options.clear(); + options.clear(); +} + +bool +OptionsList::contains(const string &name) const +{ + return options.contains(name); +} + +void +OptionsList::erase(const string &name) +{ + options.erase(name); } -int -OptionsList::getNumberOfOptions() const +bool +OptionsList::empty() const { - return num_options.size() - + paired_num_options.size() - + string_options.size() - + date_options.size() - + symbol_list_options.size() - + vector_int_options.size() - + vector_str_options.size() - + vector_cellstr_options.size() - + vector_value_options.size() - + vector_of_vector_value_options.size(); + return options.empty(); } diff --git a/src/Statement.hh b/src/Statement.hh index 4b800123e29f54a158b7dc51224bff9e1637ebe8..7fc35150f96f84971abbbd38d7d5f5c61770ab41 100644 --- a/src/Statement.hh +++ b/src/Statement.hh @@ -24,6 +24,8 @@ #include <string> #include <map> #include <set> +#include <optional> +#include <variant> #include "SymbolList.hh" #include "WarningConsolidation.hh" @@ -204,36 +206,115 @@ public: void writeJsonOutput(ostream &output) const override; }; +/* Stores a list of named options with their values. + The values are stored using an std::variant; see the “options” data member + for the list of available types. */ class OptionsList { public: - using num_options_t = map<string, string>; - using paired_num_options_t = map<string, pair<string, string>>; - using string_options_t = map<string, string>; - using date_options_t = map<string, string>; - using symbol_list_options_t = map<string, SymbolList>; - using vec_int_options_t = map<string, vector<int>>; - using vec_str_options_t = map<string, vector<string >>; - using vec_cellstr_options_t = map<string, vector<string >>; - using vec_value_options_t = map<string, vector<string>>; - using vec_of_vec_value_options_t = map<string, vector<vector<string>>>; - num_options_t num_options; - paired_num_options_t paired_num_options; - string_options_t string_options; - date_options_t date_options; - symbol_list_options_t symbol_list_options; - vec_int_options_t vector_int_options; - vec_str_options_t vector_str_options; - vec_cellstr_options_t vector_cellstr_options; - vec_value_options_t vector_value_options; - vec_of_vec_value_options_t vector_of_vector_value_options; - int getNumberOfOptions() const; + // Some types to lift ambiguities + struct NumVal : string + { + }; + struct StringVal : string + { + }; + struct DateVal : string + { + }; + struct SymbolListVal : SymbolList + { + /* This one is needed because vector<string> implicitly converts to + SymbolList. Otherwise adding a vector<string> to the variant would add a + SymbolList, which is probably not the intended meaning. */ + }; + struct VecStrVal : vector<string> + { + }; + struct VecCellStrVal : vector<string> + { + }; + struct VecValueVal : vector<string> + { + }; + + bool empty() const; + void clear(); + // Whether there is an option with that name that has been given a value + bool contains(const string &name) const; + // Erase the option with that name + void erase(const string &name); + + /* Declares an option with a name and value. Overwrite any previous value for + that name. */ + template<class T> + void + set(string name, T &&val) + { + options.insert_or_assign(move(name), forward<T>(val)); + } + + struct UnknownOptionException + { + const string name; + UnknownOptionException(string name_arg) : name{move(name_arg)} + { + } + }; + + /* Retrieves the value of the option with that name. + Throws UnknownOptionException if there is no option with that name. + Throws bad_variant_access if the option has a value of a different type. */ + template<class T> + T + get(const string &name) const + { + auto it = options.find(name); + if (it != options.end()) + return std::get<T>(it->second); + else + throw UnknownOptionException{name}; + } + + /* Retrieves the value of the option with that name. + Returns nullopt if there is no option with that name. + Throws bad_variant_access if the option has a value of a different type. */ + template<class T> + optional<T> + get_if(const string &name) const + { + auto it = options.find(name); + if (it != options.end()) + return std::get<T>(it->second); + else + return nullopt; + } + + /* Applies a variant visitor to the value of the option with that name. + Throws UnknownOptionException if there is no option with that name. */ + template<class Visitor> + decltype(auto) + visit(const string &name, Visitor &&vis) const + { + auto it = options.find(name); + if (it != options.end()) + return std::visit(forward<Visitor>(vis), it->second); + else + throw UnknownOptionException{name}; + } + void writeOutput(ostream &output) const; void writeOutput(ostream &output, const string &option_group) const; void writeJsonOutput(ostream &output) const; - void clear(); + private: + // pair<string, string> corresponds to a pair of numerical values + // vector<vector<string>> corresponds to a vector of vectors of numerical values + map<string, variant<NumVal, pair<string, string>, StringVal, DateVal, SymbolListVal, vector<int>, + VecStrVal, VecCellStrVal, VecValueVal, vector<vector<string>>>> options; void writeOutputCommon(ostream &output, const string &option_group) const; + // Helper constant for visitors + template<class> static constexpr bool always_false_v {false}; }; #endif // ! _STATEMENT_HH