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

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
Show changes
Commits on Source (59)
Showing with 1322 additions and 348 deletions
......@@ -11,9 +11,12 @@ BreakInheritanceList: AfterColon
Cpp11BracedListStyle: true
DeriveLineEnding: false
IndentPPDirectives: AfterHash
InsertNewlineAtEOF: true
PackConstructorInitializers: NextLine
PPIndentWidth: 1
PointerAlignment: Left
# RemoveParentheses: ReturnStatement
# RemoveSemicolon: true
SpaceAfterTemplateKeyword: false
SpaceBeforeParens: ControlStatements
SpaceBeforeCpp11BracedList: true
variables:
TERM: linux
MINGW64_BOOST_VERSION: 1.85.0-2
MINGW64_BOOST_VERSION: 1.86.0-7
WGET_OPTIONS: '--no-verbose --no-use-server-timestamps --retry-connrefused --retry-on-host-error'
# To ensure that "false && true" fails, see https://gitlab.com/gitlab-org/gitlab-runner/-/issues/25394#note_412609647
FF_ENABLE_BASH_EXIT_CODE_CHECK: 'true'
......@@ -77,3 +77,16 @@ test_clang_format:
- meson setup build-clang-format
- ninja -C build-clang-format clang-format-check
needs: []
test_clang_tidy:
stage: test
script:
# Hack needed for meson < 1.6.0 which only looks for unversioned clang-tidy
- mkdir -p ~/.local/bin && ln -s /usr/bin/clang-tidy-19 ~/.local/bin/clang-tidy
- export PATH="$HOME/.local/bin:$PATH"
- meson setup build-clang-tidy
# Generate Flex and Bison files
- meson compile -C build-clang-tidy
- ninja -C build-clang-tidy clang-tidy
needs: []
when: manual
# Meson cross file for creating a WebAssembly version of the preprocessor.
#
# Requires emscripten to be installed.
# Was successfully tested with emscripten 3.1.69 installed through emsdk
# tool, as described on: https://emscripten.org/docs/getting_started/downloads.html
# Don’t forget to source script snippet in current shell before running meson.
#
# Compilation creates a .wasm and .js wrapper under <builddir>/src/
#
# Can be run locally with node.js using:
# node dynare-preprocessor.js file.mod
# NB: a version of node.js is shipped with emscripten (under the node/
# subdirectory), but another version should also work.
[binaries]
cpp = 'em++'
[host_machine]
system = 'emscripten'
# Could be changed to wasm64 if 4GB memory constraint is hit
# Some background: https://v8.dev/blog/4gb-wasm-memory
cpu_family = 'wasm32'
cpu = 'wasm32'
endian = 'little'
[built-in options]
# Never do a debug build, because otherwise the lack of optimisations can
# overflow the memory capacities.
buildtype = 'release'
# The -fexceptions flag (for both compilation and linking) is needed for an
# unknown reason (C++ compilers are supposed to always add exception support).
# The -Wno-unqualified-std-cast-call flag removes many warnings about “move”
# not being qualified with “std::” namespace.
# The -fexperimental-library flag is needed to get std::jthread support (it was
# supposed to no longer be necessary for LLVM 20, but for some reason we still
# need it).
cpp_args = [ '-fexceptions', '-Wno-unqualified-std-cast-call', '-fexperimental-library' ]
# NODERAWFS=1 is needed for accessing the local filesystem
cpp_link_args = [ '-s', 'NODERAWFS=1', '-fexceptions' ]
[properties]
# It’s necessary to use a different copy of Boost than the one under
# /usr/include, because otherwise GCC headers confuse Clang
boost_root = '/tmp/boost_1_86_0'
/*
* Copyright © 2007-2023 Dynare Team
* Copyright © 2007-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -25,14 +25,17 @@
* command */
enum class SymbolType
{
endogenous = 0, //!< Endogenous
exogenous = 1, //!< Exogenous
exogenousDet = 2, //!< Exogenous deterministic
parameter = 4, //!< Parameter
modelLocalVariable = 10, //!< Local variable whose scope is model (pound expression)
modFileLocalVariable = 11, //!< Local variable whose scope is mod file (model excluded)
externalFunction = 12, //!< External (user-defined) function
trend = 13, //!< Trend variable
endogenous = 0, // Endogenous (non-heterogeneous)
exogenous = 1, // Exogenous (non-heterogeneous)
exogenousDet = 2, // Exogenous deterministic (non-heterogeneous)
parameter = 4, // Parameter (non-heterogeneous)
heterogeneousEndogenous = 5, // Endogenous that is heterogeneous across some dimension
heterogeneousExogenous = 6, // Exogenous that is heterogeneous across some dimension
heterogeneousParameter = 7, // Parameter that is heterogeneous across some dimension
modelLocalVariable = 10, // Local variable whose scope is model (pound expression)
modFileLocalVariable = 11, // Local variable whose scope is mod file (model excluded)
externalFunction = 12, // External (user-defined) function
trend = 13, // Trend variable
statementDeclaredVariable
= 14, //!< Local variable assigned within a Statement (see subsample statement for example)
logTrend = 15, //!< Log-trend variable
......@@ -45,6 +48,13 @@ enum class SymbolType
excludedVariable = 19 //!< Variable excluded via model_remove/var_remove/include_eqs/exclude_eqs
};
constexpr bool
isHeterogeneous(SymbolType type)
{
return type == SymbolType::heterogeneousEndogenous || type == SymbolType::heterogeneousExogenous
|| type == SymbolType::heterogeneousParameter;
}
enum class UnaryOpcode
{
uminus,
......@@ -75,7 +85,8 @@ enum class UnaryOpcode
erf,
erfc,
diff,
adl
adl,
sum
};
enum class BinaryOpcode
......
......@@ -283,7 +283,9 @@ PerfectForesightWithExpectationErrorsSolverStatement::writeOutput(
[[maybe_unused]] bool minimal_workspace) const
{
options_list.writeOutput(output);
output << "oo_ = perfect_foresight_with_expectation_errors_solver(M_, options_, oo_);" << endl;
output << "[oo_, Simulated_time_series] = perfect_foresight_with_expectation_errors_solver(M_, "
"options_, oo_);"
<< endl;
}
void
......@@ -3713,8 +3715,7 @@ SvarGlobalIdentificationCheckStatement::writeJsonOutput(ostream& output) const
output << R"({"statementName": "svar_global_identification"})";
}
SetTimeStatement::SetTimeStatement(OptionsList options_list_arg) :
options_list {move(options_list_arg)}
SetTimeStatement::SetTimeStatement(string period_arg) : period {move(period_arg)}
{
}
......@@ -3722,19 +3723,13 @@ void
SetTimeStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
options_list.writeOutput(output);
output << "options_.initial_period = " << period << endl;
}
void
SetTimeStatement::writeJsonOutput(ostream& output) const
{
output << R"({"statementName": "set_time")";
if (!options_list.empty())
{
output << ", ";
options_list.writeJsonOutput(output);
}
output << "}";
output << R"({"statementName": "set_time", "period": ")" << period << R"("})";
}
EstimationDataStatement::EstimationDataStatement(OptionsList options_list_arg) :
......@@ -5347,8 +5342,8 @@ void
ResidStatement::writeOutput(ostream& output, [[maybe_unused]] const string& basename,
[[maybe_unused]] bool minimal_workspace) const
{
options_list.writeOutput(output, "options_resid_");
output << "display_static_residuals(M_, options_, oo_, options_resid_);" << endl;
options_list.writeOutput(output);
output << "display_static_residuals(M_, options_, oo_);" << endl;
}
void
......
......@@ -524,7 +524,7 @@ public:
blockName() const override
{
return "estimated_params";
};
}
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -542,7 +542,7 @@ public:
blockName() const override
{
return "estimated_params_init";
};
}
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -557,7 +557,7 @@ public:
blockName() const override
{
return "estimated_params_bounds";
};
}
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -1007,10 +1007,10 @@ public:
class SetTimeStatement : public Statement
{
private:
const OptionsList options_list;
const string period;
public:
explicit SetTimeStatement(OptionsList options_list_arg);
explicit SetTimeStatement(string period_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......
......@@ -47,7 +47,7 @@ private:
get_paths() const
{
return paths;
};
}
private:
map<string, vector<string>> paths;
......
......@@ -24,6 +24,7 @@
#include <fstream>
#include <iostream>
#include <iterator>
#include <ranges>
#include "DataTree.hh"
......@@ -47,10 +48,12 @@ DataTree::initConstants()
}
DataTree::DataTree(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg, bool is_dynamic_arg) :
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg, bool is_dynamic_arg) :
symbol_table {symbol_table_arg},
num_constants {num_constants_arg},
external_functions_table {external_functions_table_arg},
heterogeneity_table {heterogeneity_table_arg},
is_dynamic {is_dynamic_arg}
{
initConstants();
......@@ -60,19 +63,21 @@ DataTree::DataTree(const DataTree& d) :
symbol_table {d.symbol_table},
num_constants {d.num_constants},
external_functions_table {d.external_functions_table},
heterogeneity_table {d.heterogeneity_table},
is_dynamic {d.is_dynamic},
local_variables_vector {d.local_variables_vector}
{
// Constants must be initialized first because they are used in some Add* methods
initConstants();
// See commment in DataTree::operator=() for the rationale
for (int symb_id : d.local_variables_vector)
local_variables_table[symb_id] = d.local_variables_table.at(symb_id)->clone(*this);
for (const auto& it : d.node_list)
it->clone(*this);
assert(node_list.size() == d.node_list.size());
for (const auto& [symb_id, value] : d.local_variables_table)
local_variables_table[symb_id] = value->clone(*this);
}
DataTree&
......@@ -81,6 +86,7 @@ DataTree::operator=(const DataTree& d)
assert(&symbol_table == &d.symbol_table);
assert(&num_constants == &d.num_constants);
assert(&external_functions_table == &d.external_functions_table);
assert(&heterogeneity_table == &d.heterogeneity_table);
assert(is_dynamic == d.is_dynamic);
num_const_node_map.clear();
......@@ -791,12 +797,18 @@ DataTree::AddSecondDerivExternalFunction(int top_level_symb_id, const vector<exp
return p;
}
expr_t
DataTree::AddSum(expr_t arg)
{
return AddUnaryOp(UnaryOpcode::sum, arg);
}
bool
DataTree::isSymbolUsed(int symb_id) const
{
for (const auto& [symb_lag, expr] : variable_node_map)
if (symb_lag.first == symb_id)
return true;
if (ranges::any_of(views::keys(variable_node_map),
[=](const auto& symb_lag) { return symb_lag.first == symb_id; }))
return true;
if (local_variables_table.contains(symb_id))
return true;
......@@ -842,18 +854,18 @@ DataTree::addAllParamDerivId([[maybe_unused]] set<int>& deriv_id_set)
bool
DataTree::isUnaryOpUsed(UnaryOpcode opcode) const
{
return ranges::any_of(unary_op_node_map,
[=](const auto& it) { return get<1>(it.first) == opcode; });
return ranges::any_of(views::keys(unary_op_node_map),
[=](const auto& key) { return get<1>(key) == opcode; });
}
bool
DataTree::isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const
{
set<int> var;
for (const auto& it : unary_op_node_map)
if (get<1>(it.first) == opcode)
for (const auto& [key, value] : unary_op_node_map)
if (get<1>(key) == opcode)
{
it.second->collectVariables(type, var);
value->collectVariables(type, var);
if (!var.empty())
return true;
}
......@@ -863,18 +875,18 @@ DataTree::isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const
bool
DataTree::isBinaryOpUsed(BinaryOpcode opcode) const
{
return ranges::any_of(binary_op_node_map,
[=](const auto& it) { return get<2>(it.first) == opcode; });
return ranges::any_of(views::keys(binary_op_node_map),
[=](const auto& key) { return get<2>(key) == opcode; });
}
bool
DataTree::isBinaryOpUsedOnType(SymbolType type, BinaryOpcode opcode) const
{
set<int> var;
for (const auto& it : binary_op_node_map)
if (get<2>(it.first) == opcode)
for (const auto& [key, value] : binary_op_node_map)
if (get<2>(key) == opcode)
{
it.second->collectVariables(type, var);
value->collectVariables(type, var);
if (!var.empty())
return true;
}
......
......@@ -33,6 +33,7 @@
#include "ExprNode.hh"
#include "ExternalFunctionsTable.hh"
#include "HeterogeneityTable.hh"
#include "NumericalConstants.hh"
#include "SubModel.hh"
#include "SymbolTable.hh"
......@@ -48,6 +49,8 @@ public:
NumericalConstants& num_constants;
//! A reference to the external functions table
ExternalFunctionsTable& external_functions_table;
// A reference to the heterogeneity table
HeterogeneityTable& heterogeneity_table;
//! Is it possible to use leads/lags on variable nodes?
/* NB: This data member cannot be replaced by a virtual method, because this information is needed
in AddVariable(), which itself can be called from the copy constructor. */
......@@ -139,7 +142,8 @@ private:
public:
DataTree(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg, bool is_dynamic_arg = false);
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg, bool is_dynamic_arg = false);
virtual ~DataTree() = default;
......@@ -275,6 +279,9 @@ public:
//! Adds an external function node for the second derivative of an external function
expr_t AddSecondDerivExternalFunction(int top_level_symb_id, const vector<expr_t>& arguments,
int input_index1, int input_index2);
// Adds "SUM(arg)" to model tree
expr_t AddSum(expr_t arg);
//! Checks if a given symbol is used somewhere in the data tree
[[nodiscard]] bool isSymbolUsed(int symb_id) const;
//! Checks if a given unary op is used somewhere in the data tree
......@@ -360,7 +367,13 @@ public:
if (it == local_variables_table.end())
throw UnknownLocalVariableException {symb_id};
return it->second->decreaseLeadsLags(-lead_lag);
/* In the following, the case without lead/lag is optimized. It makes a difference on models
with many nested model-local variables, see e.g.
https://forum.dynare.org/t/pre-processing-takes-very-long/26865 */
if (lead_lag == 0)
return it->second;
else
return it->second->decreaseLeadsLags(-lead_lag);
}
static void
......@@ -389,7 +402,7 @@ DataTree::AddPossiblyNegativeConstant(double v)
if (isnan(v))
return NaN;
if (isinf(v))
return (v < 0 ? MinusInfinity : Infinity);
return v < 0 ? MinusInfinity : Infinity;
bool neg = false;
if (v < 0)
......
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -50,9 +50,11 @@ DynamicModel::copyHelper(const DynamicModel& m)
DynamicModel::DynamicModel(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg,
TrendComponentModelTable& trend_component_model_table_arg,
VarModelTable& var_model_table_arg) :
ModelTree {symbol_table_arg, num_constants_arg, external_functions_table_arg, true},
ModelTree {symbol_table_arg, num_constants_arg, external_functions_table_arg,
heterogeneity_table_arg, true},
trend_component_model_table {trend_component_model_table_arg},
var_model_table {var_model_table_arg}
{
......@@ -729,9 +731,9 @@ DynamicModel::removeEquationsHelper(
}
int n_excl = all_equations.size() - new_equations.size();
all_equations = new_equations;
all_equations_lineno = new_equations_lineno;
all_complementarity_conditions = new_complementarity_conditions;
all_equations = move(new_equations);
all_equations_lineno = move(new_equations_lineno);
all_complementarity_conditions = move(new_complementarity_conditions);
all_equation_tags.erase(eqs_to_delete_by_number, old_eqn_num_2_new);
......@@ -1041,14 +1043,8 @@ DynamicModel::writeDriverOutput(ostream& output, bool compute_xrefs) const
<< (static_only_equations.size() > 0) << ";" << endl;
// Say if model contains an external function call
bool has_external_function = false;
for (auto equation : equations)
if (equation->containsExternalFunction())
{
has_external_function = true;
break;
}
output << "M_.has_external_function = " << boolalpha << has_external_function << ';' << endl;
output << "M_.has_external_function = " << boolalpha
<< ranges::any_of(equations, &ExprNode::containsExternalFunction) << ';' << endl;
// Compute list of state variables, ordered in block-order
vector<int> state_var;
......@@ -1133,7 +1129,7 @@ DynamicModel::writeDriverOutput(ostream& output, bool compute_xrefs) const
output << (i > computed_derivs_order ? -1 : NNZDerivatives[i]) << "; ";
output << "];" << endl;
writeDriverSparseIndicesHelper<true, false>(output);
writeDriverSparseIndicesHelper("dynamic", output);
// Write LHS of each equation in text form
output << "M_.lhs = {" << endl;
......@@ -1357,8 +1353,7 @@ DynamicModel::fillVarModelTableFromOrigModel() const
// save lhs variables
equations[eqn]->arg1->collectVARLHSVariable(lhs);
equations[eqn]->arg1->countDiffs() > 0 ? diff_vec.push_back(true)
: diff_vec.push_back(false);
diff_vec.push_back(equations[eqn]->arg1->countDiffs() > 0);
if (diff_vec.back())
{
set<pair<int, int>> diff_set;
......@@ -1702,10 +1697,7 @@ DynamicModel::fillTrendComponentModelTableFromOrigModel() const
// save lhs variables
equations[eqn]->arg1->collectVARLHSVariable(lhs);
if (equations[eqn]->arg1->countDiffs() > 0)
diff_vec.push_back(true);
else
diff_vec.push_back(false);
diff_vec.push_back(equations[eqn]->arg1->countDiffs() > 0);
if (diff_vec.back())
{
set<pair<int, int>> diff_set;
......@@ -1778,7 +1770,7 @@ DynamicModel::getUndiffLHSForPac(const string& aux_model_name,
exit(EXIT_FAILURE);
}
if (diff.at(i) != true)
if (!diff.at(i))
{
cerr << "ERROR: the variable on the LHS of equation #" << eqn
<< " does not have the diff operator applied to it yet you are trying to undiff it."
......@@ -1786,7 +1778,6 @@ DynamicModel::getUndiffLHSForPac(const string& aux_model_name,
exit(EXIT_FAILURE);
}
bool printerr = false;
expr_t node = nullptr;
expr_t aux_var = lhs_expr_t.at(i);
for (const auto& it : diff_subst_table)
......@@ -1803,11 +1794,8 @@ DynamicModel::getUndiffLHSForPac(const string& aux_model_name,
}
node = node->undiff();
auto it1 = diff_subst_table.find(node);
if (it1 == diff_subst_table.end())
printerr = true;
if (printerr)
if (auto it1 = diff_subst_table.find(node); it1 == diff_subst_table.end())
{ // we have undiffed something like diff(x), hence x is not in diff_subst_table
lhs_expr_t.at(i) = node;
lhs.at(i) = dynamic_cast<VariableNode*>(node)->symb_id;
......@@ -1828,7 +1816,7 @@ DynamicModel::analyzePacEquationStructure(const string& name, map<string, string
for (auto& equation : equations)
if (equation->containsPacExpectation(name))
{
if (!pac_eq_name[name].empty())
if (pac_eq_name.contains(name))
{
cerr << "It is not possible to use 'pac_expectation(" << name
<< ")' in several equations." << endl;
......@@ -1927,6 +1915,13 @@ DynamicModel::analyzePacEquationStructure(const string& name, map<string, string
move(additive_vars_params_and_constants),
move(optim_additive_vars_params_and_constants)};
}
if (!pac_eq_name.contains(name))
{
cerr << "ERROR: the model does not contain the 'pac_expectation(" << name << ")' operator."
<< endl;
exit(EXIT_FAILURE);
}
}
int
......@@ -3697,6 +3692,36 @@ DynamicModel::substituteLogTransform()
}
}
void
DynamicModel::substituteAggregationOperators()
{
ExprNode::subst_table_t subst_table;
vector<BinaryOpNode*> neweqs;
for (auto& [symb_id, expr] : local_variables_table)
expr = expr->substituteAggregationOperators(subst_table, neweqs);
for (auto& equation : equations)
{
equation = dynamic_cast<BinaryOpNode*>(
equation->substituteAggregationOperators(subst_table, neweqs));
assert(equation);
}
for (auto& equation : static_only_equations)
{
equation = dynamic_cast<BinaryOpNode*>(
equation->substituteAggregationOperators(subst_table, neweqs));
assert(equation);
}
for (auto neweq : neweqs)
{
addEquation(neweq, nullopt);
addAuxEquation(neweq);
}
}
void
DynamicModel::checkNoWithLogTransform(const set<int>& eqnumbers)
{
......@@ -3723,18 +3748,18 @@ void
DynamicModel::detrendEquations()
{
// We go backwards in the list of trend_vars, to deal correctly with I(2) processes
for (const auto& it : std::ranges::reverse_view(nonstationary_symbols_map))
for (const auto& [symb_id, deflator] : std::ranges::reverse_view(nonstationary_symbols_map))
{
for (auto& equation : equations)
{
equation = dynamic_cast<BinaryOpNode*>(
equation->detrend(it.first, it.second.first, it.second.second));
equation->detrend(symb_id, deflator.first, deflator.second));
assert(equation);
}
for (auto& equation : static_only_equations)
{
equation = dynamic_cast<BinaryOpNode*>(
equation->detrend(it.first, it.second.first, it.second.second));
equation->detrend(symb_id, deflator.first, deflator.second));
assert(equation);
}
}
......
......@@ -73,7 +73,8 @@ public:
void checkAllRegimesPresent() const noexcept(false);
private:
pair<vector<string>, vector<string>> convertBitVectorToRegimes(const vector<bool>& r) const;
[[nodiscard]] pair<vector<string>, vector<string>>
convertBitVectorToRegimes(const vector<bool>& r) const;
};
private:
......@@ -325,6 +326,7 @@ protected:
public:
DynamicModel(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg,
TrendComponentModelTable& trend_component_model_table_arg,
VarModelTable& var_model_table_arg);
......@@ -566,6 +568,10 @@ public:
// Performs the transformations associated to variables declared with “var(log)”
void substituteLogTransform();
/* Performs the transformations associated to aggregation operators in heterogeneous models, such
as SUM(…) */
void substituteAggregationOperators();
// Check that no variable was declared with “var(log)” in the given equations
void checkNoWithLogTransform(const set<int>& eqnumbers);
......@@ -708,7 +714,7 @@ public:
{
return tuple {static_only_equations, static_only_equations_lineno,
static_only_complementarity_conditions, static_only_equations_equation_tags};
};
}
//! Returns true if a parameter was used in the model block with a lead or lag
bool ParamUsedWithLeadLag() const;
......
// -*- C++ -*-
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -28,20 +28,20 @@
%define parse.error verbose
%define parse.trace
%code top {
class ParsingDriver;
}
%code requires {
// Only headers needed for the value and location types go here
// Headers needed by the Bison file itself go in the unqualified %code section
#include <string>
#include <vector>
#include <map>
#include <utility>
#include <tuple>
#include <variant>
#include "CommonEnums.hh"
#include "ExprNode.hh"
#include "Shocks.hh"
class ParsingDriver;
}
%param { ParsingDriver &driver }
......@@ -54,6 +54,9 @@ class ParsingDriver;
}
%code {
#include <ranges>
#include <utility>
/* Little hack: we redefine the macro which computes the locations, because
we need to access the location from within the parsing driver for error
and warning messages. */
......@@ -104,11 +107,11 @@ str_tolower(string s)
%token END ENDVAL EQUAL ESTIMATION ESTIMATED_PARAMS ESTIMATED_PARAMS_BOUNDS ESTIMATED_PARAMS_INIT EXTENDED_PATH ENDOGENOUS_PRIOR EXPRESSION
%token FILENAME DIRNAME FILTER_STEP_AHEAD FILTERED_VARS FIRST_OBS FIRST_SIMULATION_PERIOD LAST_SIMULATION_PERIOD LAST_OBS
%token SET_TIME OSR_PARAMS_BOUNDS KEEP_KALMAN_ALGO_IF_SINGULARITY_IS_DETECTED
%token <string> FALSE FLOAT_NUMBER DATES
%token <string> FALSE FLOAT_NUMBER DATE
%token DEFAULT FIXED_POINT FLIP OPT_ALGO COMPILATION_SETUP COMPILER ADD_FLAGS SUBSTITUTE_FLAGS ADD_LIBS SUBSTITUTE_LIBS
%token FORECAST K_ORDER_SOLVER INSTRUMENTS SHIFT MEAN STDEV VARIANCE MODE INTERVAL SHAPE DOMAINN
%token GAMMA_PDF GRAPH GRAPH_FORMAT CONDITIONAL_VARIANCE_DECOMPOSITION NOCHECK STD
%token HISTVAL HISTVAL_FILE HOMOTOPY_SETUP HOMOTOPY_MODE HOMOTOPY_STEPS HOMOTOPY_FORCE_CONTINUE HP_FILTER HP_NGRID FILTERED_THEORETICAL_MOMENTS_GRID HYBRID ONE_SIDED_HP_FILTER
%token HISTVAL HISTVAL_FILE HOMOTOPY_SETUP HOMOTOPY_MODE HOMOTOPY_STEPS HOMOTOPY_FORCE_CONTINUE HP_FILTER HP_NGRID FILTERED_THEORETICAL_MOMENTS_GRID HYBRID USE_FIRST_ORDER_SOLUTION ONE_SIDED_HP_FILTER
%token IDENTIFICATION INF_CONSTANT INITVAL INITVAL_FILE BOUNDS JSCALE INIT INFILE INVARS
%token <string> INT_NUMBER
%token CONDITIONAL_LIKELIHOOD
......@@ -170,7 +173,8 @@ str_tolower(string s)
%token VLISTLOG VLISTPER SPECTRAL_DENSITY INIT2SHOCKS
%token RESTRICTION RESTRICTION_FNAME CROSS_RESTRICTIONS NLAGS CONTEMP_REDUCED_FORM REAL_PSEUDO_FORECAST
%token DUMMY_OBS NSTATES INDXSCALESSTATES NO_BAYESIAN_PRIOR SPECIFICATION SIMS_ZHA
%token <string> ALPHA BETA ABAND NINV CMS NCMS CNUM GAMMA INV_GAMMA INV_GAMMA1 INV_GAMMA2 NORMAL UNIFORM EPS PDF FIG DR NONE PRIOR PRIOR_VARIANCE HESSIAN IDENTITY_MATRIX DIRICHLET DIAGONAL OPTIMAL MFS
%token <string> ALPHA BETA ABAND NINV CMS NCMS CNUM GAMMA INV_GAMMA INV_GAMMA1 INV_GAMMA2 NORMAL UNIFORM EPS PDF FIG DR NONE PRIOR DIRICHLET MFS RESIDUAL
%token PRIOR_VARIANCE HESSIAN IDENTITY_MATRIX
%token GSIG2_LMDM Q_DIAG FLAT_PRIOR NCSK NSTD WEIBULL WEIBULL_PDF
%token INDXPARR INDXOVR INDXAP APBAND INDXIMF INDXFORE FOREBAND INDXGFOREHAT INDXGIMFHAT
%token INDXESTIMA INDXGDLS EQ_MS FILTER_COVARIANCE UPDATED_COVARIANCE FILTER_DECOMPOSITION SMOOTHED_STATE_UNCERTAINTY SMOOTHER_REDUX
......@@ -216,12 +220,13 @@ str_tolower(string s)
%token HOMOTOPY_MAX_COMPLETION_SHARE HOMOTOPY_MIN_STEP_SIZE HOMOTOPY_INITIAL_STEP_SIZE HOMOTOPY_STEP_SIZE_INCREASE_SUCCESS_COUNT
%token HOMOTOPY_LINEARIZATION_FALLBACK HOMOTOPY_MARGINAL_LINEARIZATION_FALLBACK HOMOTOPY_EXCLUDE_VAREXO FROM_INITVAL_TO_ENDVAL
%token STATIC_MFS RELATIVE_TO_INITVAL MATCHED_IRFS MATCHED_IRFS_WEIGHTS WEIGHTS PERPENDICULAR
%token HETEROGENEITY HETEROGENEITY_DIMENSION SUM PERFECT_FORESIGHT_CONTROLLED_PATHS EXOGENIZE ENDOGENIZE
%token <vector<string>> SYMBOL_VEC
%type <expr_t> expression expression_or_empty
%type <expr_t> equation hand_side
%type <string> non_negative_number signed_number signed_integer date_str
%type <string> non_negative_number signed_number signed_integer
%type <string> filename symbol namespace_qualified_filename namespace_qualified_symbol
%type <string> date_expr signed_inf signed_number_w_inf range
%type <string> integer_range signed_integer_range boolean
......@@ -241,22 +246,26 @@ str_tolower(string s)
%type <vector<map<string, string>>> tag_pair_list_for_selection
%type <map<string, string>> tag_pair_list
%type <tuple<string,string,string,string>> prior_eq_opt options_eq_opt
%type <vector<pair<int, int>>> period_list
%type <AbstractShocksStatement::period_range_t> period_range
%type <vector<AbstractShocksStatement::period_range_t>> period_list
%type <vector<expr_t>> matched_moments_list value_list ramsey_constraints_list
%type <tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>> occbin_constraints_regime
%type <vector<tuple<string, BinaryOpNode *, BinaryOpNode *, expr_t, expr_t>>> occbin_constraints_regimes_list
%type <tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>> occbin_constraints_regime
%type <vector<tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>>> occbin_constraints_regimes_list
%type <map<string, expr_t>> occbin_constraints_regime_options_list
%type <pair<string, expr_t>> occbin_constraints_regime_option
%type <PacTargetKind> pac_target_kind
%type <vector<tuple<string, string, vector<pair<string, string>>>>> symbol_list_with_tex_and_partition
%type <map<string, variant<bool, string>>> mshocks_options_list
%type <pair<string, variant<bool, string>>> mshocks_option
%type <variant<int, string>> integer_or_date
%type <map<string, variant<bool, variant<int, string>>>> mshocks_options_list
%type <pair<string, variant<bool, variant<int, string>>>> mshocks_option
%type <pair<vector<expr_t>, vector<expr_t>>> matched_irfs_elem_values_weights
%type <pair<pair<string, string>, vector<tuple<int, int, expr_t, expr_t>>>> matched_irfs_elem
%type <map<pair<string, string>, vector<tuple<int, int, expr_t, expr_t>>>> matched_irfs_list
%type <tuple<string, string, string>> matched_irfs_weights_elem_var_varexo
%type <pair<tuple<string, string, string, string, string, string>, expr_t>> matched_irfs_weights_elem
%type <map<tuple<string, string, string, string, string, string>, expr_t>> matched_irfs_weights_list
%type <tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>, string>> perfect_foresight_controlled_paths_elem
%type <vector<tuple<string, vector<AbstractShocksStatement::period_range_t>, vector<expr_t>, string>>> perfect_foresight_controlled_paths_list
%%
%start statement_list;
......@@ -272,6 +281,7 @@ statement : parameters
| predetermined_variables
| model_local_variable
| change_type
| heterogeneity_dimension
| model
| initval
| initval_file
......@@ -377,6 +387,7 @@ statement : parameters
| perfect_foresight_solver
| perfect_foresight_with_expectation_errors_setup
| perfect_foresight_with_expectation_errors_solver
| perfect_foresight_controlled_paths
| prior_function
| posterior_function
| method_of_moments
......@@ -531,9 +542,9 @@ log_trend_var : LOG_TREND_VAR '(' LOG_GROWTH_FACTOR EQUAL { driver.begin_model()
;
var : VAR symbol_list_with_tex_and_partition ';'
{ driver.var($2, false); }
{ driver.var($2, {}, false); }
| VAR '(' LOG ')' symbol_list_with_tex_and_partition ';'
{ driver.var($5, true); }
{ driver.var($5, {}, true); }
| VAR '(' DEFLATOR EQUAL { driver.begin_model(); } hand_side ')' symbol_list_with_tex_and_partition ';'
{ driver.end_nonstationary_var(false, $6, $8, false); }
| VAR '(' LOG COMMA DEFLATOR EQUAL { driver.begin_model(); } hand_side ')' symbol_list_with_tex_and_partition ';'
......@@ -542,6 +553,8 @@ var : VAR symbol_list_with_tex_and_partition ';'
{ driver.end_nonstationary_var(true, $6, $8, false); }
/* The case LOG + LOG_DEFLATOR is omitted, because it does not make much sense
from an economic point of view (amounts to taking the log two times) */
| VAR '(' HETEROGENEITY EQUAL symbol ')' symbol_list_with_tex_and_partition ';'
{ driver.var($7, $5, false); }
;
var_remove : VAR_REMOVE symbol_list ';' { driver.var_remove($2); };
......@@ -615,7 +628,9 @@ var_expectation_model_option : VARIABLE EQUAL symbol
;
varexo : VAREXO symbol_list_with_tex_and_partition ';'
{ driver.varexo($2); }
{ driver.varexo($2, {}); }
| VAREXO '(' HETEROGENEITY EQUAL symbol ')' symbol_list_with_tex_and_partition ';'
{ driver.varexo($7, $5); }
;
varexo_det : VAREXO_DET symbol_list_with_tex_and_partition ';'
......@@ -627,7 +642,9 @@ predetermined_variables : PREDETERMINED_VARIABLES symbol_list ';'
;
parameters : PARAMETERS symbol_list_with_tex_and_partition ';'
{ driver.parameters($2); }
{ driver.parameters($2, {}); }
| PARAMETERS '(' HETEROGENEITY EQUAL symbol ')' symbol_list_with_tex_and_partition ';'
{ driver.parameters($7, $5); }
;
model_local_variable : MODEL_LOCAL_VARIABLE symbol_list_with_tex ';'
......@@ -648,6 +665,10 @@ change_type_arg : PARAMETERS
{ $$ = SymbolType::exogenousDet; }
;
heterogeneity_dimension : HETEROGENEITY_DIMENSION symbol_list ';'
{ driver.heterogeneity_dimension($2); }
;
init_param : symbol EQUAL expression ';' { driver.init_param($1, $3); };
expression : '(' expression ')'
......@@ -784,20 +805,24 @@ h_options: o_filename
| o_first_obs
| o_data_first_obs
| o_first_simulation_period
| o_date_first_simulation_period
| o_last_simulation_period
| o_date_last_simulation_period
| o_last_obs
| o_data_last_obs
| o_nobs
| o_series
;
integer_or_date : INT_NUMBER
{ $$.emplace<int>(stoi($1)); }
| date_expr
{ $$.emplace<string>($1); }
;
endval : ENDVAL ';' endval_list END ';'
{ driver.end_endval(false); }
| ENDVAL '(' ALL_VALUES_REQUIRED ')' ';' endval_list END ';'
{ driver.end_endval(true); }
| ENDVAL '(' LEARNT_IN EQUAL INT_NUMBER ')' ';' endval_list END ';'
| ENDVAL '(' LEARNT_IN EQUAL integer_or_date ')' ';' endval_list END ';'
{ driver.end_endval_learnt_in($5); }
;
......@@ -995,6 +1020,8 @@ model : MODEL ';' { driver.begin_model(); }
equation_list END ';' { driver.end_model(); }
| MODEL '(' model_options_list ')' ';' { driver.begin_model(); }
equation_list END ';' { driver.end_model(); }
| MODEL '(' HETEROGENEITY EQUAL symbol ')' { driver.begin_heterogeneous_model($5); }';'
equation_list END ';' { driver.end_model(); }
;
equation_list : equation_list equation
......@@ -1152,6 +1179,8 @@ hand_side : '(' hand_side ')'
{ $$ = driver.add_erfc($3); }
| STEADY_STATE '(' hand_side ')'
{ $$ = driver.add_steady_state($3); }
| SUM '(' hand_side ')'
{ $$ = driver.add_sum($3); }
;
comma_hand_side : hand_side
......@@ -1202,9 +1231,15 @@ shocks : SHOCKS ';' shock_list END ';' { driver.end_shocks(false); }
| SHOCKS '(' SURPRISE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(false); }
| SHOCKS '(' SURPRISE COMMA OVERWRITE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(true); }
| SHOCKS '(' OVERWRITE COMMA SURPRISE ')' ';' det_shock_list END ';' { driver.end_shocks_surprise(true); }
| SHOCKS '(' LEARNT_IN EQUAL INT_NUMBER ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, false); }
| SHOCKS '(' LEARNT_IN EQUAL INT_NUMBER COMMA OVERWRITE ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, true); }
| SHOCKS '(' OVERWRITE COMMA LEARNT_IN EQUAL INT_NUMBER ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($7, true); }
| SHOCKS '(' LEARNT_IN EQUAL integer_or_date ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, false); }
| SHOCKS '(' LEARNT_IN EQUAL integer_or_date COMMA OVERWRITE ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($5, true); }
| SHOCKS '(' OVERWRITE COMMA LEARNT_IN EQUAL integer_or_date ')' ';' det_shock_list END ';' { driver.end_shocks_learnt_in($7, true); }
| SHOCKS '(' HETEROGENEITY EQUAL symbol ')' ';' stoch_shock_list END ';'
{ driver.end_heterogeneous_shocks($5, false); }
| SHOCKS '(' HETEROGENEITY EQUAL symbol COMMA OVERWRITE ')' ';' stoch_shock_list END ';'
{ driver.end_heterogeneous_shocks($5, true); }
| SHOCKS '(' OVERWRITE COMMA HETEROGENEITY EQUAL symbol ')' ';' stoch_shock_list END ';'
{ driver.end_heterogeneous_shocks($7, true); }
;
shock_list : shock_list shock_elem
......@@ -1212,16 +1247,23 @@ shock_list : shock_list shock_elem
;
shock_elem : det_shock_elem
| VAR symbol ';' STDERR expression ';'
{ driver.add_stderr_shock($2, $5); }
| VAR symbol EQUAL expression ';'
{ driver.add_var_shock($2, $4); }
| VAR symbol COMMA symbol EQUAL expression ';'
{ driver.add_covar_shock($2, $4, $6); }
| CORR symbol COMMA symbol EQUAL expression ';'
{ driver.add_correl_shock($2, $4, $6); }
| stoch_shock_elem
;
stoch_shock_elem : VAR symbol ';' STDERR expression ';'
{ driver.add_stderr_shock($2, $5); }
| VAR symbol EQUAL expression ';'
{ driver.add_var_shock($2, $4); }
| VAR symbol COMMA symbol EQUAL expression ';'
{ driver.add_covar_shock($2, $4, $6); }
| CORR symbol COMMA symbol EQUAL expression ';'
{ driver.add_correl_shock($2, $4, $6); }
;
stoch_shock_list : stoch_shock_list stoch_shock_elem
| stoch_shock_elem
;
det_shock_elem : VAR symbol ';' PERIODS period_list ';' VALUES value_list ';'
{ driver.add_det_shock($2, $5, $8, ParsingDriver::DetShockType::standard); }
| VAR symbol ';' PERIODS period_list ';' ADD value_list ';'
......@@ -1337,11 +1379,11 @@ mshocks : MSHOCKS ';' mshock_list END ';'
{ driver.end_mshocks(false, false); }
| MSHOCKS '(' mshocks_options_list ')' ';' mshock_list END ';'
{
/* NB: the following relies of the fact that bool is the first
/* NB: the following relies on the fact that bool is the first
alternative in the variant, so that default initialization of the
variant by the [] operator will give false */
if ($3.contains("learnt_in"))
driver.end_mshocks_learnt_in(get<string>($3.at("learnt_in")),
driver.end_mshocks_learnt_in(get<variant<int, string>>($3.at("learnt_in")),
get<bool>($3["overwrite"]),
get<bool>($3["relative_to_initval"]));
else
......@@ -1362,7 +1404,7 @@ mshocks_options_list : mshocks_option
mshocks_option : OVERWRITE
{ $$ = {"overwrite", true}; }
| LEARNT_IN EQUAL INT_NUMBER
| LEARNT_IN EQUAL integer_or_date
{ $$ = {"learnt_in", $3}; }
| RELATIVE_TO_INITVAL
{ $$ = {"relative_to_initval", true}; }
......@@ -1372,48 +1414,38 @@ mshock_list : mshock_list det_shock_elem
| det_shock_elem
;
period_list : period_list COMMA INT_NUMBER
{
$$ = $1;
int p = stoi($3);
$$.emplace_back(p, p);
}
| period_list INT_NUMBER
{
$$ = $1;
int p = stoi($2);
$$.emplace_back(p, p);
}
| period_list COMMA INT_NUMBER ':' INT_NUMBER
period_list : period_range
{ $$ = { $1 }; }
| period_list period_range
{
$$ = $1;
int p1 = stoi($3), p2 = stoi($5);
if (p1 > p2)
driver.error("Can't have first period index greater than second index in range specification");
$$.emplace_back(p1, p2);
$$.emplace_back($2);
}
| period_list INT_NUMBER ':' INT_NUMBER
| period_list COMMA period_range
{
$$ = $1;
int p1 = stoi($2), p2 = stoi($4);
if (p1 > p2)
driver.error("Can't have first period index greater than second index in range specification");
$$.emplace_back(p1, p2);
}
| INT_NUMBER ':' INT_NUMBER
{
int p1 = stoi($1), p2 = stoi($3);
if (p1 > p2)
driver.error("Can't have first period index greater than second index in range specification");
$$ = {{p1, p2}};
}
| INT_NUMBER
{
int p = stoi($1);
$$ = {{p, p}};
$$.emplace_back($3);
}
;
period_range : INT_NUMBER
{
int p = stoi($1);
$$.emplace<pair<int, int>>(p, p);
}
| INT_NUMBER ':' INT_NUMBER
{
int p1 = stoi($1), p2 = stoi($3);
if (p1 > p2)
driver.error("Can't have first period index greater than second index in range specification");
$$.emplace<pair<int, int>>(p1, p2);
}
| date_expr
{ $$.emplace<pair<string, string>>($1, $1); }
| date_expr ':' date_expr
{ $$.emplace<pair<string, string>>($1, $3); }
;
value_list : value_list COMMA '(' expression ')'
{
$$ = $1;
......@@ -1465,9 +1497,11 @@ steady_options : o_solve_algo
| o_markowitz
| o_steady_maxit
| o_nocheck
| o_noprint
| o_steady_tolf
| o_steady_tolx
| o_fsolve_options
| o_non_zero
;
check : CHECK ';'
......@@ -1512,6 +1546,8 @@ perfect_foresight_setup_options_list : perfect_foresight_setup_options_list COMM
perfect_foresight_setup_options : o_periods
| o_datafile
| o_endval_steady
| o_pf_first_simulation_period
| o_pf_last_simulation_period
;
perfect_foresight_solver : PERFECT_FORESIGHT_SOLVER ';'
......@@ -1564,6 +1600,8 @@ perfect_foresight_with_expectation_errors_setup_options_list : perfect_foresight
perfect_foresight_with_expectation_errors_setup_options : o_periods
| o_datafile
| o_pf_first_simulation_period
| o_pf_last_simulation_period
;
perfect_foresight_with_expectation_errors_solver : PERFECT_FORESIGHT_WITH_EXPECTATION_ERRORS_SOLVER ';'
......@@ -1580,6 +1618,31 @@ perfect_foresight_with_expectation_errors_solver_options : o_pfwee_constant_simu
| perfect_foresight_solver_options
;
perfect_foresight_controlled_paths : PERFECT_FORESIGHT_CONTROLLED_PATHS ';' perfect_foresight_controlled_paths_list END ';'
{ driver.perfect_foresight_controlled_paths($3, 1); }
| PERFECT_FORESIGHT_CONTROLLED_PATHS '(' LEARNT_IN EQUAL integer_or_date ')' ';' perfect_foresight_controlled_paths_list END ';'
{ driver.perfect_foresight_controlled_paths($8, $5); }
;
perfect_foresight_controlled_paths_list : perfect_foresight_controlled_paths_list perfect_foresight_controlled_paths_elem
{
$$ = $1;
$$.push_back($2);
}
| perfect_foresight_controlled_paths_elem
{ $$ = { $1 }; }
;
perfect_foresight_controlled_paths_elem : EXOGENIZE symbol ';' PERIODS period_list ';' VALUES value_list ';' ENDOGENIZE symbol ';'
{
driver.check_symbol_is_endogenous($2);
driver.check_symbol_is_exogenous($11, false);
if ($5.size() != $8.size())
driver.error("The number of periods is different from the number of values");
$$ = { $2, $5, $8, $11};
}
;
method_of_moments : METHOD_OF_MOMENTS ';'
{ driver.method_of_moments(); }
| METHOD_OF_MOMENTS '(' method_of_moments_options_list ')' ';'
......@@ -2063,9 +2126,8 @@ prior_pdf : BETA_PDF
{ $$ = PriorDistributions::weibull; }
;
date_str : DATES
date_expr : date_str
date_expr : DATE
{ $$ = "dates('" + $1 + "')"; }
| date_expr PLUS INT_NUMBER
{ $$ = $1 + '+' + $3; }
;
......@@ -3465,7 +3527,8 @@ extended_path_option : o_periods
| o_solver_periods
| o_extended_path_order
| o_hybrid
| o_lmmcp
| o_use_first_order_solution
| o_lmmcp
;
model_diagnostics : MODEL_DIAGNOSTICS ';'
......@@ -3593,7 +3656,15 @@ matched_irfs_elem : matched_irfs_elem_var_varexo
vector<tuple<int, int, expr_t, expr_t>> v;
v.reserve($3.size());
for (size_t i {0}; i < $3.size(); i++)
v.emplace_back($3[i].first, $3[i].second, $5.first[i], $5.second[i]);
try
{
auto [p1, p2] = get<pair<int, int>>($3[i]);
v.emplace_back(p1, p2, $5.first[i], $5.second[i]);
}
catch (bad_variant_access&)
{
driver.error("matched_irfs: dates are not allowed in the 'periods' keyword");
}
$$ = {$1, v};
}
;
......@@ -3692,6 +3763,7 @@ o_periods : PERIODS EQUAL INT_NUMBER { driver.option_num("periods", $3); };
o_solver_periods : SOLVER_PERIODS EQUAL INT_NUMBER { driver.option_num("ep.periods", $3); };
o_extended_path_order : ORDER EQUAL INT_NUMBER { driver.option_num("ep.stochastic.order", $3); };
o_hybrid : HYBRID { driver.option_num("ep.stochastic.hybrid_order", "2"); };
o_use_first_order_solution : USE_FIRST_ORDER_SOLUTION { driver.option_num("ep.use_first_order_solution_as_initial_guess", "true"); };
o_steady_maxit : MAXIT EQUAL INT_NUMBER { driver.option_num("steady.maxit", $3); };
o_simul_maxit : MAXIT EQUAL INT_NUMBER { driver.option_num("simul.maxit", $3); };
o_bandpass_filter : BANDPASS_FILTER { driver.option_num("bandpass.indicator", "true"); }
......@@ -3760,13 +3832,17 @@ o_est_first_obs : FIRST_OBS EQUAL vec_int
o_posterior_sampling_method : POSTERIOR_SAMPLING_METHOD EQUAL QUOTED_STRING
{ driver.option_str("posterior_sampler_options.posterior_sampling_method", $3); } ;
o_first_obs : FIRST_OBS EQUAL INT_NUMBER { driver.option_num("first_obs", $3); };
o_data_first_obs : FIRST_OBS EQUAL date_expr { driver.option_date("firstobs", $3); } ;
o_first_simulation_period : FIRST_SIMULATION_PERIOD EQUAL INT_NUMBER { driver.option_num("first_simulation_period", $3); };
o_date_first_simulation_period : FIRST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("firstsimulationperiod", $3); } ;
o_last_simulation_period : LAST_SIMULATION_PERIOD EQUAL INT_NUMBER { driver.option_num("last_simulation_period", $3); };
o_date_last_simulation_period : LAST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("lastsimulationperiod", $3); } ;
o_data_first_obs : FIRST_OBS EQUAL date_expr { driver.option_date("first_obs", $3); } ;
o_first_simulation_period : FIRST_SIMULATION_PERIOD EQUAL INT_NUMBER { driver.option_num("first_simulation_period", $3); }
| FIRST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("first_simulation_period", $3); }
;
o_last_simulation_period : LAST_SIMULATION_PERIOD EQUAL INT_NUMBER { driver.option_num("last_simulation_period", $3); }
| LAST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("last_simulation_period", $3); }
;
o_pf_first_simulation_period : FIRST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("simul.first_simulation_period", $3); };
o_pf_last_simulation_period : LAST_SIMULATION_PERIOD EQUAL date_expr { driver.option_date("simul.last_simulation_period", $3); };
o_last_obs : LAST_OBS EQUAL INT_NUMBER { driver.option_num("last_obs", $3); };
o_data_last_obs : LAST_OBS EQUAL date_expr { driver.option_date("lastobs", $3); } ;
o_data_last_obs : LAST_OBS EQUAL date_expr { driver.option_date("last_obs", $3); } ;
o_keep_kalman_algo_if_singularity_is_detected : KEEP_KALMAN_ALGO_IF_SINGULARITY_IS_DETECTED { driver.option_num("kalman.keep_kalman_algo_if_singularity_is_detected", "true"); } ;
o_data_nobs : NOBS EQUAL INT_NUMBER { driver.option_num("nobs", $3); };
o_shift : SHIFT EQUAL signed_number { driver.option_num("shift", $3); };
......@@ -4005,11 +4081,12 @@ o_resampling : RESAMPLING EQUAL SYSTEMATIC
| RESAMPLING EQUAL NONE { driver.option_num("particle.resampling.status.systematic", "false"); driver.option_num("particle.resampling.status.none", "true"); }
| RESAMPLING EQUAL GENERIC { driver.option_num("particle.resampling.status.systematic", "false"); driver.option_num("particle.resampling.status.generic", "true"); };
o_resampling_threshold : RESAMPLING_THRESHOLD EQUAL non_negative_number { driver.option_num("particle.resampling.threshold", $3); };
o_resampling_method : RESAMPLING_METHOD EQUAL KITAGAWA { driver.option_num("particle.resampling.method.kitagawa", "true"); driver.option_num("particle.resampling.method.smooth", "false"); driver.option_num("particle.resampling.smethod.stratified", "false"); }
| RESAMPLING_METHOD EQUAL SMOOTH { driver.option_num("particle.resampling.method.kitagawa", "false"); driver.option_num("particle.resampling.method.smooth", "true"); driver.option_num("particle.resampling.smethod.stratified", "false"); }
| RESAMPLING_METHOD EQUAL STRATIFIED { driver.option_num("particle.resampling.method.kitagawa", "false"); driver.option_num("particle.resampling.method.smooth", "false"); driver.option_num("particle.resampling.method.stratified", "true"); };
o_resampling_method : RESAMPLING_METHOD EQUAL KITAGAWA { driver.option_num("particle.resampling.method.kitagawa", "true"); driver.option_num("particle.resampling.method.smooth", "false"); driver.option_num("particle.resampling.method.stratified", "false"); driver.option_num("particle.resampling.method.residual", "false");}
| RESAMPLING_METHOD EQUAL SMOOTH { driver.option_num("particle.resampling.method.kitagawa", "false"); driver.option_num("particle.resampling.method.smooth", "true"); driver.option_num("particle.resampling.method.stratified", "false"); driver.option_num("particle.resampling.method.residual", "false"); }
| RESAMPLING_METHOD EQUAL STRATIFIED { driver.option_num("particle.resampling.method.kitagawa", "false"); driver.option_num("particle.resampling.method.smooth", "false"); driver.option_num("particle.resampling.method.stratified", "true"); driver.option_num("particle.resampling.method.residual", "false"); };
| RESAMPLING_METHOD EQUAL RESIDUAL { driver.option_num("particle.resampling.method.kitagawa", "false"); driver.option_num("particle.resampling.method.smooth", "false"); driver.option_num("particle.resampling.method.stratified", "false"); driver.option_num("particle.resampling.method.residual", "true"); };
o_cpf_weights : CPF_WEIGHTS EQUAL AMISANOTRISTANI { driver.option_num("particle.cpf_weights_method.amisanotristani", "true"); driver.option_num("particle.cpf_weights_method.murrayjonesparslow", "false"); }
| CPF_WEIGHTS EQUAL MURRAYJONESPARSLOW { driver.option_num("particle.cpf_weights_method.amisanotristani", "false"); driver.option_num("particle.cpf_weights_method.murrayjonesparslow", "true"); };
| CPF_WEIGHTS EQUAL MURRAYJONESPARSLOW { driver.option_num("particle.cpf_weights_method.amisanotristani", "false"); driver.option_num("particle.cpf_weights_method.murrayjonesparslow", "true"); };
o_filter_algorithm : FILTER_ALGORITHM EQUAL symbol { driver.option_str("particle.filter_algorithm", $3); };
o_nonlinear_filter_initialization : NONLINEAR_FILTER_INITIALIZATION EQUAL INT_NUMBER { driver.option_num("particle.initialization", $3); };
o_proposal_approximation : PROPOSAL_APPROXIMATION EQUAL CUBATURE { driver.option_num("particle.proposal_approximation.cubature", "true"); driver.option_num("particle.proposal_approximation.unscented", "false"); driver.option_num("particle.proposal_approximation.montecarlo", "false"); }
......@@ -4278,10 +4355,11 @@ o_analytic_derivation_mode : ANALYTIC_DERIVATION_MODE EQUAL signed_number { driv
o_endogenous_prior : ENDOGENOUS_PRIOR { driver.option_num("endogenous_prior", "true"); }
o_use_univariate_filters_if_singularity_is_detected : USE_UNIVARIATE_FILTERS_IF_SINGULARITY_IS_DETECTED EQUAL INT_NUMBER { driver.option_num("use_univariate_filters_if_singularity_is_detected", $3); }
o_mcmc_jumping_covariance : MCMC_JUMPING_COVARIANCE EQUAL HESSIAN
{ driver.option_str("MCMC_jumping_covariance", $3); } | MCMC_JUMPING_COVARIANCE EQUAL PRIOR_VARIANCE
{ driver.option_str("MCMC_jumping_covariance", $3); }
{ driver.option_str("MCMC_jumping_covariance", "hessian"); }
| MCMC_JUMPING_COVARIANCE EQUAL PRIOR_VARIANCE
{ driver.option_str("MCMC_jumping_covariance", "prior_variance"); }
| MCMC_JUMPING_COVARIANCE EQUAL IDENTITY_MATRIX
{ driver.option_str("MCMC_jumping_covariance", $3); }
{ driver.option_str("MCMC_jumping_covariance", "identity_matrix"); }
| MCMC_JUMPING_COVARIANCE EQUAL filename
{ driver.option_str("MCMC_jumping_covariance", $3); }
;
......@@ -4352,7 +4430,7 @@ o_emas_girf : EMAS_GIRF { driver.option_num("irf_opt.ergodic_mean_irf", "true");
o_emas_drop : EMAS_DROP EQUAL INT_NUMBER { driver.option_num("irf_opt.EM.drop", $3); };
o_emas_tolf : EMAS_TOLF EQUAL non_negative_number { driver.option_num("irf_opt.EM.tolf", $3); };
o_emas_max_iter : EMAS_MAX_ITER EQUAL INT_NUMBER { driver.option_num("irf_opt.EM.iter", $3); };
o_non_zero : NON_ZERO { driver.option_num("non_zero", "true"); };
o_non_zero : NON_ZERO { driver.option_num("steady.non_zero", "true"); };
// Some options to "identification"
o_no_identification_strength : NO_IDENTIFICATION_STRENGTH { driver.option_num("no_identification_strength", "true"); };
......@@ -4442,9 +4520,8 @@ vec_int_number : INT_NUMBER
vec_int_elem : vec_int_number
| INT_NUMBER ':' INT_NUMBER
{
$$ = {};
for (int i = stoi($1); i <= stoi($3); i++)
$$.push_back(i);
auto v = views::iota(stoi($1), stoi($3) + 1);
$$ = {v.begin(), v.end()};
}
;
......@@ -4572,6 +4649,7 @@ symbol : NAME
| ADD
| MULTIPLY
| MFS
| RESIDUAL
;
%%
......
/* -*- C++ -*- */
/*
* Copyright © 2003-2024 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -20,7 +20,6 @@
%{
#include <cstring>
#include "ParsingDriver.hh"
using namespace std;
......@@ -60,7 +59,6 @@ string eofbuff;
%x VERBATIM_BLOCK
%x NATIVE
%x NATIVE_COMMENT
%x DATES_STATEMENT
%x LINE1
%x LINE2
%x LINE3
......@@ -70,7 +68,9 @@ string eofbuff;
#define YY_USER_ACTION location_increment(yylloc, yytext);
%}
DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
NAME [a-z_][a-z0-9_]*
FLOAT_NUMBER ((([0-9]*\.[0-9]+)|([0-9]+\.))([ed][-+]?[0-9]+)?)|([0-9]+[ed][-+]?[0-9]+)
DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4]|[sh][12])
%%
/* Code put at the beginning of yylex() */
......@@ -92,12 +92,12 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
}
/* spaces, tabs and carriage returns are ignored */
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,COMMENT,DATES_STATEMENT,LINE1,LINE2,LINE3>[[:space:]]+ { yylloc->step(); }
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,COMMENT,LINE1,LINE2,LINE3>[[:space:]]+ { yylloc->step(); }
/* Comments */
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,DATES_STATEMENT>%.*
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,DATES_STATEMENT>"//".*
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,DATES_STATEMENT>"/*" {comment_caller = YY_START; BEGIN COMMENT;}
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK>%.*
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK>"//".*
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK>"/*" {comment_caller = YY_START; BEGIN COMMENT;}
<COMMENT>"*/" {BEGIN comment_caller;}
<COMMENT>.
......@@ -111,6 +111,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<INITIAL>predetermined_variables {BEGIN DYNARE_STATEMENT; return token::PREDETERMINED_VARIABLES;}
<INITIAL>parameters {BEGIN DYNARE_STATEMENT; return token::PARAMETERS;}
<INITIAL>model_local_variable {BEGIN DYNARE_STATEMENT; return token::MODEL_LOCAL_VARIABLE;}
<INITIAL>heterogeneity_dimension {BEGIN DYNARE_STATEMENT; return token::HETEROGENEITY_DIMENSION;}
<INITIAL>model_info {BEGIN DYNARE_STATEMENT; return token::MODEL_INFO;}
<INITIAL>estimation {BEGIN DYNARE_STATEMENT; return token::ESTIMATION;}
<INITIAL>set_time {BEGIN DYNARE_STATEMENT; return token::SET_TIME;}
......@@ -235,6 +236,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<INITIAL>pac_target_info {BEGIN DYNARE_BLOCK; return token::PAC_TARGET_INFO;}
<INITIAL>matched_irfs {BEGIN DYNARE_BLOCK; return token::MATCHED_IRFS;}
<INITIAL>matched_irfs_weights {BEGIN DYNARE_BLOCK; return token::MATCHED_IRFS_WEIGHTS;}
<INITIAL>perfect_foresight_controlled_paths {BEGIN DYNARE_BLOCK; return token::PERFECT_FORESIGHT_CONTROLLED_PATHS;}
/* For the semicolon after an "end" keyword */
<INITIAL>; {return Dynare::parser::token_type (yytext[0]);}
......@@ -245,7 +247,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>subsamples {return token::SUBSAMPLES;}
<DYNARE_STATEMENT>options {return token::OPTIONS;}
<DYNARE_STATEMENT>prior {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::PRIOR;
}
<INITIAL>std {BEGIN DYNARE_STATEMENT; return token::STD;}
......@@ -255,31 +257,12 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<INITIAL>prior_function {BEGIN DYNARE_STATEMENT; return token::PRIOR_FUNCTION;}
<INITIAL>posterior_function {BEGIN DYNARE_STATEMENT; return token::POSTERIOR_FUNCTION;}
/* Inside of a Dynare statement */
<DYNARE_STATEMENT>{DATE} {
char* yycopy = strdup(yytext);
char* uput = yycopy + yyleng;
unput(')');
unput('\'');
while (uput > yycopy)
unput(*--uput);
unput('\'');
unput('(');
unput('s');
unput('e');
unput('t');
unput('a');
unput('d');
free( yycopy );
}
<DYNARE_STATEMENT>${DATE} { yylloc->step();
#if (YY_FLEX_MAJOR_VERSION > 2) || (YY_FLEX_MAJOR_VERSION == 2 && YY_FLEX_MINOR_VERSION >= 6)
yyout << yytext + 1;
#else
*yyout << yytext + 1;
#endif
}
<DYNARE_STATEMENT>dates {dates_parens_nb=0; BEGIN DATES_STATEMENT; yylval->build<string>("dates");}
<DYNARE_STATEMENT,DYNARE_BLOCK>{DATE} {
yylval->emplace<string>(yytext);
return token::DATE;
}
/* Inside a Dynare statement */
<DYNARE_STATEMENT>file {return token::FILE;}
<DYNARE_STATEMENT>datafile {return token::DATAFILE;}
<DYNARE_STATEMENT>dirname {return token::DIRNAME;}
......@@ -312,10 +295,10 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>posterior_nograph {return token::POSTERIOR_NOGRAPH;}
<DYNARE_STATEMENT>nodisplay {return token::NODISPLAY;}
<DYNARE_STATEMENT>graph_format {return token::GRAPH_FORMAT;}
<DYNARE_STATEMENT>eps {yylval->build<string>(yytext); return token::EPS;}
<DYNARE_STATEMENT>pdf {yylval->build<string>(yytext); return token::PDF;}
<DYNARE_STATEMENT>fig {yylval->build<string>(yytext); return token::FIG;}
<DYNARE_STATEMENT>none {yylval->build<string>(yytext); return token::NONE;}
<DYNARE_STATEMENT>eps {yylval->emplace<string>(yytext); return token::EPS;}
<DYNARE_STATEMENT>pdf {yylval->emplace<string>(yytext); return token::PDF;}
<DYNARE_STATEMENT>fig {yylval->emplace<string>(yytext); return token::FIG;}
<DYNARE_STATEMENT>none {yylval->emplace<string>(yytext); return token::NONE;}
<DYNARE_STATEMENT>print {return token::PRINT;}
<DYNARE_STATEMENT>noprint {return token::NOPRINT;}
<DYNARE_STATEMENT>conf_sig {return token::CONF_SIG;}
......@@ -423,6 +406,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>logarithmic_reduction {return token::LOGARITHMIC_REDUCTION;}
<DYNARE_STATEMENT>use_univariate_filters_if_singularity_is_detected {return token::USE_UNIVARIATE_FILTERS_IF_SINGULARITY_IS_DETECTED;}
<DYNARE_STATEMENT>hybrid {return token::HYBRID;}
<DYNARE_STATEMENT>use_first_order_solution {return token::USE_FIRST_ORDER_SOLUTION;}
<DYNARE_STATEMENT>default {return token::DEFAULT;}
<DYNARE_STATEMENT>init2shocks {return token::INIT2SHOCKS;}
......@@ -435,6 +419,10 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>kitagawa {return token::KITAGAWA;}
<DYNARE_STATEMENT>smooth {return token::SMOOTH;}
<DYNARE_STATEMENT>stratified {return token::STRATIFIED;}
<DYNARE_STATEMENT>residual {
yylval->emplace<string>(yytext);
return token::RESIDUAL;
}
<DYNARE_STATEMENT>cpf_weights {return token::CPF_WEIGHTS;}
<DYNARE_STATEMENT>amisanotristani {return token::AMISANOTRISTANI;}
<DYNARE_STATEMENT>murrayjonesparslow {return token::MURRAYJONESPARSLOW;}
......@@ -456,43 +444,40 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>fsolve_options {return token::FSOLVE_OPTIONS;}
<DYNARE_STATEMENT>alpha {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::ALPHA;
}
<DYNARE_STATEMENT>beta {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::BETA;
}
<DYNARE_STATEMENT>gamma {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::GAMMA;
}
<DYNARE_STATEMENT>inv_gamma {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::INV_GAMMA;
}
<DYNARE_STATEMENT>inv_gamma1 {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::INV_GAMMA1;
}
<DYNARE_STATEMENT>inv_gamma2 {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::INV_GAMMA2;
}
<DYNARE_STATEMENT>dirichlet {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::DIRICHLET;
}
<DYNARE_STATEMENT>weibull {
yylval->build<string>(yytext);
return token::WEIBULL;
}
<DYNARE_STATEMENT>weibull {return token::WEIBULL;}
<DYNARE_STATEMENT>normal {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::NORMAL;
}
<DYNARE_STATEMENT>uniform {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::UNIFORM;
}
<DYNARE_STATEMENT>gsig2_lmdm {return token::GSIG2_LMDM;}
......@@ -503,13 +488,13 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>ncsk {return token::NCSK;}
<DYNARE_STATEMENT>nstd {return token::NSTD;}
<DYNARE_STATEMENT>ninv {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::NINV;
}
<DYNARE_STATEMENT>indxparr {return token::INDXPARR;}
<DYNARE_STATEMENT>indxovr {return token::INDXOVR;}
<DYNARE_STATEMENT>aband {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::ABAND;
}
<DYNARE_STATEMENT>write_equation_tags {return token::WRITE_EQUATION_TAGS;}
......@@ -526,18 +511,18 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>indxgdls {return token::INDXGDLS;}
<DYNARE_STATEMENT>eq_ms {return token::EQ_MS;}
<DYNARE_STATEMENT>cms {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::CMS;
}
<DYNARE_STATEMENT>ncms {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::NCMS;
}
<DYNARE_STATEMENT>eq_cms {return token::EQ_CMS;}
<DYNARE_STATEMENT>tlindx {return token::TLINDX;}
<DYNARE_STATEMENT>tlnumber {return token::TLNUMBER;}
<DYNARE_STATEMENT>cnum {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::CNUM;
}
<DYNARE_STATEMENT>nodecomposition {return token::NODECOMPOSITION;};
......@@ -619,18 +604,9 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>substitute_libs {return token::SUBSTITUTE_LIBS;}
<DYNARE_STATEMENT>compiler {return token::COMPILER;}
<DYNARE_STATEMENT>instruments {return token::INSTRUMENTS;}
<DYNARE_STATEMENT>hessian {
yylval->build<string>(yytext);
return token::HESSIAN;
}
<DYNARE_STATEMENT>prior_variance {
yylval->build<string>(yytext);
return token::PRIOR_VARIANCE;
}
<DYNARE_STATEMENT>identity_matrix {
yylval->build<string>(yytext);
return token::IDENTITY_MATRIX;
}
<DYNARE_STATEMENT>hessian {return token::HESSIAN;}
<DYNARE_STATEMENT>prior_variance {return token::PRIOR_VARIANCE;}
<DYNARE_STATEMENT>identity_matrix {return token::IDENTITY_MATRIX;}
<DYNARE_STATEMENT>mcmc_jumping_covariance {return token::MCMC_JUMPING_COVARIANCE;}
/* These four (var, varexo, varexo_det, parameters) are for change_type */
......@@ -730,14 +706,6 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>lmmcp {return token::LMMCP;}
<DYNARE_STATEMENT>additional_optimizer_steps {return token::ADDITIONAL_OPTIMIZER_STEPS;}
<DYNARE_STATEMENT>bartlett_kernel_lag {return token::BARTLETT_KERNEL_LAG; }
<DYNARE_STATEMENT>optimal {
yylval->build<string>(yytext);
return token::OPTIMAL;
}
<DYNARE_STATEMENT>diagonal {
yylval->build<string>(yytext);
return token::DIAGONAL;
}
<DYNARE_STATEMENT>gmm {return token::GMM;}
<DYNARE_STATEMENT>smm {return token::SMM;}
<DYNARE_STATEMENT>irf_matching {return token::IRF_MATCHING;}
......@@ -783,8 +751,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>non_zero {return token::NON_ZERO;}
<DYNARE_STATEMENT>\$[^$]*\$ {
strtok(yytext + 1, "$");
yylval->build<string>(yytext + 1);
yylval->emplace<string>(yytext + 1).pop_back();
return token::TEX_NAME;
}
......@@ -797,20 +764,21 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK>periods {return token::PERIODS;}
<DYNARE_BLOCK>scales {return token::SCALES;}
<DYNARE_BLOCK>add {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::ADD;
}
<DYNARE_BLOCK>multiply {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::MULTIPLY;
}
<DYNARE_STATEMENT,DYNARE_BLOCK>cutoff {return token::CUTOFF;}
<DYNARE_STATEMENT,DYNARE_BLOCK>mfs {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::MFS;
}
<DYNARE_STATEMENT,DYNARE_BLOCK>static_mfs {return token::STATIC_MFS;}
<DYNARE_STATEMENT,DYNARE_BLOCK>balanced_growth_test_tol {return token::BALANCED_GROWTH_TEST_TOL;}
<DYNARE_STATEMENT,DYNARE_BLOCK>heterogeneity {return token::HETEROGENEITY;}
<DYNARE_BLOCK>gamma_pdf {return token::GAMMA_PDF;}
<DYNARE_BLOCK>beta_pdf {return token::BETA_PDF;}
<DYNARE_BLOCK>normal_pdf {return token::NORMAL_PDF;}
......@@ -822,19 +790,19 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK>dsge_prior_weight {return token::DSGE_PRIOR_WEIGHT;}
<DYNARE_BLOCK>surprise {return token::SURPRISE;}
<DYNARE_BLOCK>bind {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::BIND;
}
<DYNARE_BLOCK>relax {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::RELAX;
}
<DYNARE_BLOCK>error_bind {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::ERROR_BIND;
}
<DYNARE_BLOCK>error_relax {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::ERROR_RELAX;
}
<DYNARE_BLOCK>relative_to_initval {return token::RELATIVE_TO_INITVAL;}
......@@ -848,22 +816,24 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK,DYNARE_STATEMENT>auxname {return token::AUXNAME;}
<DYNARE_BLOCK>auxname_target_nonstationary {return token::AUXNAME_TARGET_NONSTATIONARY;}
<DYNARE_BLOCK,DYNARE_STATEMENT>kind {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::KIND;
}
<DYNARE_BLOCK,DYNARE_STATEMENT>ll {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::LL;
}
<DYNARE_BLOCK,DYNARE_STATEMENT>dl {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::DL;
}
<DYNARE_BLOCK,DYNARE_STATEMENT>dd {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::DD;
}
<DYNARE_BLOCK>weights {return token::WEIGHTS;}
<DYNARE_BLOCK>exogenize {return token::EXOGENIZE;}
<DYNARE_BLOCK>endogenize {return token::ENDOGENIZE;}
/* Inside Dynare statement */
<DYNARE_STATEMENT>solve_algo {return token::SOLVE_ALGO;}
......@@ -875,7 +845,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>order {return token::ORDER;}
<DYNARE_STATEMENT>lyapunov {return token::LYAPUNOV;}
<DYNARE_STATEMENT>dr {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::DR;
}
<DYNARE_STATEMENT>lyapunov_complex_threshold {return token::LYAPUNOV_COMPLEX_THRESHOLD;}
......@@ -939,11 +909,11 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>time_shift {return token::TIME_SHIFT;}
<DYNARE_STATEMENT>structural {return token::STRUCTURAL;}
<DYNARE_STATEMENT>true {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::TRUE;
}
<DYNARE_STATEMENT>false {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::FALSE;
}
......@@ -1011,6 +981,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_BLOCK>var_expectation {return token::VAR_EXPECTATION;}
<DYNARE_BLOCK>pac_expectation {return token::PAC_EXPECTATION;}
<DYNARE_BLOCK>pac_target_nonstationary {return token::PAC_TARGET_NONSTATIONARY;}
<DYNARE_BLOCK>sum {return token::SUM;}
<DYNARE_STATEMENT>discount {return token::DISCOUNT;}
<DYNARE_STATEMENT,DYNARE_BLOCK>varobs {return token::VAROBS;}
<DYNARE_STATEMENT,DYNARE_BLOCK>varexobs {return token::VAREXOBS;}
......@@ -1066,38 +1037,27 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<DYNARE_STATEMENT>use_shock_groups {return token::USE_SHOCK_GROUPS;}
<DYNARE_STATEMENT>colormap {return token::COLORMAP;}
<DYNARE_STATEMENT,DYNARE_BLOCK>[a-z_][a-z0-9_]* {
yylval->build<string>(yytext);
<DYNARE_STATEMENT,DYNARE_BLOCK>{NAME} {
yylval->emplace<string>(yytext);
return token::NAME;
}
<DYNARE_STATEMENT,DYNARE_BLOCK>((([0-9]*\.[0-9]+)|([0-9]+\.))([ed][-+]?[0-9]+)?)|([0-9]+[ed][-+]?[0-9]+) {
yylval->build<string>(yytext);
<DYNARE_STATEMENT,DYNARE_BLOCK>{FLOAT_NUMBER} {
yylval->emplace<string>(yytext);
return token::FLOAT_NUMBER;
}
<DYNARE_STATEMENT,DYNARE_BLOCK>[0-9]+ {
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::INT_NUMBER;
}
<DATES_STATEMENT>\( { yylval->as<string>().append(yytext); dates_parens_nb++; }
<DATES_STATEMENT>\) {
yylval->as<string>().append(yytext);
if (--dates_parens_nb == 0)
{
BEGIN DYNARE_STATEMENT;
return token::DATES;
}
}
<DATES_STATEMENT>. { yylval->as<string>().append(yytext); }
<DYNARE_BLOCK>\|e { return token::PIPE_E; }
<DYNARE_BLOCK>\|x { return token::PIPE_X; }
<DYNARE_BLOCK>\|p { return token::PIPE_P; }
<DYNARE_STATEMENT,DYNARE_BLOCK>\'[^\']*\' {
yylval->build<string>(yytext + 1).pop_back();
yylval->emplace<string>(yytext + 1).pop_back();
return token::QUOTED_STRING;
}
......@@ -1129,11 +1089,11 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
element in initval (in which case Dynare recognizes the matrix name as an external
function symbol), and may want to modify the matrix later with Matlab statements.
*/
<INITIAL>[a-z_][a-z0-9_]* {
<INITIAL>{NAME} {
if (driver.symbol_exists_and_is_not_modfile_local_or_external_function(yytext))
{
BEGIN DYNARE_STATEMENT;
yylval->build<string>(yytext);
yylval->emplace<string>(yytext);
return token::NAME;
}
else
......@@ -1154,7 +1114,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
be able to back out of the statement if we realize it's a native statement
and move to the NATIVE context
*/
<INITIAL>\[([[:space:]]*[a-z_][a-z0-9_]*[[:space:]]*,{1}[[:space:]]*)*([[:space:]]*[a-z_][a-z0-9_]*[[:space:]]*){1}\] {
<INITIAL>\[([[:space:]]*{NAME}[[:space:]]*,{1}[[:space:]]*)*([[:space:]]*{NAME}[[:space:]]*){1}\] {
string yytextcpy{yytext};
yytextcpy.erase(remove(yytextcpy.begin(), yytextcpy.end(), '['), yytextcpy.end());
yytextcpy.erase(remove(yytextcpy.begin(), yytextcpy.end(), ']'), yytextcpy.end());
......@@ -1178,7 +1138,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
if (dynare_statement)
{
BEGIN DYNARE_STATEMENT;
yylval->build<vector<string>>(val);
yylval->emplace<vector<string>>(val);
return token::SYMBOL_VEC;
}
}
......@@ -1223,7 +1183,7 @@ DATE -?[0-9]+([ya]|m([1-9]|1[0-2])|q[1-4])
<NATIVE_COMMENT>"*/"[[:space:]]*\n { BEGIN NATIVE; }
<NATIVE_COMMENT>.
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,COMMENT,DATES_STATEMENT,LINE1,LINE2,LINE3,NATIVE_COMMENT><<EOF>> { yyterminate(); }
<INITIAL,DYNARE_STATEMENT,DYNARE_BLOCK,COMMENT,LINE1,LINE2,LINE3,NATIVE_COMMENT><<EOF>> { yyterminate(); }
<*>. { driver.error(*yylloc, "character unrecognized by lexer"); }
%%
......
/*
* Copyright © 2020-2023 Dynare Team
* Copyright © 2020-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -74,13 +74,12 @@ EquationTags::erase(const set<int>& eqns, const map<int, int>& old_eqn_num_2_new
eqn_tags.erase(eqn);
for (const auto& [oldeqn, neweqn] : old_eqn_num_2_new)
for (auto& [eqn, tags] : eqn_tags)
if (eqn == oldeqn)
{
auto tmp = eqn_tags.extract(eqn);
tmp.key() = neweqn;
eqn_tags.insert(move(tmp));
}
if (eqn_tags.contains(oldeqn))
{
auto tmp = eqn_tags.extract(oldeqn);
tmp.key() = neweqn;
eqn_tags.insert(move(tmp));
}
}
void
......
/*
* Copyright © 2007-2024 Dynare Team
* Copyright © 2007-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -870,6 +870,13 @@ NumConstNode::substituteLogTransform([[maybe_unused]] int orig_symb_id,
return const_cast<NumConstNode*>(this);
}
expr_t
NumConstNode::substituteAggregationOperators([[maybe_unused]] subst_table_t& subst_table,
[[maybe_unused]] vector<BinaryOpNode*>& neweqs) const
{
return const_cast<NumConstNode*>(this);
}
VariableNode::VariableNode(DataTree& datatree_arg, int idx_arg, int symb_id_arg, int lag_arg) :
ExprNode {datatree_arg, idx_arg}, symb_id {symb_id_arg}, lag {lag_arg}
{
......@@ -900,6 +907,7 @@ VariableNode::prepareForDerivation()
[[fallthrough]];
case SymbolType::endogenous:
case SymbolType::parameter:
case SymbolType::heterogeneousEndogenous:
non_null_derivatives.insert(getDerivID());
break;
case SymbolType::modelLocalVariable:
......@@ -907,6 +915,8 @@ VariableNode::prepareForDerivation()
// Non null derivatives are those of the value of the local parameter
non_null_derivatives = datatree.getLocalVariable(symb_id, lag)->non_null_derivatives;
break;
case SymbolType::heterogeneousExogenous:
case SymbolType::heterogeneousParameter:
case SymbolType::modFileLocalVariable:
case SymbolType::statementDeclaredVariable:
case SymbolType::unusedEndogenous:
......@@ -955,6 +965,9 @@ VariableNode::prepareForChainRuleDerivation(
case SymbolType::modFileLocalVariable:
case SymbolType::statementDeclaredVariable:
case SymbolType::unusedEndogenous:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
case SymbolType::heterogeneousParameter:
// Those variables are never derived using chain rule
non_null_chain_rule_derivatives.try_emplace(const_cast<VariableNode*>(this));
break;
......@@ -990,10 +1003,14 @@ VariableNode::computeDerivative(int deriv_id)
[[fallthrough]];
case SymbolType::endogenous:
case SymbolType::parameter:
case SymbolType::heterogeneousEndogenous:
if (deriv_id == getDerivID())
return datatree.One;
else
return datatree.Zero;
case SymbolType::heterogeneousExogenous:
case SymbolType::heterogeneousParameter:
return datatree.Zero;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)->getDerivative(deriv_id);
case SymbolType::modFileLocalVariable:
......@@ -1069,8 +1086,23 @@ VariableNode::writeJsonAST(ostream& output) const
case SymbolType::excludedVariable:
cerr << "VariableNode::computeDerivative: Impossible case!" << endl;
exit(EXIT_FAILURE);
case SymbolType::heterogeneousEndogenous:
output << "heterogeneousEndogenous";
break;
case SymbolType::heterogeneousExogenous:
output << "heterogeneousExogenous";
break;
case SymbolType::heterogeneousParameter:
output << "heterogeneousParameter";
break;
}
output << R"(", "lag" : )" << lag << "}";
output << '"';
if (isHeterogeneous(get_type()))
output << R"(, "heterogeneity_dimension" : ")"
<< datatree.heterogeneity_table.getName(
datatree.symbol_table.getHeterogeneityDimension(symb_id))
<< '"';
output << R"(, "lag" : )" << lag << "}";
}
void
......@@ -1168,12 +1200,18 @@ VariableNode::writeOutput(ostream& output, ExprNodeOutputType output_type,
case SymbolType::endogenous:
switch (int tsid {getTypeSpecificID()}; output_type)
{
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::juliaSparseDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::matlabSparseDynamicModel:
case ExprNodeOutputType::CDynamicModel:
case ExprNodeOutputType::CSparseDynamicModel:
assert(lag >= -1 && lag <= 1);
i = tsid + (lag + 1) * datatree.symbol_table.endo_nbr()
+ ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::CDynamicModel:
i = datatree.getJacobianCol(getDerivID(), isSparseModelOutput(output_type))
+ ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i
......@@ -1405,6 +1443,64 @@ VariableNode::writeOutput(ostream& output, ExprNodeOutputType output_type,
case SymbolType::excludedVariable:
cerr << "VariableNode::writeOutput: Impossible case" << endl;
exit(EXIT_FAILURE);
case SymbolType::heterogeneousEndogenous:
switch (int tsid = datatree.symbol_table.getTypeSpecificID(symb_id); output_type)
{
case ExprNodeOutputType::juliaSparseDynamicModel:
case ExprNodeOutputType::matlabSparseDynamicModel:
case ExprNodeOutputType::CSparseDynamicModel:
assert(lag >= -1 && lag <= 1);
i = tsid
+ (lag + 1)
* datatree.symbol_table.het_endo_nbr(
datatree.symbol_table.getHeterogeneityDimension(symb_id))
+ ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "yh" << LEFT_ARRAY_SUBSCRIPT(output_type) << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: unsupported output type for heterogeneousEndogenous "
"symbol"
<< endl;
exit(EXIT_FAILURE);
}
break;
case SymbolType::heterogeneousExogenous:
i = datatree.symbol_table.getTypeSpecificID(symb_id) + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case ExprNodeOutputType::juliaSparseDynamicModel:
case ExprNodeOutputType::matlabSparseDynamicModel:
case ExprNodeOutputType::CSparseDynamicModel:
assert(lag == 0);
output << "xh" << LEFT_ARRAY_SUBSCRIPT(output_type) << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: unsupported output type for heterogeneousExogenous "
"symbol"
<< endl;
exit(EXIT_FAILURE);
}
break;
case SymbolType::heterogeneousParameter:
i = datatree.symbol_table.getTypeSpecificID(symb_id) + ARRAY_SUBSCRIPT_OFFSET(output_type);
switch (output_type)
{
case ExprNodeOutputType::juliaSparseDynamicModel:
case ExprNodeOutputType::matlabSparseDynamicModel:
case ExprNodeOutputType::CSparseDynamicModel:
output << "paramsh" << LEFT_ARRAY_SUBSCRIPT(output_type) << i
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
default:
cerr << "VariableNode::writeOutput: unsupported output type for heterogeneousParameter "
"symbol"
<< endl;
exit(EXIT_FAILURE);
}
break;
}
}
......@@ -1519,6 +1615,7 @@ VariableNode::computeChainRuleDerivative(
[[fallthrough]];
case SymbolType::endogenous:
case SymbolType::parameter:
case SymbolType::heterogeneousEndogenous:
if (deriv_id == getDerivID())
return datatree.One;
// If there is in the equation a recursive variable we could use a chaine rule derivation
......@@ -1527,6 +1624,9 @@ VariableNode::computeChainRuleDerivative(
non_null_chain_rule_derivatives, cache);
else
return datatree.Zero;
case SymbolType::heterogeneousExogenous:
case SymbolType::heterogeneousParameter:
return datatree.Zero;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)
......@@ -1584,6 +1684,9 @@ VariableNode::computeXrefs(EquationInfo& ei) const
case SymbolType::externalFunction:
case SymbolType::epilogue:
case SymbolType::excludedVariable:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
case SymbolType::heterogeneousParameter:
break;
}
}
......@@ -1682,6 +1785,9 @@ VariableNode::maxLead() const
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::epilogue:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
return lag;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)->maxLead();
......@@ -1698,6 +1804,9 @@ VariableNode::maxLag() const
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::epilogue:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
return -lag;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)->maxLag();
......@@ -1715,6 +1824,8 @@ VariableNode::maxLagWithDiffsExpanded() const
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::epilogue:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
return -lag;
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)->maxLagWithDiffsExpanded();
......@@ -1836,8 +1947,11 @@ VariableNode::decreaseLeadsLags(int n) const
case SymbolType::endogenous:
case SymbolType::exogenous:
case SymbolType::exogenousDet:
case SymbolType::epilogue:
case SymbolType::trend:
case SymbolType::logTrend:
case SymbolType::heterogeneousEndogenous:
case SymbolType::heterogeneousExogenous:
return datatree.AddVariable(symb_id, lag - n);
case SymbolType::modelLocalVariable:
return datatree.getLocalVariable(symb_id, lag)->decreaseLeadsLags(n);
......@@ -2234,6 +2348,17 @@ VariableNode::substituteLogTransform(int orig_symb_id, int aux_symb_id) const
return const_cast<VariableNode*>(this);
}
expr_t
VariableNode::substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
{
if (get_type() == SymbolType::modelLocalVariable)
return datatree.getLocalVariable(symb_id, lag)
->substituteAggregationOperators(subst_table, neweqs);
return const_cast<VariableNode*>(this);
}
UnaryOpNode::UnaryOpNode(DataTree& datatree_arg, int idx_arg, UnaryOpcode op_code_arg,
const expr_t arg_arg, int expectation_information_set_arg,
int param1_symb_id_arg, int param2_symb_id_arg, string adl_param_name_arg,
......@@ -2259,12 +2384,12 @@ UnaryOpNode::prepareForDerivation()
/* Non-null derivatives are those of the argument (except for STEADY_STATE in
a dynamic context, in which case the potentially non-null derivatives are
all the parameters) */
all the parameters; and for SUM, which will be substituted out before deriving) */
if ((op_code == UnaryOpcode::steadyState || op_code == UnaryOpcode::steadyStateParamDeriv
|| op_code == UnaryOpcode::steadyStateParam2ndDeriv)
&& datatree.is_dynamic)
datatree.addAllParamDerivId(non_null_derivatives);
else
else if (op_code != UnaryOpcode::sum)
{
arg->prepareForDerivation();
non_null_derivatives = arg->non_null_derivatives;
......@@ -2441,6 +2566,9 @@ UnaryOpNode::composeDerivatives(expr_t darg, int deriv_id)
case UnaryOpcode::adl:
cerr << "UnaryOpNode::composeDerivatives: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::sum:
cerr << "UnaryOpNode::composeDerivatives: not implemented on UnaryOpcode::sum" << endl;
exit(EXIT_FAILURE);
}
__builtin_unreachable(); // Silence GCC warning
}
......@@ -2535,6 +2663,8 @@ UnaryOpNode::cost(int cost, bool is_matlab) const
case UnaryOpcode::adl:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::sum:
return 0; // In the generated files, the SUM() operator behaves like a variable
}
else
// Cost for C files
......@@ -2585,6 +2715,8 @@ UnaryOpNode::cost(int cost, bool is_matlab) const
case UnaryOpcode::adl:
cerr << "UnaryOpNode::cost: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::sum:
return 0; // In the generated files, the SUM() operator behaves like a variable
}
__builtin_unreachable(); // Silence GCC warning
}
......@@ -2729,6 +2861,9 @@ UnaryOpNode::writeJsonAST(ostream& output) const
case UnaryOpcode::erfc:
output << "erfc";
break;
case UnaryOpcode::sum:
output << "sum";
break;
}
output << R"(", "arg" : )";
arg->writeJsonAST(output);
......@@ -2843,10 +2978,8 @@ UnaryOpNode::writeJsonOutput(ostream& output, const temporary_terms_t& temporary
output << "])";
return;
case UnaryOpcode::steadyState:
output << "(";
arg->writeJsonOutput(output, temporary_terms, tef_terms, isdynamic);
output << ")";
return;
output << "STEADY_STATE";
break;
case UnaryOpcode::steadyStateParamDeriv:
{
auto varg = dynamic_cast<VariableNode*>(arg);
......@@ -2881,6 +3014,9 @@ UnaryOpNode::writeJsonOutput(ostream& output, const temporary_terms_t& temporary
case UnaryOpcode::erfc:
output << "erfc";
break;
case UnaryOpcode::sum:
output << "sum";
break;
}
bool close_parenthesis = false;
......@@ -3111,6 +3247,20 @@ UnaryOpNode::writeOutput(ostream& output, ExprNodeOutputType output_type,
case UnaryOpcode::adl:
output << "adl";
break;
case UnaryOpcode::sum:
if (isLatexOutput(output_type))
output << "sum";
else
{
auto varg {dynamic_cast<VariableNode*>(arg)};
assert(varg && varg->lag == 0);
int idx {
datatree.heterogeneity_table.getSummedHeterogenousEndogenousIndex(varg->symb_id)};
output << "yagg" << LEFT_ARRAY_SUBSCRIPT(output_type) << idx + 1
<< RIGHT_ARRAY_SUBSCRIPT(output_type);
return;
}
break;
}
if (output_type == ExprNodeOutputType::juliaTimeDataFrame && op_code != UnaryOpcode::uminus)
......@@ -3240,6 +3390,9 @@ UnaryOpNode::eval_opcode(UnaryOpcode op_code, double v) noexcept(false)
case UnaryOpcode::adl:
cerr << "UnaryOpNode::eval_opcode: not implemented on UnaryOpcode::adl" << endl;
exit(EXIT_FAILURE);
case UnaryOpcode::sum:
cerr << "UnaryOpNode::eval_opcode: not implemented on UnaryOpcode::sum" << endl;
exit(EXIT_FAILURE);
}
__builtin_unreachable(); // Silence GCC warning
}
......@@ -3497,6 +3650,8 @@ UnaryOpNode::buildSimilarUnaryOpNode(expr_t alt_arg, DataTree& alt_datatree) con
return alt_datatree.AddDiff(alt_arg);
case UnaryOpcode::adl:
return alt_datatree.AddAdl(alt_arg, adl_param_name, adl_lags);
case UnaryOpcode::sum:
return alt_datatree.AddSum(alt_arg);
}
__builtin_unreachable(); // Silence GCC warning
}
......@@ -4089,6 +4244,34 @@ UnaryOpNode::substituteLogTransform(int orig_symb_id, int aux_symb_id) const
return recurseTransform(&ExprNode::substituteLogTransform, orig_symb_id, aux_symb_id);
}
expr_t
UnaryOpNode::substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
{
if (op_code == UnaryOpcode::sum)
{
if (auto it = subst_table.find(const_cast<UnaryOpNode*>(this)); it != subst_table.end())
return const_cast<VariableNode*>(it->second);
// Arriving here, we need to create an auxiliary variable for this operator
const VariableNode* varg {dynamic_cast<const VariableNode*>(arg)};
assert(varg && varg->lag == 0);
const string varname {"SUM_" + varg->getName()};
int symb_id {datatree.symbol_table.addAggregationOpAuxiliaryVar(
varname, const_cast<UnaryOpNode*>(this))};
expr_t newAuxE = datatree.AddVariable(symb_id, 0);
subst_table[this] = dynamic_cast<VariableNode*>(newAuxE);
neweqs.push_back(datatree.AddEqual(newAuxE, const_cast<UnaryOpNode*>(this)));
datatree.heterogeneity_table.addSummedHeterogeneousEndogenous(varg->symb_id);
return newAuxE;
}
else
return recurseTransform(&ExprNode::substituteAggregationOperators, subst_table, neweqs);
}
BinaryOpNode::BinaryOpNode(DataTree& datatree_arg, int idx_arg, const expr_t arg1_arg,
BinaryOpcode op_code_arg, const expr_t arg2_arg,
int powerDerivOrder_arg) :
......@@ -6014,6 +6197,13 @@ BinaryOpNode::substituteLogTransform(int orig_symb_id, int aux_symb_id) const
return recurseTransform(&ExprNode::substituteLogTransform, orig_symb_id, aux_symb_id);
}
expr_t
BinaryOpNode::substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
{
return recurseTransform(&ExprNode::substituteAggregationOperators, subst_table, neweqs);
}
TrinaryOpNode::TrinaryOpNode(DataTree& datatree_arg, int idx_arg, const expr_t arg1_arg,
TrinaryOpcode op_code_arg, const expr_t arg2_arg,
const expr_t arg3_arg) :
......@@ -6266,9 +6456,9 @@ TrinaryOpNode::eval_opcode(double v1, TrinaryOpcode op_code, double v2, double v
switch (op_code)
{
case TrinaryOpcode::normcdf:
return (0.5 * (1 + erf((v1 - v2) / v3 / numbers::sqrt2)));
return 0.5 * (1 + erf((v1 - v2) / v3 / numbers::sqrt2));
case TrinaryOpcode::normpdf:
return (1 / (v3 * sqrt(2 * numbers::pi) * exp(pow((v1 - v2) / v3, 2) / 2)));
return 1 / (v3 * sqrt(2 * numbers::pi) * exp(pow((v1 - v2) / v3, 2) / 2));
}
__builtin_unreachable(); // Silence GCC warning
}
......@@ -6797,9 +6987,9 @@ TrinaryOpNode::isVariableNodeEqualTo([[maybe_unused]] SymbolType type_arg,
bool
TrinaryOpNode::containsPacExpectation(const string& pac_model_name) const
{
return (arg1->containsPacExpectation(pac_model_name)
|| arg2->containsPacExpectation(pac_model_name)
|| arg3->containsPacExpectation(pac_model_name));
return arg1->containsPacExpectation(pac_model_name)
|| arg2->containsPacExpectation(pac_model_name)
|| arg3->containsPacExpectation(pac_model_name);
}
bool
......@@ -6853,6 +7043,13 @@ TrinaryOpNode::substituteLogTransform(int orig_symb_id, int aux_symb_id) const
return recurseTransform(&ExprNode::substituteLogTransform, orig_symb_id, aux_symb_id);
}
expr_t
TrinaryOpNode::substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
{
return recurseTransform(&ExprNode::substituteAggregationOperators, subst_table, neweqs);
}
AbstractExternalFunctionNode::AbstractExternalFunctionNode(DataTree& datatree_arg, int idx_arg,
int symb_id_arg,
vector<expr_t> arguments_arg) :
......@@ -7402,6 +7599,13 @@ AbstractExternalFunctionNode::substituteLogTransform(int orig_symb_id, int aux_s
return recurseTransform(&ExprNode::substituteLogTransform, orig_symb_id, aux_symb_id);
}
expr_t
AbstractExternalFunctionNode::substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
{
return recurseTransform(&ExprNode::substituteAggregationOperators, subst_table, neweqs);
}
expr_t
AbstractExternalFunctionNode::toStatic(DataTree& static_datatree) const
{
......@@ -7685,7 +7889,6 @@ ExternalFunctionNode::writeJsonExternalFunctionOutput(vector<string>& efout,
void
ExternalFunctionNode::computeXrefs(EquationInfo& ei) const
{
vector<expr_t> dynamic_arguments;
for (auto argument : arguments)
argument->computeXrefs(ei);
}
......@@ -7702,7 +7905,7 @@ ExternalFunctionNode::sameTefTermPredicate() const
{
return [this](expr_t e) {
auto e2 = dynamic_cast<ExternalFunctionNode*>(e);
return (e2 != nullptr && e2->symb_id == symb_id && e2->arguments == arguments);
return e2 != nullptr && e2->symb_id == symb_id && e2->arguments == arguments;
};
}
......@@ -8029,7 +8232,6 @@ FirstDerivExternalFunctionNode::buildSimilarExternalFunctionNode(vector<expr_t>&
void
FirstDerivExternalFunctionNode::computeXrefs(EquationInfo& ei) const
{
vector<expr_t> dynamic_arguments;
for (auto argument : arguments)
argument->computeXrefs(ei);
}
......@@ -8041,12 +8243,12 @@ FirstDerivExternalFunctionNode::sameTefTermPredicate() const
if (first_deriv_symb_id == symb_id)
return [this](expr_t e) {
auto e2 = dynamic_cast<ExternalFunctionNode*>(e);
return (e2 && e2->symb_id == symb_id && e2->arguments == arguments);
return e2 && e2->symb_id == symb_id && e2->arguments == arguments;
};
else
return [this](expr_t e) {
auto e2 = dynamic_cast<FirstDerivExternalFunctionNode*>(e);
return (e2 && e2->symb_id == symb_id && e2->arguments == arguments);
return e2 && e2->symb_id == symb_id && e2->arguments == arguments;
};
}
......@@ -8308,7 +8510,6 @@ SecondDerivExternalFunctionNode::buildSimilarExternalFunctionNode(vector<expr_t>
void
SecondDerivExternalFunctionNode::computeXrefs(EquationInfo& ei) const
{
vector<expr_t> dynamic_arguments;
for (auto argument : arguments)
argument->computeXrefs(ei);
}
......@@ -8397,12 +8598,12 @@ SecondDerivExternalFunctionNode::sameTefTermPredicate() const
if (second_deriv_symb_id == symb_id)
return [this](expr_t e) {
auto e2 = dynamic_cast<ExternalFunctionNode*>(e);
return (e2 && e2->symb_id == symb_id && e2->arguments == arguments);
return e2 && e2->symb_id == symb_id && e2->arguments == arguments;
};
else
return [this](expr_t e) {
auto e2 = dynamic_cast<SecondDerivExternalFunctionNode*>(e);
return (e2 && e2->symb_id == symb_id && e2->arguments == arguments);
return e2 && e2->symb_id == symb_id && e2->arguments == arguments;
};
}
......@@ -8763,6 +8964,13 @@ SubModelNode::substituteLogTransform([[maybe_unused]] int orig_symb_id,
return const_cast<SubModelNode*>(this);
}
expr_t
SubModelNode::substituteAggregationOperators([[maybe_unused]] subst_table_t& subst_table,
[[maybe_unused]] vector<BinaryOpNode*>& neweqs) const
{
return const_cast<SubModelNode*>(this);
}
VarExpectationNode::VarExpectationNode(DataTree& datatree_arg, int idx_arg, string model_name_arg) :
SubModelNode {datatree_arg, idx_arg, move(model_name_arg)}
{
......@@ -9281,9 +9489,9 @@ ExprNode::matchParamTimesTargetMinusVariable(int symb_id) const
auto& avi = datatree.symbol_table.getAuxVarInfo(target->symb_id);
if (avi.type == AuxVarType::pacTargetNonstationary && target->lag == -1)
return true;
return (avi.type == AuxVarType::unaryOp && avi.unary_op == "log" && avi.orig_symb_id
&& !datatree.symbol_table.isAuxiliaryVariable(*avi.orig_symb_id)
&& target->lag + avi.orig_lead_lag.value() == -1);
return avi.type == AuxVarType::unaryOp && avi.unary_op == "log" && avi.orig_symb_id
&& !datatree.symbol_table.isAuxiliaryVariable(*avi.orig_symb_id)
&& target->lag + avi.orig_lead_lag.value() == -1;
}
else
return target->lag == -1;
......@@ -9362,13 +9570,14 @@ ExprNode::toString() const
}
tuple<int, expr_t, expr_t>
ExprNode::matchComplementarityCondition() const
ExprNode::matchComplementarityCondition(
[[maybe_unused]] const optional<int>& heterogeneity_dimension) const
{
throw MatchFailureException {"This expression is not an inequality"};
}
tuple<int, expr_t, expr_t>
BinaryOpNode::matchComplementarityCondition() const
BinaryOpNode::matchComplementarityCondition(const optional<int>& heterogeneity_dimension) const
{
bool is_greater {[&] {
switch (op_code)
......@@ -9386,7 +9595,13 @@ BinaryOpNode::matchComplementarityCondition() const
auto match_contemporaneous_endogenous = [&](expr_t e) -> optional<int> {
auto* ve = dynamic_cast<VariableNode*>(e);
if (ve && ve->lag == 0 && datatree.symbol_table.getType(ve->symb_id) == SymbolType::endogenous)
if (ve && ve->lag == 0
&& ((!heterogeneity_dimension
&& datatree.symbol_table.getType(ve->symb_id) == SymbolType::endogenous)
|| (heterogeneity_dimension
&& datatree.symbol_table.getType(ve->symb_id) == SymbolType::heterogeneousEndogenous
&& datatree.symbol_table.getHeterogeneityDimension(ve->symb_id)
== *heterogeneity_dimension)))
return ve->symb_id;
else
return nullopt;
......@@ -9423,11 +9638,11 @@ BinaryOpNode::matchComplementarityCondition() const
|| (!is_greater
&& (barg1->op_code == BinaryOpcode::less
|| barg1->op_code == BinaryOpcode::lessEqual)))))
throw MatchFailureException {"Complementarity condition does not have the right form"};
throw MatchFailureException {};
auto id = match_contemporaneous_endogenous(barg1->arg2);
if (!id)
throw MatchFailureException {"Complementarity condition does not have the right form"};
throw MatchFailureException {};
check_bound_constant(barg1->arg1);
check_bound_constant(arg2);
......
/*
* Copyright © 2007-2024 Dynare Team
* Copyright © 2007-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -283,7 +283,7 @@ protected:
min_cost(bool is_matlab)
{
return is_matlab ? min_cost_matlab : min_cost_c;
};
}
//! Initializes data member non_null_derivatives
virtual void prepareForDerivation() = 0;
......@@ -572,38 +572,35 @@ public:
{
};
//! Returns the maximum lead of endogenous in this expression
//! Returns the maximum lead of endogenous in this expression (not incl. heterogeneous endo)
/*! Always returns a non-negative value */
[[nodiscard]] virtual int maxEndoLead() const = 0;
//! Returns the maximum lead of exogenous in this expression
//! Returns the maximum lead of exogenous in this expression (not incl. heterogeneous exo)
/*! Always returns a non-negative value */
[[nodiscard]] virtual int maxExoLead() const = 0;
//! Returns the maximum lag of endogenous in this expression
//! Returns the maximum lag of endogenous in this expression (not incl. heterogeneous endo)
/*! Always returns a non-negative value */
[[nodiscard]] virtual int maxEndoLag() const = 0;
//! Returns the maximum lag of exogenous in this expression
//! Returns the maximum lag of exogenous in this expression (not incl. heterogeneous exo)
/*! Always returns a non-negative value */
[[nodiscard]] virtual int maxExoLag() const = 0;
//! Returns the maximum lead of endo/exo/exodet in this expression
/*! A negative value means that the expression contains only lagged
variables. A value of numeric_limits<int>::min() means that there is
no variable. */
/* Returns the maximum lead of endo/exo/exodet in this expression (including heterogeneous
endo/exo). A negative value means that the expression contains only lagged variables. A value
of numeric_limits<int>::min() means that there is no variable. */
[[nodiscard]] virtual int maxLead() const = 0;
//! Returns the maximum lag of endo/exo/exodet in this expression
/*! A negative value means that the expression contains only leaded
variables. A value of numeric_limits<int>::min() means that there is
no variable. */
/* Returns the maximum lag of endo/exo/exodet in this expression (including heterogeneous
endo/exo). A negative value means that the expression contains only leaded variables. A value
of numeric_limits<int>::min() means that there is no variable. */
[[nodiscard]] virtual int maxLag() const = 0;
//! Returns the maximum lag of endo/exo/exodet, as if diffs were expanded
/*! This function behaves as maxLag(), except that it treats diff()
differently. For e.g., on diff(diff(x(-1))), maxLag() returns 1 while
maxLagWithDiffsExpanded() returns 3. */
/* Returns the maximum lag of endo/exo/exodet (including heterogeneous endo/exo), as if diffs were
expanded. This function behaves as maxLag(), except that it treats diff() differently. For
e.g., on diff(diff(x(-1))), maxLag() returns 1 while maxLagWithDiffsExpanded() returns 3. */
[[nodiscard]] virtual int maxLagWithDiffsExpanded() const = 0;
[[nodiscard]] virtual expr_t undiff() const = 0;
......@@ -946,7 +943,15 @@ public:
/* Matches an expression that constitutes a complementarity condition.
If successful, returns a triplet (endo_symb_id, lower_bound, upper_bound).
Otherwise, throws a MatchFailureException. */
[[nodiscard]] virtual tuple<int, expr_t, expr_t> matchComplementarityCondition() const;
[[nodiscard]] virtual tuple<int, expr_t, expr_t>
matchComplementarityCondition(const optional<int>& heterogeneity_dimension = nullopt) const;
/* Replaces aggregation operators (e.g. SUM()) by new auxiliary variables.
Also declares those aggregation operators in the HeterogeneityTable, so as to
compute their index in the dedicated vector in argument of the dynamic/static files. */
[[nodiscard]] virtual expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const
= 0;
};
//! Object used to compare two nodes (using their indexes)
......@@ -1058,6 +1063,8 @@ public:
= "") const override;
[[nodiscard]] bool isParamTimesEndogExpr() const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
};
//! Symbol or variable node
......@@ -1165,6 +1172,8 @@ public:
vector<int>& powers) const override;
[[nodiscard]] pair<int, expr_t> matchEndogenousTimesConstant() const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
};
//! Unary operator node
......@@ -1312,6 +1321,8 @@ public:
[[nodiscard]] bool isParamTimesEndogExpr() const override;
void decomposeAdditiveTerms(vector<pair<expr_t, int>>& terms, int current_sign) const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
};
//! Binary operator node
......@@ -1507,7 +1518,11 @@ public:
vector<int>& powers) const override;
[[nodiscard]] pair<int, expr_t> matchEndogenousTimesConstant() const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] tuple<int, expr_t, expr_t> matchComplementarityCondition() const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
[[nodiscard]] tuple<int, expr_t, expr_t>
matchComplementarityCondition(const optional<int>& heterogeneity_dimension
= nullopt) const override;
};
//! Trinary operator node
......@@ -1651,6 +1666,8 @@ public:
[[nodiscard]] bool containsPacTargetNonstationary(const string& pac_model_name
= "") const override;
[[nodiscard]] bool isParamTimesEndogExpr() const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
};
......@@ -1826,6 +1843,8 @@ public:
= "") const override;
[[nodiscard]] bool isParamTimesEndogExpr() const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
};
class ExternalFunctionNode : public AbstractExternalFunctionNode
......@@ -2028,6 +2047,8 @@ public:
expr_t detrend(int symb_id, bool log_trend, expr_t trend) const override;
[[nodiscard]] expr_t removeTrendLeadLag(const map<int, expr_t>& trend_symbols_map) const override;
[[nodiscard]] expr_t substituteLogTransform(int orig_symb_id, int aux_symb_id) const override;
[[nodiscard]] expr_t substituteAggregationOperators(subst_table_t& subst_table,
vector<BinaryOpNode*>& neweqs) const override;
protected:
void prepareForDerivation() override;
......
/*
* Copyright © 2024 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cassert>
#include <utility>
#include "HeterogeneityTable.hh"
#include "SymbolTable.hh"
void
HeterogeneityTable::setSymbolTable(SymbolTable* symbol_table_arg)
{
symbol_table = symbol_table_arg;
}
int
HeterogeneityTable::addDimension(string name)
{
if (name_to_id.contains(name))
throw AlreadyDeclaredDimensionException {move(name)};
int id {static_cast<int>(id_to_name.size())};
name_to_id.emplace(name, id);
id_to_name.push_back(move(name));
return id;
}
bool
HeterogeneityTable::exists(const string& name) const
{
return name_to_id.contains(name);
}
int
HeterogeneityTable::getID(const string& name) const
{
if (auto it = name_to_id.find(name); it != name_to_id.end())
return it->second;
else
throw UnknownDimensionNameException {name};
}
string
HeterogeneityTable::getName(int id) const
{
if (id < 0 || id >= static_cast<int>(id_to_name.size()))
throw UnknownDimensionIDException {id};
else
return id_to_name[id];
}
bool
HeterogeneityTable::empty() const
{
return name_to_id.empty();
}
vector<string>
HeterogeneityTable::getDimensions() const
{
return id_to_name;
}
int
HeterogeneityTable::size() const
{
return static_cast<int>(name_to_id.size());
}
void
HeterogeneityTable::addSummedHeterogeneousEndogenous(int symb_id)
{
assert(symbol_table->getType(symb_id) == SymbolType::heterogeneousEndogenous);
if (summed_het_endo_to_index.contains(symb_id))
throw AlreadyDeclaredSummedHeterogeneousEndogenousException {symb_id};
int index {static_cast<int>(index_to_summed_het_endo.size())};
summed_het_endo_to_index.emplace(symb_id, index);
index_to_summed_het_endo.push_back(symb_id);
}
int
HeterogeneityTable::getSummedHeterogenousEndogenousIndex(int symb_id) const
{
if (auto it = summed_het_endo_to_index.find(symb_id); it != summed_het_endo_to_index.end())
return it->second;
else
throw UnknownSummedHeterogeneousEndogenousException {symb_id};
}
int
HeterogeneityTable::aggregateEndoSize() const
{
return index_to_summed_het_endo.size();
}
void
HeterogeneityTable::writeOutput(ostream& output) const
{
for (size_t id {0}; id < id_to_name.size(); id++)
output << "M_.heterogeneity(" << id + 1 << ").dimension_name = '" << id_to_name[id] << "';"
<< endl;
output << "M_.heterogeneity_aggregates = {" << endl;
for (int symb_id : index_to_summed_het_endo)
output << "'sum', " << symbol_table->getHeterogeneityDimension(symb_id) + 1 << ", "
<< symbol_table->getTypeSpecificID(symb_id) + 1 << ";" << endl;
output << "};" << endl;
}
void
HeterogeneityTable::writeJsonOutput(ostream& output) const
{
assert(!empty());
output << R"("heterogeneity_dimension": [)";
for (bool first_written {false}; const auto& dim : id_to_name)
{
if (exchange(first_written, true))
output << ", ";
output << '"' << dim << '"';
}
output << "]" << endl;
}
/*
* Copyright © 2024 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HETEROGENEITY_TABLE_HH
#define HETEROGENEITY_TABLE_HH
#include <map>
#include <ostream>
#include <string>
#include <vector>
using namespace std;
class SymbolTable; // Forward declaration, to avoid circularity
/*
There is a guarantee that heterogeneity IDs are increasing, i.e. if dimension A is added after
dimension B, then the ID of A is greater than the ID of B.
Moreover, the IDs form a contiguous interval starting at 0.
*/
class HeterogeneityTable
{
private:
// Maps dimension names to IDs
map<string, int> name_to_id;
// Maps dimension IDs to names
vector<string> id_to_name;
SymbolTable* symbol_table {nullptr}; // Cannot be a reference, because of circularity
/* Keeps track of the SUM() operator instances.
Maps a symbol ID that appears inside a SUM() operator into an index in
M_.heterogeneity_aggregates */
map<int, int> summed_het_endo_to_index;
// Maps an index in M_.heterogeneity_aggregates into a symbol ID
vector<int> index_to_summed_het_endo;
public:
void setSymbolTable(SymbolTable* symbol_table_arg);
struct AlreadyDeclaredDimensionException
{
// Dimension name
const string name;
};
struct UnknownDimensionNameException
{
// Dimension name
const string name;
};
struct UnknownDimensionIDException
{
// Dimension ID
const int id;
};
// Returns the dimension ID
int addDimension(string name);
[[nodiscard]] bool exists(const string& name) const;
[[nodiscard]] int getID(const string& name) const;
[[nodiscard]] string getName(int id) const;
[[nodiscard]] bool empty() const;
[[nodiscard]] vector<string> getDimensions() const;
[[nodiscard]] int size() const;
struct AlreadyDeclaredSummedHeterogeneousEndogenousException
{
const int symb_id;
};
struct UnknownSummedHeterogeneousEndogenousException
{
const int symb_id;
};
void addSummedHeterogeneousEndogenous(int symb_id);
[[nodiscard]] int getSummedHeterogenousEndogenousIndex(int symb_id) const;
[[nodiscard]] int aggregateEndoSize() const;
void writeOutput(ostream& output) const;
void writeJsonOutput(ostream& output) const;
};
#endif
/*
* Copyright © 2024-2025 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <iostream>
#include "HeterogeneousModel.hh"
HeterogeneousModel::HeterogeneousModel(SymbolTable& symbol_table_arg,
NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg,
int heterogeneity_dimension_arg) :
ModelTree {symbol_table_arg, num_constants_arg, external_functions_table_arg,
heterogeneity_table_arg, true},
heterogeneity_dimension {heterogeneity_dimension_arg}
{
}
HeterogeneousModel&
HeterogeneousModel::operator=(const HeterogeneousModel& m)
{
ModelTree::operator=(m);
assert(heterogeneity_dimension == m.heterogeneity_dimension);
deriv_id_table = m.deriv_id_table;
inv_deriv_id_table = m.inv_deriv_id_table;
return *this;
}
void
HeterogeneousModel::computeChainRuleJacobian()
{
cerr << "Heterogeneous::computeChainRuleJacobian(): unimplemented" << endl;
exit(EXIT_FAILURE);
}
int
HeterogeneousModel::getBlockJacobianEndoCol([[maybe_unused]] int blk, [[maybe_unused]] int var,
[[maybe_unused]] int lead_lag) const
{
cerr << "Heterogeneous::getBlockJacobianEndoCol(): unimplemented" << endl;
exit(EXIT_FAILURE);
}
int
HeterogeneousModel::getMFS() const
{
cerr << "Heterogeneous::getMFS(): unimplemented" << endl;
exit(EXIT_FAILURE);
}
void
HeterogeneousModel::computeDerivIDs()
{
set<pair<int, int>> dynvars;
for (auto& equation : equations)
{
equation->collectDynamicVariables(SymbolType::heterogeneousEndogenous, dynvars);
equation->collectDynamicVariables(SymbolType::heterogeneousExogenous, dynvars);
equation->collectDynamicVariables(SymbolType::endogenous, dynvars);
equation->collectDynamicVariables(SymbolType::exogenous, dynvars);
equation->collectDynamicVariables(SymbolType::parameter, dynvars);
}
for (const auto& [symb_id, lead_lag] : dynvars)
{
auto type {symbol_table.getType(symb_id)};
if (isHeterogeneous(type))
assert(symbol_table.getHeterogeneityDimension(symb_id) == heterogeneity_dimension);
if (type == SymbolType::heterogeneousEndogenous || type == SymbolType::endogenous)
assert(abs(lead_lag) <= 1);
if (type == SymbolType::heterogeneousExogenous || type == SymbolType::exogenous)
assert(lead_lag == 0);
int deriv_id {static_cast<int>(deriv_id_table.size())};
deriv_id_table.emplace(pair {symb_id, lead_lag}, deriv_id);
inv_deriv_id_table.emplace_back(symb_id, lead_lag);
}
}
void
HeterogeneousModel::computingPass(int derivsOrder, bool no_tmp_terms, bool use_dll)
{
assert(!use_dll); // Not yet implemented
computeDerivIDs();
set<int> vars;
for (auto& [symb_lag, deriv_id] : deriv_id_table)
if (symbol_table.getType(symb_lag.first) != SymbolType::parameter)
vars.insert(deriv_id);
cout << "Computing " << modelClassName() << " derivatives (order " << derivsOrder << ")." << endl;
computeDerivatives(derivsOrder, vars);
computeTemporaryTerms(!use_dll, no_tmp_terms);
computeMCPEquationsReordering(heterogeneity_dimension);
}
void
HeterogeneousModel::writeModelFiles(const string& basename, bool julia) const
{
assert(!julia); // Not yet implemented
writeSparseModelMFiles<true>(basename, heterogeneity_dimension);
writeComplementarityConditionsFile<true>(basename, heterogeneity_dimension);
}
int
HeterogeneousModel::getJacobianCol(int deriv_id, bool sparse) const
{
assert(sparse);
SymbolType type {getTypeByDerivID(deriv_id)};
int tsid {getTypeSpecificIDByDerivID(deriv_id)};
int lag {getLagByDerivID(deriv_id)};
if (type == SymbolType::heterogeneousEndogenous)
return tsid + (lag + 1) * symbol_table.het_endo_nbr(heterogeneity_dimension);
int shift {3 * symbol_table.het_endo_nbr(heterogeneity_dimension)};
if (type == SymbolType::heterogeneousExogenous)
return shift + tsid;
shift += symbol_table.het_exo_nbr(heterogeneity_dimension);
if (type == SymbolType::endogenous)
return shift + tsid + (lag + 1) * symbol_table.endo_nbr();
shift += symbol_table.endo_nbr();
if (type == SymbolType::exogenous)
return shift + tsid;
throw UnknownDerivIDException();
}
int
HeterogeneousModel::getJacobianColsNbr(bool sparse) const
{
assert(sparse);
return 3 * (symbol_table.het_endo_nbr(heterogeneity_dimension) + symbol_table.endo_nbr())
+ symbol_table.het_exo_nbr(heterogeneity_dimension) + symbol_table.exo_nbr();
}
SymbolType
HeterogeneousModel::getTypeByDerivID(int deriv_id) const noexcept(false)
{
return symbol_table.getType(getSymbIDByDerivID(deriv_id));
}
int
HeterogeneousModel::getLagByDerivID(int deriv_id) const noexcept(false)
{
if (deriv_id < 0 || deriv_id >= static_cast<int>(inv_deriv_id_table.size()))
throw UnknownDerivIDException();
return inv_deriv_id_table[deriv_id].second;
}
int
HeterogeneousModel::getSymbIDByDerivID(int deriv_id) const noexcept(false)
{
if (deriv_id < 0 || deriv_id >= static_cast<int>(inv_deriv_id_table.size()))
throw UnknownDerivIDException();
return inv_deriv_id_table[deriv_id].first;
}
int
HeterogeneousModel::getTypeSpecificIDByDerivID(int deriv_id) const
{
return symbol_table.getTypeSpecificID(getSymbIDByDerivID(deriv_id));
}
int
HeterogeneousModel::getDerivID(int symb_id, int lead_lag) const noexcept(false)
{
if (auto it = deriv_id_table.find({symb_id, lead_lag}); it == deriv_id_table.end())
throw UnknownDerivIDException();
else
return it->second;
}
void
HeterogeneousModel::writeDriverOutput(ostream& output) const
{
std::vector<int> state_var;
for (int endoID = 0; endoID < symbol_table.het_endo_nbr(heterogeneity_dimension); endoID++)
try
{
getDerivID(symbol_table.getID(SymbolType::heterogeneousEndogenous, endoID,
heterogeneity_dimension),
-1);
if (ranges::find(state_var, endoID) == state_var.end())
state_var.push_back(endoID);
}
catch (UnknownDerivIDException& e)
{
}
output << "M_.heterogeneity(" << heterogeneity_dimension + 1 << ").state_var = [";
for (int it : state_var)
output << it + 1 << " ";
output << "];" << endl;
output << "M_.heterogeneity(" << heterogeneity_dimension + 1 << ").dynamic_tmp_nbr = [";
for (const auto& it : temporary_terms_derivatives)
output << it.size() << "; ";
output << "];" << endl;
writeDriverSparseIndicesHelper(
"heterogeneity("s + to_string(heterogeneity_dimension + 1) + ").dynamic", output);
output << "M_.heterogeneity(" << heterogeneity_dimension + 1
<< ").dynamic_mcp_equations_reordering = [";
for (auto i : mcp_equations_reordering)
output << i + 1 << "; ";
output << "];" << endl;
}
/*
* Copyright © 2024 Dynare Team
*
* This file is part of Dynare.
*
* Dynare is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Dynare is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef HETEROGENEOUS_MODEL_HH
#define HETEROGENEOUS_MODEL_HH
#include <string>
#include "ModelTree.hh"
using namespace std;
class HeterogeneousModel : public ModelTree
{
public:
const int heterogeneity_dimension;
HeterogeneousModel(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
HeterogeneityTable& heterogeneity_table_arg, int heterogeneity_dimension_arg);
HeterogeneousModel(const HeterogeneousModel& m) = default;
HeterogeneousModel& operator=(const HeterogeneousModel& m);
void computingPass(int derivsOrder, bool no_tmp_terms, bool use_dll);
void writeModelFiles(const string& basename, bool julia) const;
void writeDriverOutput(ostream& output) const;
[[nodiscard]] int getJacobianCol(int deriv_id, bool sparse) const override;
[[nodiscard]] int getJacobianColsNbr(bool sparse) const override;
#if 0
void substituteEndoLeadGreaterThanTwo();
//! Transforms the model by removing all lags greater or equal than 2 on endos
void substituteEndoLagGreaterThanTwo();
//! Transforms the model by removing all leads on exos
/*! Note that this can create new lags on endos and exos */
void substituteExoLead();
//! Transforms the model by removing all lags on exos
void substituteExoLag();
//! Transforms the model by removing all UnaryOpcode::expectation
void substituteExpectation(bool partial_information_model);
//! Transforms the model by decreasing the lead/lag of predetermined variables in model equations
//! by one
void transformPredeterminedVariables();
//! Substitutes out all model-local variables
void substituteModelLocalVariables();
#endif
// FIXME: the following 5 functions are identical to those in DynamicModel. Factorization?
[[nodiscard]] int getDerivID(int symb_id, int lead_lag) const noexcept(false) override;
[[nodiscard]] SymbolType getTypeByDerivID(int deriv_id) const noexcept(false) override;
[[nodiscard]] int getLagByDerivID(int deriv_id) const noexcept(false) override;
[[nodiscard]] int getSymbIDByDerivID(int deriv_id) const noexcept(false) override;
[[nodiscard]] int getTypeSpecificIDByDerivID(int deriv_id) const override;
protected:
void computeChainRuleJacobian() override;
int getBlockJacobianEndoCol(int blk, int var, int lead_lag) const override;
string
modelClassName() const override
{
return "dynamic model for heterogeneity dimension '"
+ heterogeneity_table.getName(heterogeneity_dimension) + "'";
}
int getMFS() const override;
private:
// Maps a pair (symbol ID, lead/lag) to a deriv ID
map<pair<int, int>, int> deriv_id_table;
// Maps a deriv ID to a pair (symbol ID, lead/lag)
vector<pair<int, int>> inv_deriv_id_table;
// Allocates the derivation IDs for all endogenous variables for this heterogeneity dimension
void computeDerivIDs();
};
#endif