Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 4.6
  • 5.x
  • 6.x
  • aux_vars_fix
  • julia
  • julia-6.3.0
  • julia-6.4.0
  • julia-meson
  • llvm-15
  • master
  • precond
  • rework_pac
  • uop
  • created_preprocessor_repo
  • julia-6.2.0
15 results

Target

Select target project
  • normann/preprocessor
  • Dynare/preprocessor
  • FerhatMihoubi/preprocessor
  • MichelJuillard/preprocessor
  • sebastien/preprocessor
  • lnsongxf/preprocessor
  • albop/preprocessor
  • DoraK/preprocessor
  • amg/preprocessor
  • wmutschl/preprocessor
  • JohannesPfeifer/preprocessor
11 results
Select Git revision
  • master
  • created_preprocessor_repo
2 results
Show changes
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -211,7 +211,7 @@ protected:
getRecursiveSize() const
{
return size - mfs_size;
};
}
};
// Whether block decomposition has been successfully computed
......@@ -296,7 +296,7 @@ protected:
/* Computes the mcp_equations_reordering vector.
Also checks that a variable does not appear as constrained in two different equations. */
void computeMCPEquationsReordering();
void computeMCPEquationsReordering(const optional<int>& heterogeneous_dimension = nullopt);
//! Writes temporary terms
template<ExprNodeOutputType output_type>
......@@ -439,7 +439,9 @@ protected:
void writeSetAuxiliaryVariablesFile(const string& basename, bool julia) const;
template<bool dynamic>
void writeComplementarityConditionsFile(const string& basename) const;
void writeComplementarityConditionsFile(const string& basename,
const optional<int>& heterogeneous_dimension
= nullopt) const;
private:
//! Sparse matrix of double to store the values of the static Jacobian
......@@ -559,7 +561,7 @@ protected:
{
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]]
.first;
};
}
//! Return true if the equation has been normalized
bool
isBlockEquationRenormalized(int blk, int eq) const
......@@ -567,44 +569,44 @@ protected:
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]]
.first
== EquationType::evaluateRenormalized;
};
}
//! Return the expr_t of equation belonging to the block
BinaryOpNode*
getBlockEquationExpr(int blk, int eq) const
{
return equations[eq_idx_block2orig[blocks[blk].first_equation + eq]];
};
}
//! Return the expr_t of renormalized equation belonging to the block
BinaryOpNode*
getBlockEquationRenormalizedExpr(int blk, int eq) const
{
return equation_type_and_normalized_equation[eq_idx_block2orig[blocks[blk].first_equation + eq]]
.second;
};
}
//! Return the original number of equation belonging to the block
int
getBlockEquationID(int blk, int eq) const
{
return eq_idx_block2orig[blocks[blk].first_equation + eq];
};
}
//! Return the original number of variable belonging to the block
int
getBlockVariableID(int blk, int var) const
{
return endo_idx_block2orig[blocks[blk].first_equation + var];
};
}
//! Return the position of an equation (given by its original index) inside its block
int
getBlockInitialEquationID(int blk, int eq) const
{
return eq_idx_orig2block[eq] - blocks[blk].first_equation;
};
}
//! Return the position of a variable (given by its original index) inside its block
int
getBlockInitialVariableID(int blk, int var) const
{
return endo_idx_orig2block[var] - blocks[blk].first_equation;
};
}
//! Initialize equation_reordered & variable_reordered
void initializeVariablesAndEquations();
......@@ -1004,9 +1006,8 @@ ModelTree::writeModelCFile(const string& basename, const string& mexext,
const filesystem::path model_src_dir {filesystem::path {basename} / "model" / "src"};
auto [d_output, tt_output] = writeModelFileHelper < dynamic
? ExprNodeOutputType::CDynamicModel
: ExprNodeOutputType::CStaticModel > ();
auto [d_output, tt_output] = writeModelFileHelper<dynamic ? ExprNodeOutputType::CDynamicModel
: ExprNodeOutputType::CStaticModel>();
vector<filesystem::path> header_files, object_files;
// TODO: when C++20 support is complete, mark the following strings constexpr
......@@ -2376,9 +2377,9 @@ ModelTree::writeSparseModelJuliaFiles(const string& basename) const
{
assert(heterogeneity_table.empty());
auto [d_sparse_output, tt_sparse_output] = writeModelFileHelper < dynamic
? ExprNodeOutputType::juliaSparseDynamicModel
: ExprNodeOutputType::juliaSparseStaticModel > ();
auto [d_sparse_output, tt_sparse_output]
= writeModelFileHelper<dynamic ? ExprNodeOutputType::juliaSparseDynamicModel
: ExprNodeOutputType::juliaSparseStaticModel>();
filesystem::path julia_dir {filesystem::path {basename} / "model" / "julia"};
// TODO: when C++20 support is complete, mark the following strings constexpr
......@@ -3154,10 +3155,13 @@ ModelTree::writeSetAuxiliaryVariablesFile(const string& basename, bool julia) co
template<bool dynamic>
void
ModelTree::writeComplementarityConditionsFile(const string& basename) const
ModelTree::writeComplementarityConditionsFile(const string& basename,
const optional<int>& heterogeneous_dimension) const
{
// TODO: when C++20 support is complete, mark the following string constexpr
const string funcname {(dynamic ? "dynamic"s : "static"s) + "_complementarity_conditions"};
const string funcname {
(dynamic ? "dynamic"s : "static"s)
+ (heterogeneous_dimension ? "_het"s + to_string(*heterogeneous_dimension + 1) : ""s)
+ "_complementarity_conditions"};
const filesystem::path filename {packageDir(basename) / (funcname + ".m")};
/* Can’t use matlabOutsideModel for output type, since it uses M_.
Static is ok even for the dynamic model, since there are no leads/lags. */
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -303,10 +303,10 @@ EndValStatement::writeJsonOutput(ostream& output) const
output << "]}";
}
EndValLearntInStatement::EndValLearntInStatement(int learnt_in_period_arg,
EndValLearntInStatement::EndValLearntInStatement(variant<int, string> learnt_in_period_arg,
learnt_end_values_t learnt_end_values_arg,
const SymbolTable& symbol_table_arg) :
learnt_in_period {learnt_in_period_arg},
learnt_in_period {move(learnt_in_period_arg)},
learnt_end_values {move(learnt_end_values_arg)},
symbol_table {symbol_table_arg}
{
......@@ -343,9 +343,10 @@ EndValLearntInStatement::writeOutput(ostream& output, [[maybe_unused]] const str
{
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
continue;
output << "struct('learnt_in'," << learnt_in_period << ",'exo_id',"
<< symbol_table.getTypeSpecificID(symb_id) + 1 << ",'type','" << typeToString(type)
<< "'"
output << "struct('learnt_in',";
visit([&](const auto& p) { output << p; }, learnt_in_period);
output << ",'exo_id'," << symbol_table.getTypeSpecificID(symb_id) + 1 << ",'type','"
<< typeToString(type) << "'"
<< ",'value',";
value->writeOutput(output);
output << ");" << endl;
......@@ -356,7 +357,18 @@ EndValLearntInStatement::writeOutput(ostream& output, [[maybe_unused]] const str
void
EndValLearntInStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "endval", "learnt_in": )" << learnt_in_period << R"(, "vals": [)";
output << R"({"statementName": "endval", "learnt_in": )";
visit(
[&]<class T>(const T& p) {
if constexpr (is_same_v<T, int>)
output << p;
else if constexpr (is_same_v<T, string>)
output << '"' << p << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
},
learnt_in_period);
output << R"(, "vals": [)";
for (bool printed_something {false}; auto& [type, symb_id, value] : learnt_end_values)
{
if (symbol_table.getType(symb_id) == SymbolType::unusedEndogenous) // See #82
......
/*
* Copyright © 2003-2023 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -23,6 +23,7 @@
#include <filesystem>
#include <map>
#include <string>
#include <variant>
#include <vector>
#include "ExprNode.hh"
......@@ -101,7 +102,7 @@ public:
class EndValLearntInStatement : public Statement
{
public:
const int learnt_in_period;
const variant<int, string> learnt_in_period;
enum class LearntEndValType
{
level,
......@@ -117,7 +118,8 @@ private:
static string typeToString(LearntEndValType type);
public:
EndValLearntInStatement(int learnt_in_period_arg, learnt_end_values_t learnt_end_values_arg,
EndValLearntInStatement(variant<int, string> learnt_in_period_arg,
learnt_end_values_t learnt_end_values_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -28,6 +28,8 @@
#include "ExprNode.hh"
#include "ParsingDriver.hh"
#include "Statement.hh"
/* NB: the following also imports our specialization of operator<< for location class,
used below in error() and undeclared_model_variable_error() */
#include "WarningConsolidation.hh"
bool
......@@ -113,7 +115,7 @@ ParsingDriver::parse(istream& in, bool debug)
void
ParsingDriver::error(const Dynare::parser::location_type& l, const string& m)
{
create_error_string(l, m, cerr);
cerr << "ERROR: " << l << ": " << m << endl;
exit(EXIT_FAILURE);
}
......@@ -123,54 +125,12 @@ ParsingDriver::error(const string& m)
error(location, m);
}
void
ParsingDriver::create_error_string(const Dynare::parser::location_type& l, const string& m,
ostream& stream)
{
stream << "ERROR: " << *l.begin.filename << ": line " << l.begin.line;
if (l.begin.line == l.end.line)
if (l.begin.column == l.end.column - 1)
stream << ", col " << l.begin.column;
else
stream << ", cols " << l.begin.column << "-" << l.end.column - 1;
else
stream << ", col " << l.begin.column << " -"
<< " line " << l.end.line << ", col " << l.end.column - 1;
stream << ": " << m << endl;
}
void
ParsingDriver::create_error_string(const Dynare::parser::location_type& l, const string& m,
const string& var)
{
ostringstream stream;
create_error_string(l, m, stream);
model_errors.emplace_back(var, stream.str());
}
void
ParsingDriver::model_error(const string& m, const string& var)
{
create_error_string(location, m, var);
}
void
ParsingDriver::undeclared_model_variable_error(const string& m, const string& var)
{
ostringstream stream;
if (!nostrict)
{
stream << "ERROR: " << *location.begin.filename << ": line " << location.begin.line;
if (location.begin.line == location.end.line)
if (location.begin.column == location.end.column - 1)
stream << ", col " << location.begin.column;
else
stream << ", cols " << location.begin.column << "-" << location.end.column - 1;
else
stream << ", col " << location.begin.column << " -"
<< " line " << location.end.line << ", col " << location.end.column - 1;
stream << ": ";
}
stream << "ERROR: " << location << ": ";
stream << m;
if (nostrict)
stream << " automatically declared exogenous.";
......@@ -826,22 +786,26 @@ ParsingDriver::end_endval(bool all_values_required)
}
void
ParsingDriver::end_endval_learnt_in(const string& learnt_in_period)
ParsingDriver::end_endval_learnt_in(variant<int, string> learnt_in_period)
{
int learnt_in_period_int = stoi(learnt_in_period);
if (learnt_in_period_int < 1)
error("endval: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
if (holds_alternative<int>(learnt_in_period))
{
end_endval(false);
return;
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("endval: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_endval(false);
return;
}
}
for (auto [type, symb_id, value] : end_values)
if (mod_file->symbol_table.getType(symb_id) != SymbolType::exogenous)
error("endval(learnt_in=...): " + mod_file->symbol_table.getName(symb_id)
+ " is not an exogenous variable");
mod_file->addStatement(make_unique<EndValLearntInStatement>(
learnt_in_period_int, move(end_values), mod_file->symbol_table));
move(learnt_in_period), move(end_values), mod_file->symbol_table));
end_values.clear();
}
......@@ -913,13 +877,6 @@ void
ParsingDriver::end_model()
{
bool exit_after_write = false;
if (model_errors.size() > 0)
for (auto& it : model_errors)
{
if (it.first.empty())
exit_after_write = true;
cerr << it.second;
}
if (undeclared_model_variable_errors.size() > 0)
for (auto& it : undeclared_model_variable_errors)
......@@ -995,6 +952,11 @@ ParsingDriver::end_mshocks(bool overwrite, bool relative_to_initval)
void
ParsingDriver::end_shocks_surprise(bool overwrite)
{
if (ranges::any_of(views::values(det_shocks), [](auto& v) {
return ranges::any_of(views::keys(v),
[](auto& p) { return !holds_alternative<pair<int, int>>(p); });
}))
error("shocks(surprise): dates are not allowed in the 'periods' keyword");
mod_file->addStatement(
make_unique<ShocksSurpriseStatement>(overwrite, move(det_shocks), mod_file->symbol_table));
det_shocks.clear();
......@@ -1005,92 +967,110 @@ ParsingDriver::end_shocks_surprise(bool overwrite)
}
void
ParsingDriver::end_shocks_learnt_in(const string& learnt_in_period, bool overwrite)
ParsingDriver::end_shocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite)
{
int learnt_in_period_int = stoi(learnt_in_period);
if (learnt_in_period_int < 1)
error("shocks: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
if (holds_alternative<int>(learnt_in_period))
{
end_shocks(overwrite);
return;
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("shocks: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_shocks(overwrite);
return;
}
for (auto& storage : {det_shocks, learnt_shocks_add, learnt_shocks_multiply})
for (auto& [symb_id, vals] : storage)
for (const auto& [period_range, expr] : vals)
if (holds_alternative<pair<int, int>>(period_range))
if (int period1 = get<pair<int, int>>(period_range).first;
period1 < learnt_in_period_int)
error("shocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt ("
+ to_string(learnt_in_period_int) + ")");
}
for (auto& storage : {det_shocks, learnt_shocks_add, learnt_shocks_multiply})
for (auto& [symb_id, vals] : storage)
for (auto [period1, period2, expr] : vals)
if (period1 < learnt_in_period_int)
error("shocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt (" + learnt_in_period
+ ")");
// Aggregate the three types of shocks
ShocksLearntInStatement::learnt_shocks_t learnt_shocks;
for (const auto& [id, v] : det_shocks)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::level, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::level, period_range, value);
learnt_shocks[id] = v2;
}
for (const auto& [id, v] : learnt_shocks_add)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::add, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::add, period_range, value);
learnt_shocks[id] = v2;
}
for (const auto& [id, v] : learnt_shocks_multiply)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiply, period1, period2,
value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(ShocksLearntInStatement::LearntShockType::multiply, period_range, value);
learnt_shocks[id] = v2;
}
mod_file->addStatement(make_unique<ShocksLearntInStatement>(
learnt_in_period_int, overwrite, move(learnt_shocks), mod_file->symbol_table));
move(learnt_in_period), overwrite, move(learnt_shocks), mod_file->symbol_table));
det_shocks.clear();
learnt_shocks_add.clear();
learnt_shocks_multiply.clear();
}
void
ParsingDriver::end_mshocks_learnt_in(const string& learnt_in_period, bool overwrite,
ParsingDriver::end_mshocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite,
bool relative_to_initval)
{
int learnt_in_period_int = stoi(learnt_in_period);
if (learnt_in_period_int < 1)
error("mshocks: value '" + learnt_in_period + "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
if (holds_alternative<int>(learnt_in_period))
{
end_mshocks(overwrite, relative_to_initval);
return;
int learnt_in_period_int = get<int>(learnt_in_period);
if (learnt_in_period_int < 1)
error("mshocks: value '" + to_string(learnt_in_period_int)
+ "' is not allowed for 'learnt_in' option");
if (learnt_in_period_int == 1)
{
end_mshocks(overwrite, relative_to_initval);
return;
}
for (auto& [symb_id, vals] : det_shocks)
for (const auto& [period_range, expr] : vals)
if (holds_alternative<pair<int, int>>(period_range))
if (int period1 = get<pair<int, int>>(period_range).first;
period1 < learnt_in_period_int)
error("mshocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt ("
+ to_string(learnt_in_period_int) + ")");
}
for (auto& [symb_id, vals] : det_shocks)
for (auto [period1, period2, expr] : vals)
if (period1 < learnt_in_period_int)
error("mshocks: for variable " + mod_file->symbol_table.getName(symb_id)
+ ", shock period (" + to_string(period1)
+ ") is earlier than the period in which the shock is learnt (" + learnt_in_period
+ ")");
ShocksLearntInStatement::learnt_shocks_t learnt_shocks;
const auto type {relative_to_initval
? ShocksLearntInStatement::LearntShockType::multiplyInitialSteadyState
: ShocksLearntInStatement::LearntShockType::multiplySteadyState};
for (const auto& [id, v] : det_shocks)
{
vector<tuple<ShocksLearntInStatement::LearntShockType, int, int, expr_t>> v2;
for (auto [period1, period2, value] : v)
v2.emplace_back(type, period1, period2, value);
vector<tuple<ShocksLearntInStatement::LearntShockType,
AbstractShocksStatement::period_range_t, expr_t>>
v2;
for (const auto& [period_range, value] : v)
v2.emplace_back(type, period_range, value);
learnt_shocks[id] = v2;
}
mod_file->addStatement(make_unique<ShocksLearntInStatement>(
learnt_in_period_int, overwrite, move(learnt_shocks), mod_file->symbol_table));
move(learnt_in_period), overwrite, move(learnt_shocks), mod_file->symbol_table));
det_shocks.clear();
if (!learnt_shocks_add.empty())
error("mshocks: 'add' keyword not allowed");
......@@ -1109,7 +1089,8 @@ ParsingDriver::end_heteroskedastic_shocks(bool overwrite)
}
void
ParsingDriver::add_det_shock(const string& var, const vector<pair<int, int>>& periods,
ParsingDriver::add_det_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, DetShockType type)
{
switch (type)
......@@ -1137,10 +1118,10 @@ ParsingDriver::add_det_shock(const string& var, const vector<pair<int, int>>& pe
error("shocks/conditional_forecast_paths: variable " + var
+ ": number of periods is different from number of shock values");
vector<tuple<int, int, expr_t>> v;
vector<pair<AbstractShocksStatement::period_range_t, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i].first, periods[i].second, values[i]);
v.emplace_back(periods[i], values[i]);
switch (type)
{
......@@ -1158,11 +1139,15 @@ ParsingDriver::add_det_shock(const string& var, const vector<pair<int, int>>& pe
}
void
ParsingDriver::add_heteroskedastic_shock(const string& var, const vector<pair<int, int>>& periods,
const vector<expr_t>& values, bool scales)
ParsingDriver::add_heteroskedastic_shock(
const string& var, const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, bool scales)
{
check_symbol_is_exogenous(var, false);
if (ranges::any_of(periods, [](auto& p) { return !holds_alternative<pair<int, int>>(p); }))
error("heteroskedastic_shocks: dates are not allowed in the 'periods' keyword");
int symb_id = mod_file->symbol_table.getID(var);
if ((!scales && heteroskedastic_shocks_values.contains(symb_id))
......@@ -1175,7 +1160,10 @@ ParsingDriver::add_heteroskedastic_shock(const string& var, const vector<pair<in
vector<tuple<int, int, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i].first, periods[i].second, values[i]);
{
auto [period1, period2] = get<pair<int, int>>(periods[i]);
v.emplace_back(period1, period2, values[i]);
}
if (scales)
heteroskedastic_shocks_scales[symb_id] = v;
......@@ -1786,11 +1774,9 @@ ParsingDriver::set_unit_root_vars()
}
void
ParsingDriver::set_time(const string& arg)
ParsingDriver::set_time(string period)
{
option_date("initial_period", arg);
mod_file->addStatement(make_unique<SetTimeStatement>(move(options_list)));
options_list.clear();
mod_file->addStatement(make_unique<SetTimeStatement>(move(period)));
}
void
......@@ -2678,6 +2664,11 @@ ParsingDriver::plot_conditional_forecast(const optional<string>& periods,
void
ParsingDriver::conditional_forecast_paths()
{
if (ranges::any_of(views::values(det_shocks), [](auto& v) {
return ranges::any_of(views::keys(v),
[](auto& p) { return !holds_alternative<pair<int, int>>(p); });
}))
error("conditional_forecast_paths: dates are not allowed in the 'periods' keyword");
mod_file->addStatement(
make_unique<ConditionalForecastPathsStatement>(move(det_shocks), mod_file->symbol_table));
det_shocks.clear();
......@@ -2751,6 +2742,9 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_
}
}()};
if (heterogeneous_model)
error("'mcp' tags are not allowed in heterogeneous model blocks");
if (mod_file->symbol_table.getType(symb_id) != SymbolType::endogenous)
error("Left-hand side of expression in 'mcp' tag is not an endogenous variable");
......@@ -2770,11 +2764,14 @@ ParsingDriver::add_model_equal(expr_t arg1, expr_t arg2, map<string, string> eq_
try
{
matched_complementarity_condition
= complementarity_condition->matchComplementarityCondition();
= heterogeneous_model ? complementarity_condition->matchComplementarityCondition(
heterogeneous_model->heterogeneity_dimension)
: complementarity_condition->matchComplementarityCondition();
}
catch (ExprNode::MatchFailureException& e)
{
error("Complementarity condition has an incorrect form: " + e.message);
error("Complementarity condition has an incorrect form"s
+ (e.message.empty() ? ""s : ": "s + e.message));
}
if (eq_tags.contains("static"))
......@@ -3750,6 +3747,29 @@ ParsingDriver::perfect_foresight_with_expectation_errors_solver()
options_list.clear();
}
void
ParsingDriver::perfect_foresight_controlled_paths(
const vector<tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>,
string>>& paths,
variant<int, string> learnt_in_period)
{
PerfectForesightControlledPathsStatement::paths_t paths_transformed;
for (const auto& [exogenize, periods, values, endogenize] : paths)
{
int exogenize_id = mod_file->symbol_table.getID(exogenize);
int endogenize_id = mod_file->symbol_table.getID(endogenize);
vector<pair<AbstractShocksStatement::period_range_t, expr_t>> v;
for (size_t i = 0; i < periods.size(); i++)
v.emplace_back(periods[i], values[i]);
paths_transformed.emplace_back(exogenize_id, move(v), endogenize_id);
}
mod_file->addStatement(make_unique<PerfectForesightControlledPathsStatement>(
move(paths_transformed), move(learnt_in_period), mod_file->symbol_table));
}
void
ParsingDriver::method_of_moments()
{
......
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -29,12 +29,12 @@
#include <stack>
#include <string>
#include <string_view>
#include <variant>
#include <vector>
#include "ModFile.hh"
#include "SymbolList.hh"
class ParsingDriver;
#include "DynareBison.hh"
#include "ExprNode.hh"
......@@ -74,9 +74,6 @@ public:
//! Increment the location counter given a token
static void location_increment(Dynare::parser::location_type* yylloc, const char* yytext);
//! Count parens in dates statement
int dates_parens_nb;
};
//! Drives the scanning and parsing of the .mod file, and constructs its abstract representation
......@@ -273,7 +270,6 @@ private:
bool nostrict;
vector<pair<string, string>> model_errors;
vector<pair<string, string>> undeclared_model_variable_errors;
//! True when parsing the epilogue block
......@@ -328,15 +324,8 @@ public:
//! Error handler with explicit location (used in model block, accumulating error messages to be
//! printed later)
void model_error(const string& m, const string& var);
void undeclared_model_variable_error(const string& m, const string& var);
//! Code shared between model_error() and error()
void create_error_string(const Dynare::parser::location_type& l, const string& m,
const string& var);
void create_error_string(const Dynare::parser::location_type& l, const string& m,
ostream& stream);
//! Check if a given symbol exists in the parsing context, and is not a mod file local variable
bool symbol_exists_and_is_not_modfile_local_or_external_function(const string& s);
//! Sets mode of ModelTree class to use C output
......@@ -449,7 +438,7 @@ public:
//! Writes end of an endval block
void end_endval(bool all_values_required);
//! Writes end of an endval(learnt_in=…) block
void end_endval_learnt_in(const string& learnt_in_period);
void end_endval_learnt_in(variant<int, string> learnt_in_period);
//! Writes end of an histval block
void end_histval(bool all_values_required);
//! Writes end of an homotopy_setup block
......@@ -476,11 +465,11 @@ public:
//! Writes a shocks(surprise) statement
void end_shocks_surprise(bool overwrite);
//! Writes a shocks(learnt_in=…) block
void end_shocks_learnt_in(const string& learnt_in_period, bool overwrite);
void end_shocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite);
// For a shocks(heterogeneity=…) block
void end_heterogeneous_shocks(const string& heterogeneity_dimension, bool overwrite);
//! Writes a mshocks(learnt_in=…) block
void end_mshocks_learnt_in(const string& learnt_in_period, bool overwrite,
void end_mshocks_learnt_in(variant<int, string> learnt_in_period, bool overwrite,
bool relative_to_initval);
//! Writes a heteroskedastic_shocks statement
void end_heteroskedastic_shocks(bool overwrite);
......@@ -493,10 +482,12 @@ public:
multiply, // for “multiply” in “shocks(learnt_in)”
conditional_forecast
};
void add_det_shock(const string& var, const vector<pair<int, int>>& periods,
void add_det_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, DetShockType type);
//! Adds a heteroskedastic shock (either values or scales)
void add_heteroskedastic_shock(const string& var, const vector<pair<int, int>>& periods,
void add_heteroskedastic_shock(const string& var,
const vector<AbstractShocksStatement::period_range_t>& periods,
const vector<expr_t>& values, bool scales);
//! Adds a std error shock
void add_stderr_shock(const string& var, expr_t value);
......@@ -571,8 +562,8 @@ public:
void osr_params_bounds();
//! Add a line in an osr params block
void add_osr_params_element();
//! Sets the frequency of the data
void set_time(const string& arg);
// Sets the initial period for estimation
void set_time(string period);
//! Estimation Data
void estimation_data();
//! Sets the prior for a parameter
......@@ -930,6 +921,10 @@ public:
void perfect_foresight_solver();
void perfect_foresight_with_expectation_errors_setup();
void perfect_foresight_with_expectation_errors_solver();
void perfect_foresight_controlled_paths(
const vector<tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>,
string>>& paths,
variant<int, string> learnt_in_period);
void prior_posterior_function(bool prior_func);
//! Method of Moments estimation statement
void method_of_moments();
......
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -19,11 +19,43 @@
#include <cassert>
#include <cstdlib>
#include <functional>
#include <iostream>
#include <utility>
#include "Shocks.hh"
static auto print_matlab_period_range = []<class T>(ostream& output, const T& arg) {
if constexpr (is_same_v<T, pair<int, int>>)
output << arg.first << ":" << arg.second;
else if constexpr (is_same_v<T, pair<string, string>>)
output << "(" << arg.first << "):(" << arg.second << ")";
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
static auto print_json_period_range = []<class T>(ostream& output, const T& arg) {
if constexpr (is_same_v<T, pair<int, int>>)
output << R"("period1": )" << arg.first << ", "
<< R"("period2": )" << arg.second;
else if constexpr (is_same_v<T, pair<string, string>>)
output << R"("period1": ")" << arg.first << R"(", )"
<< R"("period2": ")" << arg.second << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
static auto print_matlab_learnt_in = [](ostream& output, const auto& p) { output << p; };
static auto print_json_learnt_in = []<class T>(ostream& output, const T& p) {
if constexpr (is_same_v<T, int>)
output << p;
else if constexpr (is_same_v<T, string>)
output << '"' << p << '"';
else
static_assert(always_false_v<T>, "Non-exhaustive visitor!");
};
AbstractShocksStatement::AbstractShocksStatement(bool overwrite_arg, ShockType type_arg,
det_shocks_t det_shocks_arg,
const SymbolTable& symbol_table_arg) :
......@@ -39,12 +71,14 @@ AbstractShocksStatement::writeDetShocks(ostream& output) const
{
for (const auto& [id, shock_vec] : det_shocks)
for (bool exo_det = (symbol_table.getType(id) == SymbolType::exogenousDet);
const auto& [period1, period2, value] : shock_vec)
const auto& [period_range, value] : shock_vec)
{
output << "M_.det_shocks = [ M_.det_shocks;" << endl
<< boolalpha << "struct('exo_det'," << exo_det << ",'exo_id',"
<< symbol_table.getTypeSpecificID(id) + 1 << ",'type','" << typeToString(type) << "'"
<< ",'periods'," << period1 << ":" << period2 << ",'value',";
<< ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'value',";
value->writeOutput(output);
output << ") ];" << endl;
}
......@@ -60,13 +94,13 @@ AbstractShocksStatement::writeJsonDetShocks(ostream& output) const
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [period_range, value] : shock_vec)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("value": ")";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -461,8 +495,9 @@ ShocksSurpriseStatement::writeOutput(ostream& output, [[maybe_unused]] const str
else
output << "M_.surprise_shocks = [ M_.surprise_shocks;" << endl;
for (const auto& [id, shock_vec] : surprise_shocks)
for (const auto& [period1, period2, value] : shock_vec)
for (const auto& [period_range, value] : shock_vec)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
output << "struct('exo_id'," << symbol_table.getTypeSpecificID(id) + 1 << ",'periods',"
<< period1 << ":" << period2 << ",'value',";
value->writeOutput(output);
......@@ -483,8 +518,9 @@ ShocksSurpriseStatement::writeJsonOutput(ostream& output) const
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [period_range, value] : shock_vec)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
......@@ -498,10 +534,11 @@ ShocksSurpriseStatement::writeJsonOutput(ostream& output) const
output << "]}";
}
ShocksLearntInStatement::ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
ShocksLearntInStatement::ShocksLearntInStatement(variant<int, string> learnt_in_period_arg,
bool overwrite_arg,
learnt_shocks_t learnt_shocks_arg,
const SymbolTable& symbol_table_arg) :
learnt_in_period {learnt_in_period_arg},
learnt_in_period {move(learnt_in_period_arg)},
overwrite {overwrite_arg},
learnt_shocks {move(learnt_shocks_arg)},
symbol_table {symbol_table_arg}
......@@ -539,18 +576,29 @@ ShocksLearntInStatement::writeOutput(ostream& output, [[maybe_unused]] const str
[[maybe_unused]] bool minimal_workspace) const
{
if (overwrite)
output << "if ~isempty(M_.learnt_shocks)" << endl
<< " M_.learnt_shocks = M_.learnt_shocks([M_.learnt_shocks.learnt_in] ~= "
<< learnt_in_period << ");" << endl
<< "end" << endl;
{
output << "if ~isempty(M_.learnt_shocks)" << endl
<< " M_.learnt_shocks = M_.learnt_shocks(cellfun(@(x) ~isa(x, '";
if (holds_alternative<int>(learnt_in_period))
output << "numeric";
else
output << "dates";
output << "') || x ~= ";
/* NB: date expression not parenthesized since it can only contain a + operator, which has
higher precedence than ~= and || */
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ", {M_.learnt_shocks.learnt_in}));" << endl << "end" << endl;
}
output << "M_.learnt_shocks = [ M_.learnt_shocks;" << endl;
for (const auto& [id, shock_vec] : learnt_shocks)
for (const auto& [type, period1, period2, value] : shock_vec)
for (const auto& [type, period_range, value] : shock_vec)
{
output << "struct('learnt_in'," << learnt_in_period << ",'exo_id',"
<< symbol_table.getTypeSpecificID(id) + 1 << ",'periods'," << period1 << ":"
<< period2 << ",'type','" << typeToString(type) << "'"
output << "struct('learnt_in',";
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ",'exo_id'," << symbol_table.getTypeSpecificID(id) + 1 << ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'type','" << typeToString(type) << "'"
<< ",'value',";
value->writeOutput(output);
output << ");" << endl;
......@@ -562,21 +610,22 @@ void
ShocksLearntInStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "shocks")"
<< R"(, "learnt_in": )" << learnt_in_period << R"(, "overwrite": )" << boolalpha
<< overwrite << R"(, "learnt_shocks": [)";
<< R"(, "learnt_in": )";
visit(bind(print_json_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << R"(, "overwrite": )" << boolalpha << overwrite << R"(, "learnt_shocks": [)";
for (bool printed_something {false}; const auto& [id, shock_vec] : learnt_shocks)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [type, period1, period2, value] : shock_vec)
for (bool printed_something2 {false}; const auto& [type, period_range, value] : shock_vec)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("type": ")" << typeToString(type) << R"(", )"
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "type": ")" << typeToString(type) << R"(", )"
<< R"("value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
......@@ -805,9 +854,12 @@ ConditionalForecastPathsStatement::computePathLength(
{
int length {0};
for (const auto& [ignore, elems] : paths)
for (auto& [period1, period2, value] : elems)
// Period1 < Period2, as enforced in ParsingDriver::add_period()
length = max(length, period2);
for (auto& [period_range, value] : elems)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
// Period1 < Period2, as enforced in ParsingDriver::add_period()
length = max(length, period2);
}
return length;
}
......@@ -827,13 +879,13 @@ ConditionalForecastPathsStatement::writeOutput(ostream& output,
else
output << "constrained_vars_ = [constrained_vars_; "
<< symbol_table.getTypeSpecificID(id) + 1 << "];" << endl;
for (const auto& [period1, period2, value] : elems)
for (int j = period1; j <= period2; j++)
{
output << "constrained_paths_(" << k << "," << j << ")=";
value->writeOutput(output);
output << ";" << endl;
}
for (const auto& [period_range, value] : elems)
{
auto [period1, period2] = get<pair<int, int>>(period_range);
output << "constrained_paths_(" << k << "," << period1 << ":" << period2 << ")=";
value->writeOutput(output);
output << ";" << endl;
}
k++;
}
}
......@@ -849,13 +901,13 @@ ConditionalForecastPathsStatement::writeJsonOutput(ostream& output) const
output << ", ";
output << R"({"var": ")" << symbol_table.getName(id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [period1, period2, value] : elems)
for (bool printed_something2 {false}; const auto& [period_range, value] : elems)
{
if (exchange(printed_something2, true))
output << ", ";
output << R"({"period1": )" << period1 << ", "
<< R"("period2": )" << period2 << ", "
<< R"("value": ")";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
......@@ -864,6 +916,65 @@ ConditionalForecastPathsStatement::writeJsonOutput(ostream& output) const
output << "]}";
}
PerfectForesightControlledPathsStatement::PerfectForesightControlledPathsStatement(
paths_t paths_arg, variant<int, string> learnt_in_period_arg,
const SymbolTable& symbol_table_arg) :
paths {move(paths_arg)},
learnt_in_period {move(learnt_in_period_arg)},
symbol_table {symbol_table_arg}
{
}
void
PerfectForesightControlledPathsStatement::writeOutput(ostream& output,
[[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
for (const auto& [exogenize_id, constraints, endogenize_id] : paths)
for (const auto& [period_range, value] : constraints)
{
output << "M_.perfect_foresight_controlled_paths = [ "
"M_.perfect_foresight_controlled_paths;"
<< endl
<< "struct('exogenize_id'," << symbol_table.getTypeSpecificID(exogenize_id) + 1
<< ",'periods',";
visit(bind(print_matlab_period_range, ref(output), placeholders::_1), period_range);
output << ",'value',";
value->writeOutput(output);
output << ",'endogenize_id'," << symbol_table.getTypeSpecificID(endogenize_id) + 1
<< ",'learnt_in',";
visit(bind(print_matlab_learnt_in, ref(output), placeholders::_1), learnt_in_period);
output << ") ];" << endl;
}
}
void
PerfectForesightControlledPathsStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "perfect_foresight_controlled_paths")"
<< R"(, "paths": [)";
for (bool printed_something {false};
const auto& [exogenize_id, constraints, endogenize_id] : paths)
{
if (exchange(printed_something, true))
output << ", ";
output << R"({"exogenize": ")" << symbol_table.getName(exogenize_id) << R"(", )"
<< R"("values": [)";
for (bool printed_something2 {false}; const auto& [period_range, value] : constraints)
{
if (exchange(printed_something2, true))
output << ", ";
output << "{";
visit(bind(print_json_period_range, ref(output), placeholders::_1), period_range);
output << R"(, "value": ")";
value->writeJsonOutput(output, {}, {});
output << R"("})";
}
output << R"(], "endogenize": ")" << symbol_table.getName(endogenize_id) << R"("})";
}
output << "]}";
}
MomentCalibration::MomentCalibration(constraints_t constraints_arg,
const SymbolTable& symbol_table_arg) :
constraints {move(constraints_arg)}, symbol_table {symbol_table_arg}
......
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -22,6 +22,7 @@
#include <map>
#include <string>
#include <variant>
#include <vector>
#include "ExprNode.hh"
......@@ -34,11 +35,13 @@ using namespace std;
class AbstractShocksStatement : public Statement
{
public:
// The tuple is (period1, period2, value)
using det_shocks_t = map<int, vector<tuple<int, int, expr_t>>>;
// A period range is either two indices (1-based), or two dates (from dseries)
using period_range_t = variant<pair<int, int>, pair<string, string>>;
// The pair is (period range, value)
using det_shocks_t = map<int, vector<pair<period_range_t, expr_t>>>;
enum class ShockType
{
level, // The value is the level of the exogenous (“values” statement in “shocks”)
level, // The value is the level of the exogenous (“values” statement in “shocks”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state
// (“values” statement in “mshocks”)
multiplyInitialSteadyState // The value is the ratio of the exogenous over its initial steady
......@@ -123,14 +126,14 @@ public:
class ShocksLearntInStatement : public Statement
{
public:
const int learnt_in_period;
const variant<int, string> learnt_in_period;
//! Does this “shocks(learnt_in=…)” or “mshocks(learnt_in=…)” block replace the previous ones?
const bool overwrite;
enum class LearntShockType
{
level, // The value is the level of the exogenous (“values” statement in “shocks(learnt_in=…)”)
add, // The value is the additive change of the exogenous compared to previous information
// period (“add” statement in “shocks(learnt_in=…)”)
add, // The value is the additive change of the exogenous compared to previous information
// period (“add” statement in “shocks(learnt_in=…)”)
multiply, // The value is the multiplicative change of the exogenous compared to previous
// information period (“multiply” statement in “shocks(learnt_in=…)”)
multiplySteadyState, // The value is the ratio of the exogenous over its (terminal) steady state
......@@ -140,8 +143,9 @@ public:
// state as anticipated in the same informational period (“values”
// statement in “mshocks(learnt_in=…, relative_to_initval)”)
};
// The tuple is (type, period1, period2, value)
using learnt_shocks_t = map<int, vector<tuple<LearntShockType, int, int, expr_t>>>;
// The tuple is (type, period range, value)
using learnt_shocks_t
= map<int, vector<tuple<LearntShockType, AbstractShocksStatement::period_range_t, expr_t>>>;
const learnt_shocks_t learnt_shocks;
private:
......@@ -149,7 +153,7 @@ private:
static string typeToString(LearntShockType type);
public:
ShocksLearntInStatement(int learnt_in_period_arg, bool overwrite_arg,
ShocksLearntInStatement(variant<int, string> learnt_in_period_arg, bool overwrite_arg,
learnt_shocks_t learnt_shocks_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -212,6 +216,26 @@ public:
static int computePathLength(const AbstractShocksStatement::det_shocks_t& paths);
};
class PerfectForesightControlledPathsStatement : public Statement
{
public:
// (exogenize_id, vector of (period range, value), endogenize_id)
using paths_t
= vector<tuple<int, vector<pair<AbstractShocksStatement::period_range_t, expr_t>>, int>>;
private:
const paths_t paths;
const variant<int, string> learnt_in_period;
const SymbolTable& symbol_table;
public:
PerfectForesightControlledPathsStatement(paths_t paths_arg,
variant<int, string> learnt_in_period_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class MomentCalibration : public Statement
{
public:
......
......@@ -49,7 +49,7 @@ NativeStatement::writeOutput(ostream& output, [[maybe_unused]] const string& bas
otherwise 2023M12 will be matched as 2023M1 (see dynare#1918). Technically, it seems that
boost::xpressive does not look for the longest match in an alternation, but stops at the first
match from left to right. */
string date_regex = R"((-?\d+([YyAa]|[Mm](1[0-2]|[1-9])|[Qq][1-4]|[SsHh][1-2])))";
string date_regex = R"((-?\d+([YyAa]|[Mm](1[0-2]|[1-9])|[Qq][1-4]|[SsHh][12])))";
/* NB: the following dance around the dollar sign (exclude it from lookbehind, then use it in a
temporary string after the first replace, then remove it in the second replace) has a purpose:
it allows the user to disable the substitution mechanism. For example, if the user writes
......
......@@ -30,6 +30,10 @@
#include "SymbolList.hh"
#include "WarningConsolidation.hh"
// Helper constant for visitors
template<class>
inline constexpr bool always_false_v {false};
struct ModFileStructure
{
//! Whether check is present
......@@ -315,7 +319,8 @@ public:
/* 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>
requires invocable<Visitor, OptionValue> decltype(auto)
requires invocable<Visitor, OptionValue>
decltype(auto)
visit(const string& name, Visitor&& vis) const
{
auto it = options.find(name);
......@@ -332,9 +337,6 @@ public:
private:
map<string, OptionValue> options;
void writeOutputCommon(ostream& output, const string& option_group) const;
// Helper constant for visitors
template<class>
static constexpr bool always_false_v {false};
};
#endif
......@@ -63,7 +63,7 @@ public:
empty() const
{
return symbols.empty();
};
}
//! Return the list of symbols
[[nodiscard]] vector<string> getSymbols() const;
};
......
......@@ -352,7 +352,7 @@ public:
AuxVarsSize() const
{
return aux_vars.size();
};
}
//! Tests if symbol already exists
[[nodiscard]] inline bool exists(const string& name) const;
//! Get symbol name (by ID)
......
/*
* Copyright © 2012-2022 Dynare Team
* Copyright © 2012-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -18,39 +18,33 @@
*/
#include "WarningConsolidation.hh"
#include <ostream>
WarningConsolidation&
operator<<(WarningConsolidation& wcc, const string& warning)
ostream&
operator<<(ostream& stream, const Dynare::location& l)
{
if (wcc.no_warn)
return wcc;
cerr << warning;
wcc.addWarning(warning);
return wcc;
};
stream << *l.begin.filename << ": line " << l.begin.line;
if (l.begin.line == l.end.line)
if (l.begin.column == l.end.column - 1)
stream << ", col " << l.begin.column;
else
stream << ", cols " << l.begin.column << "-" << l.end.column - 1;
else
stream << ", col " << l.begin.column << " -"
<< " line " << l.end.line << ", col " << l.end.column - 1;
return stream;
}
WarningConsolidation&
operator<<(WarningConsolidation& wcc, const Dynare::location& loc)
void
WarningConsolidation::incrementWarnings(const string& msg)
{
if (wcc.no_warn)
return wcc;
stringstream ostr;
Dynare::position last = loc.end - 1;
ostr << loc.begin;
if (last.filename && (!loc.begin.filename || *loc.begin.filename != *last.filename))
ostr << '-' << last;
else if (loc.begin.line != last.line)
ostr << '-' << last.line << '.' << last.column;
else if (loc.begin.column != last.column)
ostr << '-' << last.column;
cerr << ostr.str();
wcc.addWarning(ostr.str());
return wcc;
};
size_t p {0};
while ((p = msg.find('\n', p)) != string::npos)
{
p++;
num_warnings++;
}
}
WarningConsolidation&
operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&))
......@@ -58,49 +52,12 @@ operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&))
if (wcc.no_warn)
return wcc;
cerr << pf;
wcc.addWarning(pf);
return wcc;
}
void
WarningConsolidation::writeOutput(ostream& output) const
{
if (warnings.str().empty())
return;
ostringstream ostr;
ostr << pf;
output << "disp([char(10) 'Dynare Preprocessor Warning(s) Encountered:']);" << endl;
bool writedisp = true;
string warningsstr = warnings.str();
for (size_t i = 0; i < warningsstr.length(); i++)
{
if (writedisp)
{
output << "disp(' ";
writedisp = false;
}
cerr << ostr.str();
if (warningsstr[i] != '\n')
output << warningsstr[i];
else
{
output << "');" << endl;
if (i + 1 < warningsstr.length())
writedisp = true;
}
}
}
wcc.incrementWarnings(ostr.str());
int
WarningConsolidation::countWarnings() const
{
size_t p = 0;
int n = 0;
while ((p = warnings.str().find('\n', p)) != string::npos)
{
p++;
n++;
}
return n;
return wcc;
}
/*
* Copyright © 2012-2023 Dynare Team
* Copyright © 2012-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -21,45 +21,64 @@
#define WARNING_CONSOLIDATION_HH
#include "DynareBisonLocation.hh"
#include <iostream>
#include <ostream>
#include <sstream>
#include <string>
using namespace std;
//! Stores Warnings issued by the Preprocessor
/* Provide our implementation of operator<< with locations in DynareBison.hh. Note that the
following is a template specialization of the version provided in DynareBisonLocation.hh.
Ideally it should go into DynareBisonLocation.hh, but there does not seem to be a way to achieve
that. */
ostream& operator<<(ostream& stream, const Dynare::location& l);
class WarningConsolidation
{
private:
stringstream warnings;
bool no_warn;
const bool no_warn;
int num_warnings {0};
// Increases the warning counter by as many newlines as there are in the message
void incrementWarnings(const string& msg);
public:
explicit WarningConsolidation(bool no_warn_arg) : no_warn {no_warn_arg}
{
}
//! Add A Warning to the StringStream
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, const string& warning);
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, const Dynare::location& loc);
// Generic function to print something to the warning stream
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, auto&& warning);
/* Print std::endl to the warning stream. Unfortunately, since std::endl is a template of
functions, it cannot be bound to the universal reference of the generic function, hence the
need for this specialization. */
friend WarningConsolidation& operator<<(WarningConsolidation& wcc, ostream& (*pf)(ostream&));
void
addWarning(const string& w)
{
warnings << w;
};
void
addWarning(ostream& (*pf)(ostream&))
int
numWarnings() const
{
warnings << pf;
};
//! Write Warnings to m file
void writeOutput(ostream& output) const;
//! Count warnings
/*! This is done in a very lousy way, by counting newlines in the
stringstream... */
int countWarnings() const;
return num_warnings;
}
};
WarningConsolidation&
operator<<(WarningConsolidation& wcc, auto&& warning)
{
if (wcc.no_warn)
return wcc;
ostringstream ostr;
ostr << warning;
cerr << ostr.str();
wcc.incrementWarnings(ostr.str());
return wcc;
}
#endif
......@@ -241,9 +241,9 @@ Real::normpdf(const BaseTypePtr& btp1, const BaseTypePtr& btp2) const
auto btp22 = dynamic_pointer_cast<Real>(btp2);
if (!btp12 || !btp22)
throw StackTrace("Type mismatch for operands of `normpdf` operator");
return make_shared<Real>((1
/ (btp22->value * std::sqrt(2 * numbers::pi)
* std::exp(pow((value - btp12->value) / btp22->value, 2) / 2))));
return make_shared<Real>(1
/ (btp22->value * std::sqrt(2 * numbers::pi)
* std::exp(pow((value - btp12->value) / btp22->value, 2) / 2)));
}
RealPtr
......@@ -254,7 +254,7 @@ Real::normcdf(const BaseTypePtr& btp1, const BaseTypePtr& btp2) const
if (!btp12 || !btp22)
throw StackTrace("Type mismatch for operands of `normpdf` operator");
return make_shared<Real>(
(0.5 * (1 + std::erf((value - btp12->value) / btp22->value / numbers::sqrt2))));
0.5 * (1 + std::erf((value - btp12->value) / btp22->value / numbers::sqrt2)));
}
BaseTypePtr
......@@ -314,7 +314,7 @@ String::is_equal(const BaseTypePtr& btp) const
BoolPtr
String::cast_bool([[maybe_unused]] Environment& env) const
{
auto f = [](const char& a, const char& b) { return (tolower(a) == tolower(b)); };
auto f = [](const char& a, const char& b) { return tolower(a) == tolower(b); };
if (ranges::equal(value, "true"s, f))
return make_shared<Bool>(true);
......
// -*- C++ -*-
/*
* Copyright © 2019-2023 Dynare Team
* Copyright © 2019-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -28,10 +28,6 @@
%define parse.error verbose
%define parse.trace
%code requires {
namespace macro { class Driver; }
}
%param { macro::Driver& driver }
%locations
......@@ -43,6 +39,9 @@ namespace macro { class Driver; }
%code requires {
#include "Directives.hh"
namespace macro { class Driver; }
using namespace macro;
}
......