Skip to content
Snippets Groups Projects

Compare revisions

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

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • normann/preprocessor
  • Dynare/preprocessor
  • FerhatMihoubi/preprocessor
  • MichelJuillard/preprocessor
  • sebastien/preprocessor
  • lnsongxf/preprocessor
  • albop/preprocessor
  • DoraK/preprocessor
  • amg/preprocessor
  • wmutschl/preprocessor
  • JohannesPfeifer/preprocessor
11 results
Select Git revision
Show changes
Showing
with 9544 additions and 11546 deletions
# ===========================================================================
# http://www.nongnu.org/autoconf-archive/ax_latex_test.html
# ===========================================================================
#
# OBSOLETE MACRO
#
# Deprecated because of licensing issues. The Lesser GPL imposes licensing
# restrictions on the generated configure script unless it is augmented
# with an Autoconf Exception clause.
#
# SYNOPSIS
#
# AX_LATEX_TEST(FILEDATA,VARIABLETOSET,[NOCLEAN])
#
# DESCRIPTION
#
# This macros execute the latex application with FILEDATA as input and set
# VARIABLETOSET the yes or no depending of the result if NOCLEAN is set,
# the folder used for the test is not delete after testing.
#
# The macro assumes that the variable PDFLATEX is set.
#
# LICENSE
#
# Copyright © 2008 Boretti Mathieu <boretti@eig.unige.ch>
# Copyright © 2009 Dynare Team
#
# This library is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or (at
# your option) any later version.
#
# This library 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 Lesser
# General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this library. If not, see <http://www.gnu.org/licenses/>.
AC_DEFUN([AX_LATEX_TEST],[
rm -rf conftest.dir/.acltx
AS_MKDIR_P([conftest.dir/.acltx])
cd conftest.dir/.acltx
m4_ifval([$2],[$2="no"; export $2;])
cat > conftest.tex << ACLEOF
$1
ACLEOF
cat conftest.tex | $PDFLATEX 2>&1 1>output m4_ifval([$2],[&& $2=yes])
cd ..
cd ..
sed 's/^/| /' conftest.dir/.acltx/conftest.tex >&5
echo "$as_me:$LINENO: executing cat conftest.tex | $PDFLATEX" >&5
sed 's/^/| /' conftest.dir/.acltx/output >&5
m4_ifval([$3],,[rm -rf conftest.dir/.acltx])
])
# Meson file for building the preprocessor in a standalone fashion.
# It is not used when building Dynare as a whole.
project('dynare-preprocessor', 'cpp',
version : '7-unstable',
# NB: update C++ standard in .clang-format whenever the following is modified
default_options : [ 'cpp_std=gnu++20', 'warning_level=2' ],
meson_version : '>=0.64.0')
add_global_arguments('-DPACKAGE_VERSION="' + meson.project_version() + '"', language : 'cpp')
if get_option('warning_level').to_int() >= 2
add_global_arguments('-Wold-style-cast', language : 'cpp')
endif
cpp_compiler = meson.get_compiler('cpp')
subdir('src')
subdir('doc')
# Meson native file for compiling under Homebrew / arm64
[binaries]
cpp = '/opt/homebrew/bin/g++-15'
flex = '/opt/homebrew/opt/flex/bin/flex'
bison = '/opt/homebrew/opt/bison/bin/bison'
[built-in options]
# XCode 15 (on Ventura and Sonoma) has a linker issue, see https://github.com/mesonbuild/meson/issues/12282, workaround is to use ld_classic
cpp_link_args = [ '-Wl,-ld_classic' ]
\ No newline at end of file
# Meson native file for compiling under Homebrew / x86-64
[binaries]
cpp = '/usr/local/bin/g++-15'
flex = '/usr/local/opt/flex/bin/flex'
bison = '/usr/local/opt/bison/bin/bison'
[built-in options]
# XCode 15 (on Ventura and Sonoma) has a linker issue, see https://github.com/mesonbuild/meson/issues/12282, workaround is to use ld_classic
cpp_link_args = [ '-Wl,-ld_classic' ]
\ No newline at end of file
# Meson cross file for targeting Linux arm64
[binaries]
cpp = 'aarch64-linux-gnu-g++'
strip = 'aarch64-linux-gnu-strip'
[host_machine]
system = 'linux'
cpu_family = 'aarch64'
cpu = 'aarch64'
endian = 'little'
# 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'
# Meson cross file for targeting Windows from Linux
# NB: The boost_root property must be set, possibly through a second cross file
[binaries]
cpp = 'x86_64-w64-mingw32-g++-posix'
strip = 'x86_64-w64-mingw32-strip'
[host_machine]
system = 'windows'
cpu_family = 'x86_64'
cpu = 'x86_64'
endian = 'little'
[built-in options]
prefer_static = true
# See the comments in the main Dynare Meson cross-file
cpp_args = [ '-fstack-protector', '-march=nocona', '-msahf', '-mtune=generic' ]
cpp_link_args = [ '-fstack-protector' ]
#[properties]
#boost_root = '/home/sebastien/dynare/unstable/preprocessor/deps/mingw64/'
/*
* Copyright © 2022-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 <algorithm>
#include <cstdlib>
#include <ios>
#include <iostream>
#include "Bytecode.hh"
namespace Bytecode
{
Writer::Writer(const filesystem::path& filename)
{
open(filename, ios::out | ios::binary);
if (!is_open())
{
cerr << R"(Error : Can't open file ")" << filename.string() << R"(" for writing)" << endl;
exit(EXIT_FAILURE);
}
}
template<>
Writer&
operator<<(Writer& code_file, const FCALL& instr)
{
code_file.instructions_positions.push_back(code_file.tellp());
auto write_member = [&code_file](const auto& member) {
code_file.write(reinterpret_cast<const char*>(&member), sizeof member);
};
write_member(instr.tag);
write_member(instr.nb_output_arguments);
write_member(instr.nb_input_arguments);
write_member(instr.indx);
write_member(instr.add_input_arguments);
write_member(instr.row);
write_member(instr.col);
write_member(instr.call_type);
int size = static_cast<int>(instr.func_name.size());
write_member(size);
code_file.write(instr.func_name.c_str(), size + 1);
size = static_cast<int>(instr.arg_func_name.size());
write_member(size);
code_file.write(instr.arg_func_name.c_str(), size + 1);
return code_file;
}
template<>
Writer&
operator<<(Writer& code_file, const FBEGINBLOCK& instr)
{
code_file.instructions_positions.push_back(code_file.tellp());
auto write_member = [&code_file](const auto& member) {
code_file.write(reinterpret_cast<const char*>(&member), sizeof member);
};
write_member(instr.tag);
write_member(instr.size);
write_member(instr.type);
for (int i = 0; i < instr.size; i++)
{
write_member(instr.variables[i]);
write_member(instr.equations[i]);
}
if (instr.type == BlockSimulationType::solveTwoBoundariesSimple
|| instr.type == BlockSimulationType::solveTwoBoundariesComplete
|| instr.type == BlockSimulationType::solveBackwardComplete
|| instr.type == BlockSimulationType::solveForwardComplete)
{
write_member(instr.is_linear);
write_member(instr.u_count_int);
}
write_member(instr.nb_col_jacob);
write_member(instr.det_exo_size);
write_member(instr.exo_size);
ranges::for_each_n(instr.det_exogenous.begin(), instr.det_exo_size, write_member);
ranges::for_each_n(instr.exogenous.begin(), instr.exo_size, write_member);
return code_file;
}
}
/*
* Copyright © 2007-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 BYTECODE_HH
#define BYTECODE_HH
#include <concepts>
#include <filesystem>
#include <fstream>
#include <ios>
#include <type_traits>
#include <utility>
#include <vector>
#include "CommonEnums.hh"
using namespace std;
namespace Bytecode
{
// The different tags encoding a bytecode instruction
enum class Tag
{
FLDZ, // Loads a zero onto the stack
FLDC, // Loads a constant term onto the stack
FDIMT, // Defines the number of temporary terms - dynamic context (the period has to be indicated)
FDIMST, // Defines the number of temporary terms - static context (the period hasn’t to be
// indicated)
FLDT, // Loads a temporary term onto the stack - dynamic context (the period has to be indicated)
FLDST, // Loads a temporary term onto the stack - static context (the period hasn’t to be
// indicated)
FSTPT, // Stores a temporary term from the stack - dynamic context (the period has to be
// indicated)
FSTPST, // Stores a temporary term from the stack - static context (the period hasn’t to be
// indicated)
FLDU, // Loads an element of the vector U onto the stack - dynamic context (the period has to be
// indicated)
FLDSU, // Loads an element of the vector U onto the stack - static context (the period hasn’t to
// be indicated)
FSTPU, // Stores an element of the vector U from the stack - dynamic context (the period has to be
// indicated)
FSTPSU, // Stores an element of the vector U from the stack - static context (the period hasn’t to
// be indicated)
FLDV, // Loads a variable (described in SymbolType) onto the stack - dynamic context (the period
// has to be indicated)
FLDSV, // Loads a variable (described in SymbolType) onto the stack - static context (the period
// hasn’t to be indicated)
FLDVS, // Loads a variable (described in SymbolType) onto the stack - dynamic context but inside
// the STEADY_STATE operator (the period hasn’t to be indicated)
FSTPV, // Stores a variable (described in SymbolType) from the stack - dynamic context (the period
// has to be indicated)
FSTPSV, // Stores a variable (described in SymbolType) from the stack - static context (the period
// hasn’t to be indicated)
FLDR, // Loads a residual onto the stack
FSTPR, // Stores a residual from the stack
FSTPG, // Stores the derivative of a simple (single-equation) block in simulate mode
FSTPG2, // Stores the derivative matrix of a block in evaluate mode
FUNARY, // A unary operator
FBINARY, // A binary operator
FTRINARY, // A trinary operator
FJMPIFEVAL, // Jump if evaluate = true
FJMP, // Jump
FBEGINBLOCK, // Marks the beginning of a model block
FENDBLOCK, // Marks the end of a model block
FENDEQU, // Marks the last equation of the block; for a block that has to be solved, the
// derivatives appear just after this flag
FEND, // Marks the end of the model code
FNUMEXPR, // Stores the expression type and references
FCALL, // Call an external function
FLDTEF, // Loads the result of an external function onto the stack
FSTPTEF, // Stores the result of an external function from the stack
FLDTEFD, // Loads the result of the 1st derivative of an external function onto the stack
FSTPTEFD, // Stores the result of the 1st derivative of an external function from the stack
FLDTEFDD, // Loads the result of the 2nd derivative of an external function onto the stack
FSTPTEFDD // Stores the result of the 2nd derivative of an external function from the stack
};
enum class ExpressionType
{
TemporaryTerm,
ModelEquation,
FirstEndoDerivative,
FirstExoDerivative,
FirstExodetDerivative,
};
enum class ExternalFunctionCallType
{
levelWithoutDerivative,
levelWithFirstDerivative,
levelWithFirstAndSecondDerivative,
separatelyProvidedFirstDerivative,
numericalFirstDerivative,
separatelyProvidedSecondDerivative,
numericalSecondDerivative
};
class Writer;
struct Instruction
{
const Tag tag;
explicit Instruction(Tag tag_arg) : tag {tag_arg}
{
}
protected:
/* This is a base class, so the destructor should be either public+virtual or
protected+non-virtual. We opt for the latter, because otherwise this class
would no longer be POD; its memory representation would also include
runtime type information, and our crude serialization technique (copying the
whole object from memory) would thus not work. */
~Instruction() = default;
};
template<typename T>
concept IsInstruction = derived_from<T, Instruction>;
struct FLDZ final : public Instruction
{
FLDZ() : Instruction {Tag::FLDZ}
{
}
};
struct FEND final : public Instruction
{
FEND() : Instruction {Tag::FEND}
{
}
};
struct FENDBLOCK final : public Instruction
{
FENDBLOCK() : Instruction {Tag::FENDBLOCK}
{
}
};
struct FENDEQU final : public Instruction
{
FENDEQU() : Instruction {Tag::FENDEQU}
{
}
};
struct FDIMT final : public Instruction
{
const int size;
explicit FDIMT(int size_arg) : Instruction {Tag::FDIMT}, size {size_arg}
{
}
};
struct FDIMST final : public Instruction
{
const int size;
explicit FDIMST(int size_arg) : Instruction {Tag::FDIMST}, size {size_arg}
{
}
};
struct FLDC final : public Instruction
{
const double value;
explicit FLDC(double value_arg) : Instruction {Tag::FLDC}, value {value_arg}
{
}
};
struct FLDU final : public Instruction
{
const int pos;
explicit FLDU(int pos_arg) : Instruction {Tag::FLDU}, pos {pos_arg}
{
}
};
struct FLDSU final : public Instruction
{
const int pos;
explicit FLDSU(int pos_arg) : Instruction {Tag::FLDSU}, pos {pos_arg}
{
}
};
struct FLDR final : public Instruction
{
const int pos;
explicit FLDR(int pos_arg) : Instruction {Tag::FLDR}, pos {pos_arg}
{
}
};
struct FLDT final : public Instruction
{
const int pos;
explicit FLDT(int pos_arg) : Instruction {Tag::FLDT}, pos {pos_arg}
{
}
};
struct FLDST final : public Instruction
{
const int pos;
explicit FLDST(int pos_arg) : Instruction {Tag::FLDST}, pos {pos_arg}
{
}
};
struct FSTPT final : public Instruction
{
const int pos;
explicit FSTPT(int pos_arg) : Instruction {Tag::FSTPT}, pos {pos_arg}
{
}
};
struct FSTPST final : public Instruction
{
const int pos;
explicit FSTPST(int pos_arg) : Instruction {Tag::FSTPST}, pos {pos_arg}
{
}
};
struct FSTPR final : public Instruction
{
const int pos;
explicit FSTPR(int pos_arg) : Instruction {Tag::FSTPR}, pos {pos_arg}
{
}
};
struct FSTPU final : public Instruction
{
const int pos;
explicit FSTPU(int pos_arg) : Instruction {Tag::FSTPU}, pos {pos_arg}
{
}
};
struct FSTPSU final : public Instruction
{
const int pos;
explicit FSTPSU(int pos_arg) : Instruction {Tag::FSTPSU}, pos {pos_arg}
{
}
};
struct FSTPG final : public Instruction
{
explicit FSTPG() : Instruction {Tag::FSTPG}
{
}
};
struct FSTPG2 final : public Instruction
{
const int row, col;
FSTPG2(int row_arg, int col_arg) : Instruction {Tag::FSTPG2}, row {row_arg}, col {col_arg}
{
}
};
struct FUNARY final : public Instruction
{
const UnaryOpcode op_code;
explicit FUNARY(UnaryOpcode op_code_arg) : Instruction {Tag::FUNARY}, op_code {op_code_arg}
{
}
};
struct FBINARY final : public Instruction
{
const BinaryOpcode op_code;
explicit FBINARY(BinaryOpcode op_code_arg) : Instruction {Tag::FBINARY}, op_code {op_code_arg}
{
}
};
struct FTRINARY final : public Instruction
{
const TrinaryOpcode op_code;
explicit FTRINARY(TrinaryOpcode op_code_arg) : Instruction {Tag::FTRINARY}, op_code {op_code_arg}
{
}
};
struct FJMPIFEVAL final : public Instruction
{
const int pos;
explicit FJMPIFEVAL(int pos_arg) : Instruction {Tag::FJMPIFEVAL}, pos {pos_arg}
{
}
};
struct FJMP final : public Instruction
{
const int pos;
explicit FJMP(int pos_arg) : Instruction {Tag::FJMP}, pos {pos_arg}
{
}
};
struct FLDTEF final : public Instruction
{
const int number;
explicit FLDTEF(int number_arg) : Instruction {Tag::FLDTEF}, number {number_arg}
{
}
};
struct FSTPTEF final : public Instruction
{
const int number;
explicit FSTPTEF(int number_arg) : Instruction {Tag::FSTPTEF}, number {number_arg}
{
}
};
struct FLDTEFD final : public Instruction
{
const int indx, row;
FLDTEFD(int indx_arg, int row_arg) : Instruction {Tag::FLDTEFD}, indx {indx_arg}, row {row_arg}
{
}
};
struct FSTPTEFD final : public Instruction
{
const int indx, row;
FSTPTEFD(int indx_arg, int row_arg) : Instruction {Tag::FSTPTEFD}, indx {indx_arg}, row {row_arg}
{
}
};
struct FLDTEFDD final : public Instruction
{
const int indx, row, col;
FLDTEFDD(int indx_arg, int row_arg, int col_arg) :
Instruction {Tag::FLDTEFDD}, indx {indx_arg}, row {row_arg}, col {col_arg}
{
}
};
struct FSTPTEFDD final : public Instruction
{
const int indx, row, col;
FSTPTEFDD(int indx_arg, int row_arg, int col_arg) :
Instruction {Tag::FSTPTEF}, indx {indx_arg}, row {row_arg}, col {col_arg}
{
}
};
struct FLDVS final : public Instruction
{
const SymbolType type;
const int pos;
FLDVS(SymbolType type_arg, int pos_arg) : Instruction {Tag::FLDVS}, type {type_arg}, pos {pos_arg}
{
}
};
struct FLDSV final : public Instruction
{
const SymbolType type;
const int pos;
FLDSV(SymbolType type_arg, int pos_arg) : Instruction {Tag::FLDSV}, type {type_arg}, pos {pos_arg}
{
}
};
struct FSTPSV final : public Instruction
{
const SymbolType type;
const int pos;
FSTPSV(SymbolType type_arg, int pos_arg) :
Instruction {Tag::FSTPSV}, type {type_arg}, pos {pos_arg}
{
}
};
struct FLDV final : public Instruction
{
const SymbolType type;
const int pos, lead_lag;
FLDV(SymbolType type_arg, int pos_arg, int lead_lag_arg) :
Instruction {Tag::FLDV}, type {type_arg}, pos {pos_arg}, lead_lag {lead_lag_arg}
{
}
};
struct FSTPV final : public Instruction
{
const SymbolType type;
const int pos, lead_lag;
FSTPV(SymbolType type_arg, int pos_arg, int lead_lag_arg) :
Instruction {Tag::FSTPV}, type {type_arg}, pos {pos_arg}, lead_lag {lead_lag_arg}
{
}
};
class FCALL final : public Instruction
{
template<IsInstruction B>
friend Writer& operator<<(Writer& code_file, const B& instr);
private:
int nb_output_arguments, nb_input_arguments, indx;
string func_name;
string arg_func_name;
int add_input_arguments {0}, row {0}, col {0};
ExternalFunctionCallType call_type;
public:
FCALL(int nb_output_arguments_arg, int nb_input_arguments_arg, string func_name_arg, int indx_arg,
ExternalFunctionCallType call_type_arg) :
Instruction {Tag::FCALL},
nb_output_arguments {nb_output_arguments_arg},
nb_input_arguments {nb_input_arguments_arg},
indx {indx_arg},
func_name {move(func_name_arg)},
call_type {call_type_arg}
{
}
/* Deserializing constructor.
Updates the code pointer to point beyond the bytes read. */
FCALL(char*& code) : Instruction {Tag::FCALL}
{
code += sizeof(tag);
auto read_member = [&code](auto& member) {
member = *reinterpret_cast<add_pointer_t<decltype(member)>>(code);
code += sizeof member;
};
read_member(nb_output_arguments);
read_member(nb_input_arguments);
read_member(indx);
read_member(add_input_arguments);
read_member(row);
read_member(col);
read_member(call_type);
int size;
read_member(size);
func_name = code;
code += size + 1;
read_member(size);
arg_func_name = code;
code += size + 1;
}
string
get_function_name()
{
// printf("get_function_name => func_name=%s\n",func_name.c_str());fflush(stdout);
return func_name;
}
int
get_nb_output_arguments()
{
return nb_output_arguments;
}
int
get_nb_input_arguments()
{
return nb_input_arguments;
}
int
get_indx()
{
return indx;
}
void
set_arg_func_name(string arg_arg_func_name)
{
arg_func_name = move(arg_arg_func_name);
}
string
get_arg_func_name()
{
return arg_func_name;
}
void
set_nb_add_input_arguments(int arg_add_input_arguments)
{
add_input_arguments = arg_add_input_arguments;
}
int
get_nb_add_input_arguments()
{
return add_input_arguments;
}
void
set_row(int arg_row)
{
row = arg_row;
}
int
get_row()
{
return row;
}
void
set_col(int arg_col)
{
col = arg_col;
}
int
get_col()
{
return col;
}
ExternalFunctionCallType
get_call_type()
{
return call_type;
}
};
class FNUMEXPR final : public Instruction
{
private:
ExpressionType expression_type;
int equation; // Equation number (non-block-specific) (or temporary term number for
// ExpressionType::TemporaryTerm)
int dvariable1; // For derivatives, type-specific ID of the derivation variable
int lag1; // For derivatives, lead/lag of the derivation variable
public:
FNUMEXPR(const ExpressionType expression_type_arg, int equation_arg) :
Instruction {Tag::FNUMEXPR},
expression_type {expression_type_arg},
equation {equation_arg},
dvariable1 {0},
lag1 {0}
{
}
FNUMEXPR(const ExpressionType expression_type_arg, int equation_arg, int dvariable1_arg) :
Instruction {Tag::FNUMEXPR},
expression_type {expression_type_arg},
equation {equation_arg},
dvariable1 {dvariable1_arg},
lag1 {0}
{
}
FNUMEXPR(const ExpressionType expression_type_arg, int equation_arg, int dvariable1_arg,
int lag1_arg) :
Instruction {Tag::FNUMEXPR},
expression_type {expression_type_arg},
equation {equation_arg},
dvariable1 {dvariable1_arg},
lag1 {lag1_arg}
{
}
ExpressionType
get_expression_type()
{
return expression_type;
}
int
get_equation()
{
return equation;
}
int
get_dvariable1()
{
return dvariable1;
}
int
get_lag1()
{
return lag1;
}
};
class FBEGINBLOCK final : public Instruction
{
template<IsInstruction B>
friend Writer& operator<<(Writer& code_file, const B& instr);
private:
int size {0};
BlockSimulationType type;
vector<int> variables;
vector<int> equations;
vector<int> exogenous;
vector<int> det_exogenous;
bool is_linear {false};
int u_count_int {0};
int nb_col_jacob {0};
int det_exo_size, exo_size;
public:
/* Constructor when derivatives w.r.t. exogenous are present (only makes
sense when there is no block-decomposition, since there is no provision for
derivatives w.r.t. endogenous not belonging to the block) */
FBEGINBLOCK(int size_arg, BlockSimulationType type_arg, int first_element, int block_size,
const vector<int>& variables_arg, const vector<int>& equations_arg,
bool is_linear_arg, int u_count_int_arg, int nb_col_jacob_arg, int det_exo_size_arg,
int exo_size_arg, vector<int> det_exogenous_arg, vector<int> exogenous_arg) :
Instruction {Tag::FBEGINBLOCK},
size {size_arg},
type {type_arg},
variables {variables_arg.begin() + first_element,
variables_arg.begin() + (first_element + block_size)},
equations {equations_arg.begin() + first_element,
equations_arg.begin() + (first_element + block_size)},
exogenous {move(exogenous_arg)},
det_exogenous {move(det_exogenous_arg)},
is_linear {is_linear_arg},
u_count_int {u_count_int_arg},
nb_col_jacob {nb_col_jacob_arg},
det_exo_size {det_exo_size_arg},
exo_size {exo_size_arg}
{
}
// Constructor when derivatives w.r.t. exogenous are absent
FBEGINBLOCK(int size_arg, BlockSimulationType type_arg, int first_element, int block_size,
const vector<int>& variables_arg, const vector<int>& equations_arg,
bool is_linear_arg, int u_count_int_arg, int nb_col_jacob_arg) :
Instruction {Tag::FBEGINBLOCK},
size {size_arg},
type {type_arg},
variables {variables_arg.begin() + first_element,
variables_arg.begin() + (first_element + block_size)},
equations {equations_arg.begin() + first_element,
equations_arg.begin() + (first_element + block_size)},
is_linear {is_linear_arg},
u_count_int {u_count_int_arg},
nb_col_jacob {nb_col_jacob_arg},
det_exo_size {0},
exo_size {0}
{
}
/* Deserializing constructor.
Updates the code pointer to point beyond the bytes read. */
FBEGINBLOCK(char*& code) : Instruction {Tag::FBEGINBLOCK}
{
code += sizeof(tag);
auto read_member = [&code](auto& member) {
member = *reinterpret_cast<add_pointer_t<decltype(member)>>(code);
code += sizeof member;
};
read_member(size);
read_member(type);
variables.resize(size);
equations.resize(size);
for (int i {0}; i < size; i++)
{
read_member(variables[i]);
read_member(equations[i]);
}
if (type == BlockSimulationType::solveTwoBoundariesSimple
|| type == BlockSimulationType::solveTwoBoundariesComplete
|| type == BlockSimulationType::solveBackwardComplete
|| type == BlockSimulationType::solveForwardComplete)
{
read_member(is_linear);
read_member(u_count_int);
}
read_member(nb_col_jacob);
read_member(det_exo_size);
read_member(exo_size);
for (int i {0}; i < det_exo_size; i++)
{
int tmp_i;
read_member(tmp_i);
det_exogenous.push_back(tmp_i);
}
for (int i {0}; i < exo_size; i++)
{
int tmp_i;
read_member(tmp_i);
exogenous.push_back(tmp_i);
}
}
int
get_size()
{
return size;
}
BlockSimulationType
get_type()
{
return type;
}
bool
get_is_linear()
{
return is_linear;
}
int
get_u_count_int()
{
return u_count_int;
}
vector<int>
get_variables()
{
return variables;
}
vector<int>
get_equations()
{
return equations;
}
int
get_nb_col_jacob()
{
return nb_col_jacob;
}
int
get_exo_size()
{
return exo_size;
}
int
get_det_exo_size()
{
return det_exo_size;
}
vector<int>
get_exogenous()
{
return exogenous;
}
};
// Superclass of std::ofstream for writing a sequence of bytecode instructions
class Writer : private ofstream
{
template<IsInstruction B>
friend Writer& operator<<(Writer& code_file, const B& instr);
private:
// Stores the positions of all instructions in the byte stream
vector<pos_type> instructions_positions;
public:
Writer(const filesystem::path& filename);
// Returns the number of the next instruction to be written
int
getInstructionCounter() const
{
return static_cast<int>(instructions_positions.size());
}
/* Overwrites an existing instruction, given its number.
It is the responsibility of the caller to ensure that the new instruction
occupies exactly as many bytes as the former one. */
void
overwriteInstruction(int instruction_number, const IsInstruction auto& new_instruction)
{
seekp(instructions_positions.at(instruction_number));
*this << new_instruction;
instructions_positions.pop_back();
seekp(0, ios_base::end);
}
};
// Overloads of operator<< for writing bytecode instructions
template<IsInstruction B>
Writer&
operator<<(Writer& code_file, const B& instr)
{
code_file.instructions_positions.push_back(code_file.tellp());
code_file.write(reinterpret_cast<const char*>(&instr), sizeof(B));
return code_file;
}
template<>
Writer& operator<<(Writer& code_file, const FCALL& instr);
template<>
Writer& operator<<(Writer& code_file, const FBEGINBLOCK& instr);
}
#endif
/*
* Copyright © 2007-2018 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CODEINTERPRETER_HH
#define _CODEINTERPRETER_HH
//#define DEBUGL
#include <fstream>
#include <cstring>
#include <utility>
#include <vector>
#ifdef LINBCG
# include "linbcg.hh"
#endif
#ifdef BYTE_CODE
# ifndef DEBUG_EX
# include "mex.h"
# else
# include "mex_interface.hh"
# endif
#endif
using namespace std;
const double near_zero{1e-12};
/**
* \enum Tags
* \brief The differents flags of the bytecode
*/
enum Tags
{
FLDZ, //!< Stores zero in the stack - 0 (0)
FLDC, //!< Stores a constant term in the stack - 1 (1)
FDIMT, //!< Defines the number of temporary terms - dynamic context (the period has to be indicated) - 2 (2)
FDIMST, //!< Defines the number of temporary terms - static context (the period hasn't to be indicated) - 3 (3)
FLDT, //!< Stores a temporary term in the stack - dynamic context (the period has to be indicated) - 4 (4)
FLDST, //!< Stores a temporary term in the stack - static context (the period hasn't to be indicated) - 5 (5)
FSTPT, //!< Loads a temporary term from the stack - dynamic context (the period has to be indicated) - 6 (6)
FSTPST, //!< Loads a temporary term from the stack - static context (the period hasn't to be indicated) - 7 (7)
FLDU, //!< Stores an element of the vector U in the stack - dynamic context (the period has to be indicated) - 8 (8)
FLDSU, //!< Stores an element of the vector U in the stack - static context (the period hasn't to be indicated) - 9 (9)
FSTPU, //!< Loads an element of the vector U from the stack - dynamic context (the period has to be indicated) - A (10)
FSTPSU, //!< Loads an element of the vector U from the stack - static context (the period hasn't to be indicated) - B (11)
FLDV, //!< Stores a variable (described in SymbolType) in the stack - dynamic context (the period has to be indicated) - C (12)
FLDSV, //!< Stores a variable (described in SymbolType) in the stack - static context (the period hasn't to be indicated) - D (13)
FLDVS, //!< Stores a variable (described in SymbolType) in the stack - dynamic context but inside the STEADYSTATE function (the period hasn't to be indicated) - E (14)
FSTPV, //!< Loads a variable (described in SymbolType) from the stack - dynamic context (the period has to be indicated) - F (15)
FSTPSV, //!< Loads a variable (described in SymbolType) from the stack - static context (the period hasn't to be indicated) - 10 (16)
FLDR, //!< Stores a residual in the stack - 11 (17)
FSTPR, //!< Loads a residual from the stack - 12 (18)
FSTPG, //!< Loads a derivative from the stack - 13 (19)
FSTPG2, //!< Loads a derivative matrix for static model from the stack - 14 (20)
FSTPG3, //!< Loads a derivative matrix for a dynamic model from the stack - 15 (21)
FSTPG4, //!< Loads a second order derivative matrix for a dynamic model from the stack - 16 (22)
FUNARY, //!< A Unary operator - 17 (23)
FBINARY, //!< A binary operator - 18 (24)
FTRINARY, //!< A trinary operator - 19 (25)
FCUML, //!< Cumulates the result - 1A (26)
FJMPIFEVAL, //!< Jump if evaluate = true - 1B (27)
FJMP, //!< Jump - 1C (28)
FBEGINBLOCK, //!< Defines the begining of a model block - 1D (29)
FENDBLOCK, //!< Defines the end of a model block - 1E (30)
FENDEQU, //!< Defines the last equation of the block. For block that has to be solved, the derivatives appear just after this flag - 1F (31)
FEND, //!< Defines the end of the model code - 20 (32)
FOK, //!< Used for debugging purpose - 21 (33)
FNUMEXPR, //!< Store the expression type and references - 22 (34)
FCALL, //!< Call an external function - 23 (35)
FPUSH, //!< Push a double in the stack - 24 (36)
FPOP, //!< Pop a double from the stack - 25 (37)
FLDTEF, //!< Stores the result of an external function in the stack - 26 (38)
FSTPTEF, //!< Loads the result of an external function from the stack- 27 (39)
FLDTEFD, //!< Stores the result of an external function in the stack - 28 (40)
FSTPTEFD, //!< Loads the result of an external function from the stack- 29 (41)
FLDTEFDD, //!< Stores the result of an external function in the stack - 28 (42)
FSTPTEFDD //!< Loads the result of an external function from the stack- 29 (43)
};
enum BlockType
{
SIMULTANS, //!< Simultaneous time separable block
PROLOGUE, //!< Prologue block (one equation at the beginning, later merged)
EPILOGUE, //!< Epilogue block (one equation at the beginning, later merged)
SIMULTAN //!< Simultaneous time unseparable block
};
enum EquationType
{
E_UNKNOWN, //!< Unknown equation type
E_EVALUATE, //!< Simple evaluation, normalized variable on left-hand side
E_EVALUATE_S, //!< Simple evaluation, normalize using the first order derivative
E_SOLVE //!< No simple evaluation of the equation, it has to be solved
};
enum BlockSimulationType
{
UNKNOWN, //!< Unknown simulation type
EVALUATE_FORWARD, //!< Simple evaluation, normalized variable on left-hand side, forward
EVALUATE_BACKWARD, //!< Simple evaluation, normalized variable on left-hand side, backward
SOLVE_FORWARD_SIMPLE, //!< Block of one equation, newton solver needed, forward
SOLVE_BACKWARD_SIMPLE, //!< Block of one equation, newton solver needed, backward
SOLVE_TWO_BOUNDARIES_SIMPLE, //!< Block of one equation, newton solver needed, forward & ackward
SOLVE_FORWARD_COMPLETE, //!< Block of several equations, newton solver needed, forward
SOLVE_BACKWARD_COMPLETE, //!< Block of several equations, newton solver needed, backward
SOLVE_TWO_BOUNDARIES_COMPLETE //!< Block of several equations, newton solver needed, forward and backwar
};
//! Enumeration of possible symbol types
/*! Warning: do not to change existing values for 0 to 4: the values matter for homotopy_setup 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
statementDeclaredVariable = 14, //!< Local variable assigned within a Statement (see subsample statement for example)
logTrend = 15, //!< Log-trend variable
unusedEndogenous = 16, //!< Type to mark unused endogenous variables when `nostrict` option is passed
endogenousVAR = 17, //!< Variables declared in a var_model statement
epilogue = 18, //!< Variables created in epilogue block
excludedVariable = 19 //!< Type to use when an equation is excluded via include/exclude_eqs and the LHS variable is not used elsewhere in the model
};
enum ExpressionType
{
TemporaryTerm,
ModelEquation,
FirstEndoDerivative,
FirstOtherEndoDerivative,
FirstExoDerivative,
FirstExodetDerivative,
FirstParamDerivative,
SecondEndoDerivative,
SecondExoDerivative,
SecondExodetDerivative,
SecondParamDerivative,
ThirdEndoDerivative,
ThirdExoDerivative,
ThirdExodetDerivative,
ThirdParamDerivative
};
enum class UnaryOpcode
{
uminus,
exp,
log,
log10,
cos,
sin,
tan,
acos,
asin,
atan,
cosh,
sinh,
tanh,
acosh,
asinh,
atanh,
sqrt,
cbrt,
abs,
sign,
steadyState,
steadyStateParamDeriv, // for the derivative of the STEADY_STATE operator w.r.t. to a parameter
steadyStateParam2ndDeriv, // for the 2nd derivative of the STEADY_STATE operator w.r.t. to a parameter
expectation,
erf,
diff,
adl
};
enum class BinaryOpcode
{
plus,
minus,
times,
divide,
power,
powerDeriv, // for the derivative of the power function (see trac ticket #78)
equal,
max,
min,
less,
greater,
lessEqual,
greaterEqual,
equalEqual,
different
};
enum class TrinaryOpcode
{
normcdf,
normpdf
};
enum class ExternalFunctionType
{
withoutDerivative,
withFirstDerivative,
withFirstAndSecondDerivative,
numericalFirstDerivative,
firstDerivative,
numericalSecondDerivative,
secondDerivative
};
enum class PriorDistributions
{
noShape = 0,
beta = 1,
gamma = 2,
normal = 3,
invGamma = 4,
invGamma1 = 4,
uniform = 5,
invGamma2 = 6,
dirichlet = 7,
weibull = 8
};
struct Block_contain_type
{
int Equation, Variable, Own_Derivative;
};
#pragma pack(push, 1)
class TagWithoutArgument
{
protected:
uint8_t op_code;
public:
inline explicit
TagWithoutArgument(uint8_t op_code_arg) : op_code{op_code_arg}
{
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(*this));
instruction_number++;
};
};
template<typename T1>
class TagWithOneArgument
{
protected:
uint8_t op_code;
T1 arg1;
public:
inline explicit
TagWithOneArgument(uint8_t op_code_arg) : op_code{op_code_arg}
{
};
inline
TagWithOneArgument(uint8_t op_code_arg, T1 arg_arg1) : op_code{op_code_arg}, arg1{arg_arg1}
{
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(TagWithOneArgument));
instruction_number++;
};
};
template<typename T1, typename T2>
class TagWithTwoArguments
{
protected:
uint8_t op_code;
T1 arg1;
T2 arg2;
public:
inline explicit
TagWithTwoArguments(uint8_t op_code_arg) : op_code{op_code_arg}
{
};
inline
TagWithTwoArguments(uint8_t op_code_arg, T1 arg_arg1, T2 arg_arg2) : op_code{op_code_arg}, arg1{arg_arg1}, arg2{arg_arg2}
{
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(*this));
instruction_number++;
};
};
template<typename T1, typename T2, typename T3>
class TagWithThreeArguments
{
protected:
uint8_t op_code;
T1 arg1;
T2 arg2;
T3 arg3;
public:
inline explicit
TagWithThreeArguments(uint8_t op_code_arg) : op_code{op_code_arg}
{
};
inline
TagWithThreeArguments(uint8_t op_code_arg, T1 arg_arg1, T2 arg_arg2, T3 arg_arg3) : op_code{op_code_arg}, arg1{arg_arg1}, arg2{arg_arg2}, arg3{arg_arg3}
{
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(*this));
instruction_number++;
};
};
template<typename T1, typename T2, typename T3, typename T4>
class TagWithFourArguments
{
protected:
uint8_t op_code;
T1 arg1;
T2 arg2;
T3 arg3;
T4 arg4;
public:
inline explicit
TagWithFourArguments(uint8_t op_code_arg) : op_code{op_code_arg}
{
};
inline
TagWithFourArguments(uint8_t op_code_arg, T1 arg_arg1, T2 arg_arg2, T3 arg_arg3, T4 arg_arg4) : op_code{op_code_arg}, arg1{arg_arg1}, arg2{arg_arg2}, arg3{move(arg_arg3)}, arg4{arg_arg4}
{
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(*this));
instruction_number++;
};
};
class FLDZ_ : public TagWithoutArgument
{
public:
inline
FLDZ_() : TagWithoutArgument{FLDZ}
{
};
};
class FEND_ : public TagWithoutArgument
{
public:
inline
FEND_() : TagWithoutArgument{FEND}
{
};
};
class FENDBLOCK_ : public TagWithoutArgument
{
public:
inline
FENDBLOCK_() : TagWithoutArgument{FENDBLOCK}
{
};
};
class FENDEQU_ : public TagWithoutArgument
{
public:
inline
FENDEQU_() : TagWithoutArgument{FENDEQU}
{
};
};
class FCUML_ : public TagWithoutArgument
{
public:
inline
FCUML_() : TagWithoutArgument{FCUML}
{
};
};
class FPUSH_ : public TagWithoutArgument
{
public:
inline
FPUSH_() : TagWithoutArgument{FPUSH}
{
};
};
class FPOP_ : public TagWithoutArgument
{
public:
inline
FPOP_() : TagWithoutArgument{FPOP}
{
};
};
class FDIMT_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FDIMT_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FDIMT}
{
};
inline explicit
FDIMT_(unsigned int size_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FDIMT, size_arg}
{
};
inline unsigned int
get_size()
{
return arg1;
};
};
class FDIMST_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FDIMST_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FDIMST}
{
};
inline explicit
FDIMST_(const unsigned int size_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FDIMST, size_arg}
{
};
inline unsigned int
get_size()
{
return arg1;
};
};
class FLDC_ : public TagWithOneArgument<double>
{
public:
inline
FLDC_() : TagWithOneArgument<double>::TagWithOneArgument{FLDC}
{
};
inline explicit
FLDC_(const double value_arg) : TagWithOneArgument<double>::TagWithOneArgument{FLDC, value_arg}
{
};
inline double
get_value()
{
return arg1;
};
};
class FLDU_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDU_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDU}
{
};
inline explicit
FLDU_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDU, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FLDSU_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDSU_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDSU}
{
};
inline explicit
FLDSU_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDSU, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FLDR_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDR_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDR}
{
};
inline explicit
FLDR_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDR, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FLDT_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDT_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDT}
{
};
inline explicit
FLDT_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDT, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FLDST_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDST_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDST}
{
};
inline explicit
FLDST_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDST, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPT_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPT_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPT}
{
};
inline explicit
FSTPT_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPT, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPST_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPST_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPST}
{
};
inline explicit
FSTPST_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPST, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPR_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPR_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPR}
{
};
inline explicit
FSTPR_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPR, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPU_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPU_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPU}
{
};
inline explicit
FSTPU_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPU, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPSU_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPSU_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPSU}
{
};
inline explicit
FSTPSU_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPSU, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPG_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPG_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPG, 0}
{
};
inline explicit
FSTPG_(const unsigned int pos_arg) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPG, pos_arg}
{
};
inline unsigned int
get_pos()
{
return arg1;
};
};
class FSTPG2_ : public TagWithTwoArguments<unsigned int, unsigned int>
{
public:
inline
FSTPG2_() : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FSTPG2, 0, 0}
{
};
inline
FSTPG2_(const unsigned int pos_arg1, const unsigned int pos_arg2) : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FSTPG2, pos_arg1, pos_arg2}
{
};
inline unsigned int
get_row()
{
return arg1;
};
inline unsigned int
get_col()
{
return arg2;
};
};
class FSTPG3_ : public TagWithFourArguments<unsigned int, unsigned int, int, unsigned int>
{
public:
inline
FSTPG3_() : TagWithFourArguments<unsigned int, unsigned int, int, unsigned int>::TagWithFourArguments{FSTPG3, 0, 0, 0, 0}
{
};
inline
FSTPG3_(const unsigned int pos_arg1, const unsigned int pos_arg2, const int pos_arg3, const unsigned int pos_arg4) : TagWithFourArguments<unsigned int, unsigned int, int, unsigned int>::TagWithFourArguments{FSTPG3, pos_arg1, pos_arg2, pos_arg3, pos_arg4}
{
};
inline unsigned int
get_row()
{
return arg1;
};
inline unsigned int
get_col()
{
return arg2;
};
inline int
get_lag()
{
return arg2;
};
inline unsigned int
get_col_pos()
{
return arg4;
};
};
class FUNARY_ : public TagWithOneArgument<uint8_t>
{
public:
inline
FUNARY_() : TagWithOneArgument<uint8_t>::TagWithOneArgument{FUNARY}
{
};
inline explicit
FUNARY_(uint8_t op_type_arg) : TagWithOneArgument<uint8_t>::TagWithOneArgument{FUNARY, op_type_arg}
{
};
inline uint8_t
get_op_type()
{
return arg1;
};
};
class FBINARY_ : public TagWithOneArgument<uint8_t>
{
public:
inline
FBINARY_() : TagWithOneArgument<uint8_t>::TagWithOneArgument{FBINARY}
{
};
inline explicit
FBINARY_(const int op_type_arg) : TagWithOneArgument<uint8_t>::TagWithOneArgument{FBINARY, static_cast<uint8_t>(op_type_arg)}
{
};
inline uint8_t
get_op_type()
{
return arg1;
};
};
class FTRINARY_ : public TagWithOneArgument<uint8_t>
{
public:
inline
FTRINARY_() : TagWithOneArgument<uint8_t>::TagWithOneArgument{FTRINARY}
{
};
inline explicit
FTRINARY_(const int op_type_arg) : TagWithOneArgument<uint8_t>::TagWithOneArgument{FTRINARY, static_cast<uint8_t>(op_type_arg)}
{
};
inline uint8_t
get_op_type()
{
return arg1;
};
};
class FOK_ : public TagWithOneArgument<int>
{
public:
inline
FOK_() : TagWithOneArgument<int>::TagWithOneArgument{FOK}
{
};
inline explicit
FOK_(const int arg_arg) : TagWithOneArgument<int>::TagWithOneArgument{FOK, arg_arg}
{
};
inline int
get_arg()
{
return arg1;
};
};
class FJMPIFEVAL_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FJMPIFEVAL_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FJMPIFEVAL}
{
};
inline explicit
FJMPIFEVAL_(unsigned int arg_pos) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FJMPIFEVAL, arg_pos}
{
};
inline unsigned int
get_pos()
{
return arg1;
}
};
class FJMP_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FJMP_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FJMP}
{
};
inline explicit
FJMP_(unsigned int arg_pos) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FJMP, arg_pos}
{
};
inline unsigned int
get_pos()
{
return arg1;
}
};
class FLDTEF_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FLDTEF_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDTEF}
{
};
inline explicit
FLDTEF_(unsigned int number) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FLDTEF, number}
{
};
inline unsigned int
get_number()
{
return arg1;
}
};
class FSTPTEF_ : public TagWithOneArgument<unsigned int>
{
public:
inline
FSTPTEF_() : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPTEF}
{
};
inline explicit
FSTPTEF_(unsigned int number) : TagWithOneArgument<unsigned int>::TagWithOneArgument{FSTPTEF, number}
{
};
inline unsigned int
get_number()
{
return arg1;
}
};
class FLDTEFD_ : public TagWithTwoArguments<unsigned int, unsigned int>
{
public:
inline
FLDTEFD_() : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FLDTEFD}
{
};
inline
FLDTEFD_(unsigned int indx, unsigned int row) : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FLDTEFD, indx, row}
{
};
inline unsigned int
get_indx()
{
return arg1;
};
inline unsigned int
get_row()
{
return arg2;
};
};
class FSTPTEFD_ : public TagWithTwoArguments<unsigned int, unsigned int>
{
public:
inline
FSTPTEFD_() : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FSTPTEFD}
{
};
inline
FSTPTEFD_(unsigned int indx, unsigned int row) : TagWithTwoArguments<unsigned int, unsigned int>::TagWithTwoArguments{FSTPTEFD, indx, row}
{
};
inline unsigned int
get_indx()
{
return arg1;
};
inline unsigned int
get_row()
{
return arg2;
};
};
class FLDTEFDD_ : public TagWithThreeArguments<unsigned int, unsigned int, unsigned int>
{
public:
inline
FLDTEFDD_() : TagWithThreeArguments<unsigned int, unsigned int, unsigned int>::TagWithThreeArguments{FLDTEFDD}
{
};
inline
FLDTEFDD_(unsigned int indx, unsigned int row, unsigned int col) : TagWithThreeArguments<unsigned int, unsigned int, unsigned int>::TagWithThreeArguments{FLDTEFDD, indx, row, col}
{
};
inline unsigned int
get_indx()
{
return arg1;
};
inline unsigned int
get_row()
{
return arg2;
};
inline unsigned int
get_col()
{
return arg3;
};
};
class FSTPTEFDD_ : public TagWithThreeArguments<unsigned int, unsigned int, unsigned int>
{
public:
inline
FSTPTEFDD_() : TagWithThreeArguments<unsigned int, unsigned int, unsigned int>::TagWithThreeArguments{FSTPTEFDD}
{
};
inline
FSTPTEFDD_(unsigned int indx, unsigned int row, unsigned int col) : TagWithThreeArguments<unsigned int, unsigned int, unsigned int>::TagWithThreeArguments{FSTPTEF, indx, row, col}
{
};
inline unsigned int
get_indx()
{
return arg1;
};
inline unsigned int
get_row()
{
return arg2;
};
inline unsigned int
get_col()
{
return arg3;
};
};
class FLDVS_ : public TagWithTwoArguments<uint8_t, unsigned int>
{
public:
inline
FLDVS_() : TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FLDVS}
{
};
inline
FLDVS_(uint8_t type_arg, const unsigned int pos_arg) : TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FLDVS, type_arg, pos_arg}
{
};
inline uint8_t
get_type()
{
return arg1;
};
inline unsigned int
get_pos()
{
return arg2;
};
};
class FLDSV_ : public TagWithTwoArguments<uint8_t, unsigned int>
{
public:
inline
FLDSV_() : TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FLDSV}
{
};
inline
FLDSV_(const uint8_t type_arg, const unsigned int pos_arg) :
TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FLDSV, type_arg, pos_arg}
{
};
inline uint8_t
get_type()
{
return arg1;
};
inline unsigned int
get_pos()
{
return arg2;
};
};
class FSTPSV_ : public TagWithTwoArguments<uint8_t, unsigned int>
{
public:
inline
FSTPSV_() : TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FSTPSV}
{
};
inline
FSTPSV_(const uint8_t type_arg, const unsigned int pos_arg) :
TagWithTwoArguments<uint8_t, unsigned int>::TagWithTwoArguments{FSTPSV, type_arg, pos_arg}
{
};
inline uint8_t
get_type()
{
return arg1;
};
inline unsigned int
get_pos()
{
return arg2;
};
};
class FLDV_ : public TagWithThreeArguments<uint8_t, unsigned int, int>
{
public:
inline
FLDV_() : TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FLDV}
{
};
inline
FLDV_(const int type_arg, const unsigned int pos_arg) :
TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FLDV, static_cast<uint8_t>(type_arg), pos_arg, 0}
{
};
inline
FLDV_(const int type_arg, const unsigned int pos_arg, const int lead_lag_arg) :
TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FLDV, static_cast<uint8_t>(type_arg), pos_arg, lead_lag_arg}
{
};
inline uint8_t
get_type()
{
return arg1;
};
inline unsigned int
get_pos()
{
return arg2;
};
inline int
get_lead_lag()
{
return arg3;
};
};
class FSTPV_ : public TagWithThreeArguments<uint8_t, unsigned int, int>
{
public:
inline
FSTPV_() : TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FSTPV}
{
};
inline
FSTPV_(const int type_arg, const unsigned int pos_arg) :
TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FSTPV, static_cast<uint8_t>(type_arg), pos_arg, 0}
{
};
inline
FSTPV_(const int type_arg, const unsigned int pos_arg, const int lead_lag_arg) :
TagWithThreeArguments<uint8_t, unsigned int, int>::TagWithThreeArguments{FSTPV, static_cast<uint8_t>(type_arg), pos_arg, lead_lag_arg}
{
};
inline uint8_t
get_type()
{
return arg1;
};
inline unsigned int
get_pos()
{
return arg2;
};
inline int
get_lead_lag()
{
return arg3;
};
};
class FCALL_ : public TagWithFourArguments<unsigned int, unsigned int, string, unsigned int>
{
string func_name;
string arg_func_name;
unsigned int add_input_arguments, row, col;
ExternalFunctionType function_type;
public:
inline
FCALL_() : TagWithFourArguments<unsigned int, unsigned int, string, unsigned int>::TagWithFourArguments{FCALL}
{
arg_func_name = "";
add_input_arguments = 0;
row = 0;
col = 0;
function_type = ExternalFunctionType::withoutDerivative;
};
inline
FCALL_(unsigned int nb_output_arguments, unsigned int nb_input_arguments, string f_name, unsigned int indx) :
TagWithFourArguments<unsigned int, unsigned int, string, unsigned int>::TagWithFourArguments{FCALL, nb_output_arguments, nb_input_arguments, f_name, indx}
{
arg_func_name = "";
add_input_arguments = 0;
row = 0;
col = 0;
function_type = ExternalFunctionType::withoutDerivative;
func_name = f_name;
};
inline string
get_function_name()
{
//printf("get_function_name => func_name=%s\n",func_name.c_str());fflush(stdout);
return func_name;
};
inline unsigned int
get_nb_output_arguments()
{
return arg1;
};
inline unsigned int
get_nb_input_arguments()
{
return arg2;
};
inline unsigned int
get_indx()
{
return arg4;
};
inline void
set_arg_func_name(string arg_arg_func_name)
{
arg_func_name = arg_arg_func_name;
};
inline string
get_arg_func_name()
{
return arg_func_name;
};
inline void
set_nb_add_input_arguments(unsigned int arg_add_input_arguments)
{
add_input_arguments = arg_add_input_arguments;
};
inline unsigned int
get_nb_add_input_arguments()
{
return add_input_arguments;
};
inline void
set_row(unsigned int arg_row)
{
row = arg_row;
};
inline unsigned int
get_row()
{
return row;
}
inline void
set_col(unsigned int arg_col)
{
col = arg_col;
};
inline unsigned int
get_col()
{
return col;
};
inline void
set_function_type(ExternalFunctionType arg_function_type)
{
function_type = arg_function_type;
};
inline ExternalFunctionType
get_function_type()
{
return (function_type);
}
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(&op_code), sizeof(op_code));
CompileCode.write(reinterpret_cast<char *>(&arg1), sizeof(arg1));
CompileCode.write(reinterpret_cast<char *>(&arg2), sizeof(arg2));
CompileCode.write(reinterpret_cast<char *>(&arg4), sizeof(arg4));
CompileCode.write(reinterpret_cast<char *>(&add_input_arguments), sizeof(add_input_arguments));
CompileCode.write(reinterpret_cast<char *>(&row), sizeof(row));
CompileCode.write(reinterpret_cast<char *>(&col), sizeof(col));
CompileCode.write(reinterpret_cast<char *>(&function_type), sizeof(function_type));
size_t size = func_name.size();
CompileCode.write(reinterpret_cast<char *>(&size), sizeof(int));
const char *name = func_name.c_str();
CompileCode.write(reinterpret_cast<const char *>(name), func_name.size());
size = arg_func_name.size();
CompileCode.write(reinterpret_cast<char *>(&size), sizeof(int));
name = arg_func_name.c_str();
CompileCode.write(reinterpret_cast<const char *>(name), arg_func_name.size());
instruction_number++;
};
#ifdef BYTE_CODE
inline uint8_t *
load(uint8_t *code)
{
op_code = FCALL; code += sizeof(op_code);
memcpy(&arg1, code, sizeof(arg1)); code += sizeof(arg1);
memcpy(&arg2, code, sizeof(arg2)); code += sizeof(arg2);
memcpy(&arg4, code, sizeof(arg4)); code += sizeof(arg4);
memcpy(&add_input_arguments, code, sizeof(add_input_arguments)); code += sizeof(add_input_arguments);
memcpy(&row, code, sizeof(row)); code += sizeof(row);
memcpy(&col, code, sizeof(col)); code += sizeof(col);
memcpy(&function_type, code, sizeof(function_type)); code += sizeof(function_type);
int size;
memcpy(&size, code, sizeof(size)); code += sizeof(size);
char *name = static_cast<char *>(mxMalloc((size+1)*sizeof(char)));
memcpy(name, code, size); code += size;
name[size] = 0;
func_name = name;
mxFree(name);
memcpy(&size, code, sizeof(size)); code += sizeof(size);
name = static_cast<char *>(mxMalloc((size+1)*sizeof(char)));
memcpy(name, code, size); code += size;
name[size] = 0;
arg_func_name = name;
mxFree(name);
return code;
}
#endif
};
class FNUMEXPR_ : public TagWithOneArgument<ExpressionType>
{
private:
unsigned int equation;
uint16_t dvariable1, dvariable2, dvariable3;
int8_t lag1, lag2, lag3;
public:
inline
FNUMEXPR_() : TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{0}, dvariable2{0}, dvariable3{0},
lag1{0}, lag2{0}, lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)}, dvariable2{0}, dvariable3{0},
lag1{0}, lag2{0}, lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg, int lag1_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)}, dvariable2{0}, dvariable3{0},
lag1{static_cast<int8_t>(lag1_arg)}, lag2{0}, lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg, unsigned int dvariable2_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)},
dvariable2{static_cast<uint16_t>(dvariable2_arg)},
dvariable3{0},
lag1{0}, lag2{0}, lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg, int lag1_arg, unsigned int dvariable2_arg, int lag2_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)},
dvariable2{static_cast<uint16_t>(dvariable2_arg)},
dvariable3{0},
lag1{static_cast<int8_t>(lag1_arg)},
lag2{static_cast<int8_t>(lag2_arg)},
lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg, unsigned int dvariable2_arg, unsigned int dvariable3_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)},
dvariable2{static_cast<uint16_t>(dvariable2_arg)},
dvariable3{static_cast<uint16_t>(dvariable3_arg)},
lag1{0}, lag2{0}, lag3{0}
{
};
inline
FNUMEXPR_(const ExpressionType expression_type, unsigned int equation_arg, unsigned int dvariable1_arg, int lag1_arg, unsigned int dvariable2_arg, int lag2_arg, unsigned int dvariable3_arg, int lag3_arg) :
TagWithOneArgument<ExpressionType>::TagWithOneArgument{FNUMEXPR, expression_type},
equation{equation_arg},
dvariable1{static_cast<uint16_t>(dvariable1_arg)},
dvariable2{static_cast<uint16_t>(dvariable2_arg)},
dvariable3{static_cast<uint16_t>(dvariable3_arg)},
lag1{static_cast<int8_t>(lag1_arg)},
lag2{static_cast<int8_t>(lag2_arg)},
lag3{static_cast<int8_t>(lag3_arg)}
{
};
inline ExpressionType
get_expression_type()
{
return arg1;
}
inline unsigned int
get_equation()
{
return equation;
};
inline unsigned int
get_dvariable1()
{
return dvariable1;
};
inline int
get_lag1()
{
return lag1;
};
inline unsigned int
get_dvariable2()
{
return dvariable2;
};
inline int
get_lag2()
{
return lag2;
};
inline unsigned int
get_dvariable3()
{
return dvariable3;
};
inline int
get_lag3()
{
return lag3;
};
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(this), sizeof(FNUMEXPR_));
instruction_number++;
};
};
class FBEGINBLOCK_
{
private:
uint8_t op_code{FBEGINBLOCK};
int size;
uint8_t type;
vector<int> variable;
vector<int> equation;
vector<unsigned int> other_endogenous;
vector<unsigned int> exogenous;
vector<unsigned int> det_exogenous;
bool is_linear;
vector<Block_contain_type> Block_Contain_;
int endo_nbr;
int Max_Lag;
int Max_Lead;
int u_count_int;
int nb_col_jacob;
unsigned int det_exo_size, exo_size, other_endo_size;
unsigned int nb_col_det_exo_jacob, nb_col_exo_jacob, nb_col_other_endo_jacob;
public:
inline
FBEGINBLOCK_() : size{0}, type{UNKNOWN},
is_linear{false}, endo_nbr{0}, Max_Lag{0}, Max_Lead{0}, u_count_int{0}, nb_col_jacob{0}
{
}
inline
FBEGINBLOCK_(unsigned int size_arg, BlockSimulationType type_arg, int unsigned first_element, int unsigned block_size,
const vector<int> &variable_arg, const vector<int> &equation_arg,
bool is_linear_arg, int endo_nbr_arg, int Max_Lag_arg, int Max_Lead_arg, int &u_count_int_arg, int nb_col_jacob_arg,
unsigned int det_exo_size_arg, unsigned int nb_col_det_exo_jacob_arg, unsigned int exo_size_arg, unsigned int nb_col_exo_jacob_arg, unsigned int other_endo_size_arg, unsigned int nb_col_other_endo_jacob_arg,
const vector<unsigned int> &det_exogenous_arg, const vector<unsigned int> &exogenous_arg, const vector<unsigned int> &other_endogenous_arg) :
size{static_cast<int>(size_arg)},
type{static_cast<uint8_t>(type_arg)},
variable{variable_arg.begin()+first_element, variable_arg.begin()+(first_element+block_size)},
equation{equation_arg.begin()+first_element, equation_arg.begin()+(first_element+block_size)},
other_endogenous{other_endogenous_arg},
exogenous{exogenous_arg},
det_exogenous{det_exogenous_arg},
is_linear{is_linear_arg},
endo_nbr{endo_nbr_arg},
Max_Lag{Max_Lag_arg},
Max_Lead{Max_Lead_arg},
u_count_int{u_count_int_arg},
nb_col_jacob{nb_col_jacob_arg},
det_exo_size{det_exo_size_arg},
exo_size{exo_size_arg},
other_endo_size{other_endo_size_arg},
nb_col_det_exo_jacob{nb_col_det_exo_jacob_arg},
nb_col_exo_jacob{nb_col_exo_jacob_arg},
nb_col_other_endo_jacob{nb_col_other_endo_jacob_arg}
{
}
inline
FBEGINBLOCK_(unsigned int size_arg, BlockSimulationType type_arg, int unsigned first_element, int unsigned block_size,
const vector<int> &variable_arg, const vector<int> &equation_arg,
bool is_linear_arg, int endo_nbr_arg, int Max_Lag_arg, int Max_Lead_arg, int &u_count_int_arg, int nb_col_jacob_arg) :
size{static_cast<int>(size_arg)},
type{static_cast<uint8_t>(type_arg)},
variable{variable_arg.begin()+first_element, variable_arg.begin()+(first_element+block_size)},
equation{equation_arg.begin()+first_element, equation_arg.begin()+(first_element+block_size)},
is_linear{is_linear_arg},
endo_nbr{endo_nbr_arg},
Max_Lag{Max_Lag_arg},
Max_Lead{Max_Lead_arg},
u_count_int{u_count_int_arg},
nb_col_jacob{nb_col_jacob_arg},
det_exo_size{0},
exo_size{0},
other_endo_size{0},
nb_col_det_exo_jacob{0},
nb_col_exo_jacob{0},
nb_col_other_endo_jacob{0}
{
}
inline unsigned int
get_size()
{
return size;
};
inline uint8_t
get_type()
{
return type;
};
inline bool
get_is_linear()
{
return is_linear;
};
inline int
get_endo_nbr()
{
return endo_nbr;
};
inline int
get_Max_Lag()
{
return Max_Lag;
};
inline int
get_Max_Lead()
{
return Max_Lead;
};
inline int
get_u_count_int()
{
return u_count_int;
};
inline vector<Block_contain_type>
get_Block_Contain()
{
return Block_Contain_;
};
inline int
get_nb_col_jacob()
{
return nb_col_jacob;
};
inline unsigned int
get_exo_size()
{
return exo_size;
};
inline unsigned int
get_nb_col_exo_jacob()
{
return nb_col_exo_jacob;
};
inline unsigned int
get_det_exo_size()
{
return det_exo_size;
};
inline unsigned int
get_nb_col_det_exo_jacob()
{
return nb_col_det_exo_jacob;
};
inline unsigned int
get_other_endo_size()
{
return other_endo_size;
};
inline unsigned int
get_nb_col_other_endo_jacob()
{
return nb_col_other_endo_jacob;
};
inline vector<int>
get_endogenous()
{
return variable;
}
inline vector<unsigned int>
get_exogenous()
{
return exogenous;
}
inline void
write(ostream &CompileCode, unsigned int &instruction_number)
{
CompileCode.write(reinterpret_cast<char *>(&op_code), sizeof(op_code));
CompileCode.write(reinterpret_cast<char *>(&size), sizeof(size));
CompileCode.write(reinterpret_cast<char *>(&type), sizeof(type));
for (int i = 0; i < size; i++)
{
CompileCode.write(reinterpret_cast<char *>(&variable[i]), sizeof(variable[0]));
CompileCode.write(reinterpret_cast<char *>(&equation[i]), sizeof(equation[0]));
}
if (type == SOLVE_TWO_BOUNDARIES_SIMPLE || type == SOLVE_TWO_BOUNDARIES_COMPLETE
|| type == SOLVE_BACKWARD_COMPLETE || type == SOLVE_FORWARD_COMPLETE)
{
CompileCode.write(reinterpret_cast<char *>(&is_linear), sizeof(is_linear));
CompileCode.write(reinterpret_cast<char *>(&endo_nbr), sizeof(endo_nbr));
CompileCode.write(reinterpret_cast<char *>(&Max_Lag), sizeof(Max_Lag));
CompileCode.write(reinterpret_cast<char *>(&Max_Lead), sizeof(Max_Lead));
CompileCode.write(reinterpret_cast<char *>(&u_count_int), sizeof(u_count_int));
}
CompileCode.write(reinterpret_cast<char *>(&nb_col_jacob), sizeof(nb_col_jacob));
CompileCode.write(reinterpret_cast<char *>(&det_exo_size), sizeof(det_exo_size));
CompileCode.write(reinterpret_cast<char *>(&nb_col_det_exo_jacob), sizeof(nb_col_det_exo_jacob));
CompileCode.write(reinterpret_cast<char *>(&exo_size), sizeof(exo_size));
CompileCode.write(reinterpret_cast<char *>(&nb_col_exo_jacob), sizeof(nb_col_exo_jacob));
CompileCode.write(reinterpret_cast<char *>(&other_endo_size), sizeof(other_endo_size));
CompileCode.write(reinterpret_cast<char *>(&nb_col_other_endo_jacob), sizeof(nb_col_other_endo_jacob));
for (unsigned int i = 0; i < det_exo_size; i++)
CompileCode.write(reinterpret_cast<char *>(&det_exogenous[i]), sizeof(det_exogenous[0]));
for (unsigned int i = 0; i < exo_size; i++)
CompileCode.write(reinterpret_cast<char *>(&exogenous[i]), sizeof(exogenous[0]));
for (unsigned int i = 0; i < other_endo_size; i++)
CompileCode.write(reinterpret_cast<char *>(&other_endogenous[i]), sizeof(other_endogenous[0]));
instruction_number++;
};
#ifdef BYTE_CODE
inline uint8_t *
load(uint8_t *code)
{
op_code = FBEGINBLOCK; code += sizeof(op_code);
memcpy(&size, code, sizeof(size)); code += sizeof(size);
memcpy(&type, code, sizeof(type)); code += sizeof(type);
for (int i = 0; i < size; i++)
{
Block_contain_type bc;
memcpy(&bc.Variable, code, sizeof(bc.Variable)); code += sizeof(bc.Variable);
memcpy(&bc.Equation, code, sizeof(bc.Equation)); code += sizeof(bc.Equation);
Block_Contain_.push_back(bc);
}
if (type == SOLVE_TWO_BOUNDARIES_SIMPLE || type == SOLVE_TWO_BOUNDARIES_COMPLETE
|| type == SOLVE_BACKWARD_COMPLETE || type == SOLVE_FORWARD_COMPLETE)
{
memcpy(&is_linear, code, sizeof(is_linear)); code += sizeof(is_linear);
memcpy(&endo_nbr, code, sizeof(endo_nbr)); code += sizeof(endo_nbr);
memcpy(&Max_Lag, code, sizeof(Max_Lag)); code += sizeof(Max_Lag);
memcpy(&Max_Lead, code, sizeof(Max_Lead)); code += sizeof(Max_Lead);
memcpy(&u_count_int, code, sizeof(u_count_int)); code += sizeof(u_count_int);
}
memcpy(&nb_col_jacob, code, sizeof(nb_col_jacob)); code += sizeof(nb_col_jacob);
memcpy(&det_exo_size, code, sizeof(det_exo_size)); code += sizeof(det_exo_size);
memcpy(&nb_col_det_exo_jacob, code, sizeof(nb_col_det_exo_jacob)); code += sizeof(nb_col_det_exo_jacob);
memcpy(&exo_size, code, sizeof(exo_size)); code += sizeof(exo_size);
memcpy(&nb_col_exo_jacob, code, sizeof(nb_col_exo_jacob)); code += sizeof(nb_col_exo_jacob);
memcpy(&other_endo_size, code, sizeof(other_endo_size)); code += sizeof(other_endo_size);
memcpy(&nb_col_other_endo_jacob, code, sizeof(nb_col_other_endo_jacob)); code += sizeof(nb_col_other_endo_jacob);
for (unsigned int i = 0; i < det_exo_size; i++)
{
unsigned int tmp_i;
memcpy(&tmp_i, code, sizeof(tmp_i)); code += sizeof(tmp_i);
det_exogenous.push_back(tmp_i);
}
for (unsigned int i = 0; i < exo_size; i++)
{
unsigned int tmp_i;
memcpy(&tmp_i, code, sizeof(tmp_i)); code += sizeof(tmp_i);
exogenous.push_back(tmp_i);
}
for (unsigned int i = 0; i < other_endo_size; i++)
{
unsigned int tmp_i;
memcpy(&tmp_i, code, sizeof(tmp_i)); code += sizeof(tmp_i);
other_endogenous.push_back(tmp_i);
}
return code;
};
#endif
};
#ifdef BYTE_CODE
using tags_liste_t = vector<pair<Tags, void * >>;
class CodeLoad
{
private:
uint8_t *code;
unsigned int nb_blocks;
vector<size_t> begin_block;
public:
inline unsigned int
get_block_number()
{
return nb_blocks;
};
size_t inline
get_begin_block(int block)
{
return begin_block[block];
}
inline void *
get_current_code()
{
return code;
};
inline tags_liste_t
get_op_code(string file_name)
{
tags_liste_t tags_liste;
ifstream CompiledCode;
streamoff Code_Size;
CompiledCode.open(file_name + ".cod", std::ios::in | std::ios::binary| std::ios::ate);
if (!CompiledCode.is_open())
{
return tags_liste;
}
Code_Size = CompiledCode.tellg();
CompiledCode.seekg(std::ios::beg);
code = static_cast<uint8_t *>(mxMalloc(Code_Size));
CompiledCode.seekg(0);
CompiledCode.read(reinterpret_cast<char *>(code), Code_Size);
CompiledCode.close();
nb_blocks = 0;
bool done = false;
int instruction = 0;
while (!done)
{
switch (*code)
{
case FLDZ:
# ifdef DEBUGL
mexPrintf("FLDZ = %d size = %d\n", FLDZ, sizeof(FLDZ_));
# endif
tags_liste.emplace_back(FLDZ, code);
code += sizeof(FLDZ_);
break;
case FEND:
# ifdef DEBUGL
mexPrintf("FEND\n");
# endif
tags_liste.emplace_back(FEND, code);
code += sizeof(FEND_);
done = true;
break;
case FENDBLOCK:
# ifdef DEBUGL
mexPrintf("FENDBLOCK\n");
# endif
tags_liste.emplace_back(FENDBLOCK, code);
code += sizeof(FENDBLOCK_);
break;
case FENDEQU:
# ifdef DEBUGL
mexPrintf("FENDEQU\n");
# endif
tags_liste.emplace_back(FENDEQU, code);
code += sizeof(FENDEQU_);
break;
case FCUML:
# ifdef DEBUGL
mexPrintf("FCUML\n");
# endif
tags_liste.emplace_back(FCUML, code);
code += sizeof(FCUML_);
break;
case FDIMT:
# ifdef DEBUGL
mexPrintf("FDIMT = %d size = %d\n", FDIMT, sizeof(FDIMT_));
# endif
tags_liste.emplace_back(FDIMT, code);
code += sizeof(FDIMT_);
break;
case FDIMST:
# ifdef DEBUGL
mexPrintf("FDIMST\n");
# endif
tags_liste.emplace_back(FDIMST, code);
code += sizeof(FDIMST_);
break;
case FNUMEXPR:
# ifdef DEBUGL
mexPrintf("FNUMEXPR\n");
# endif
tags_liste.emplace_back(FNUMEXPR, code);
code += sizeof(FNUMEXPR_);
break;
case FLDC:
# ifdef DEBUGL
mexPrintf("FLDC\n");
# endif
tags_liste.emplace_back(FLDC, code);
code += sizeof(FLDC_);
break;
case FLDU:
# ifdef DEBUGL
mexPrintf("FLDU\n");
# endif
tags_liste.emplace_back(FLDU, code);
code += sizeof(FLDU_);
break;
case FLDSU:
# ifdef DEBUGL
mexPrintf("FLDSU\n");
# endif
tags_liste.emplace_back(FLDSU, code);
code += sizeof(FLDSU_);
break;
case FLDR:
# ifdef DEBUGL
mexPrintf("FLDR\n");
# endif
tags_liste.emplace_back(FLDR, code);
code += sizeof(FLDR_);
break;
case FLDT:
# ifdef DEBUGL
mexPrintf("FLDT\n");
# endif
tags_liste.emplace_back(FLDT, code);
code += sizeof(FLDT_);
break;
case FLDST:
# ifdef DEBUGL
mexPrintf("FLDST\n");
# endif
tags_liste.emplace_back(FLDST, code);
code += sizeof(FLDST_);
break;
case FSTPT:
# ifdef DEBUGL
mexPrintf("FSTPT = %d size = %d\n", FSTPT, sizeof(FSTPT_));
# endif
tags_liste.emplace_back(FSTPT, code);
code += sizeof(FSTPT_);
break;
case FSTPST:
# ifdef DEBUGL
mexPrintf("FSTPST\n");
# endif
tags_liste.emplace_back(FSTPST, code);
code += sizeof(FSTPST_);
break;
case FSTPR:
# ifdef DEBUGL
mexPrintf("FSTPR\n");
# endif
tags_liste.emplace_back(FSTPR, code);
code += sizeof(FSTPR_);
break;
case FSTPU:
# ifdef DEBUGL
mexPrintf("FSTPU\n");
# endif
tags_liste.emplace_back(FSTPU, code);
code += sizeof(FSTPU_);
break;
case FSTPSU:
# ifdef DEBUGL
mexPrintf("FSTPSU\n");
# endif
tags_liste.emplace_back(FSTPSU, code);
code += sizeof(FSTPSU_);
break;
case FSTPG:
# ifdef DEBUGL
mexPrintf("FSTPG\n");
# endif
tags_liste.emplace_back(FSTPG, code);
code += sizeof(FSTPG_);
break;
case FSTPG2:
# ifdef DEBUGL
mexPrintf("FSTPG2\n");
# endif
tags_liste.emplace_back(FSTPG2, code);
code += sizeof(FSTPG2_);
break;
case FSTPG3:
# ifdef DEBUGL
mexPrintf("FSTPG3\n");
# endif
tags_liste.emplace_back(FSTPG3, code);
code += sizeof(FSTPG3_);
break;
case FUNARY:
# ifdef DEBUGL
mexPrintf("FUNARY\n");
# endif
tags_liste.emplace_back(FUNARY, code);
code += sizeof(FUNARY_);
break;
case FBINARY:
# ifdef DEBUGL
mexPrintf("FBINARY\n");
# endif
tags_liste.emplace_back(FBINARY, code);
code += sizeof(FBINARY_);
break;
case FTRINARY:
# ifdef DEBUGL
mexPrintf("FTRINARY\n");
# endif
tags_liste.emplace_back(FTRINARY, code);
code += sizeof(FTRINARY_);
break;
case FOK:
# ifdef DEBUGL
mexPrintf("FOK\n");
# endif
tags_liste.emplace_back(FOK, code);
code += sizeof(FOK_);
break;
case FLDVS:
# ifdef DEBUGL
mexPrintf("FLDVS\n");
# endif
tags_liste.emplace_back(FLDVS, code);
code += sizeof(FLDVS_);
break;
case FLDSV:
# ifdef DEBUGL
mexPrintf("FLDSV\n");
# endif
tags_liste.emplace_back(FLDSV, code);
code += sizeof(FLDSV_);
break;
case FSTPSV:
# ifdef DEBUGL
mexPrintf("FSTPSV\n");
# endif
tags_liste.emplace_back(FSTPSV, code);
code += sizeof(FSTPSV_);
break;
case FLDV:
# ifdef DEBUGL
mexPrintf("FLDV\n");
# endif
tags_liste.emplace_back(FLDV, code);
code += sizeof(FLDV_);
break;
case FSTPV:
# ifdef DEBUGL
mexPrintf("FSTPV\n");
# endif
tags_liste.emplace_back(FSTPV, code);
code += sizeof(FSTPV_);
break;
case FBEGINBLOCK:
# ifdef DEBUGL
mexPrintf("FBEGINBLOCK\n");
# endif
{
FBEGINBLOCK_ *fbegin_block = new FBEGINBLOCK_;
code = fbegin_block->load(code);
begin_block.push_back(tags_liste.size());
tags_liste.emplace_back(FBEGINBLOCK, fbegin_block);
nb_blocks++;
}
break;
case FJMPIFEVAL:
# ifdef DEBUGL
mexPrintf("FJMPIFEVAL\n");
# endif
tags_liste.emplace_back(FJMPIFEVAL, code);
code += sizeof(FJMPIFEVAL_);
break;
case FJMP:
# ifdef DEBUGL
mexPrintf("FJMP\n");
# endif
tags_liste.emplace_back(FJMP, code);
code += sizeof(FJMP_);
break;
case FCALL:
{
# ifdef DEBUGL
mexPrintf("FCALL\n");
# endif
FCALL_ *fcall = new FCALL_;
code = fcall->load(code);
tags_liste.emplace_back(FCALL, fcall);
# ifdef DEBUGL
mexPrintf("FCALL finish\n"); mexEvalString("drawnow;");
mexPrintf("-- *code=%d\n", *code); mexEvalString("drawnow;");
# endif
}
break;
case FPUSH:
# ifdef DEBUGL
mexPrintf("FPUSH\n");
# endif
tags_liste.emplace_back(FPUSH, code);
code += sizeof(FPUSH_);
break;
case FPOP:
# ifdef DEBUGL
mexPrintf("FPOP\n");
# endif
tags_liste.emplace_back(FPOP, code);
code += sizeof(FPOP_);
break;
case FLDTEF:
# ifdef DEBUGL
mexPrintf("FLDTEF\n");
# endif
tags_liste.emplace_back(FLDTEF, code);
code += sizeof(FLDTEF_);
break;
case FSTPTEF:
# ifdef DEBUGL
mexPrintf("FSTPTEF\n");
# endif
tags_liste.emplace_back(FSTPTEF, code);
code += sizeof(FSTPTEF_);
break;
case FLDTEFD:
# ifdef DEBUGL
mexPrintf("FLDTEFD\n");
# endif
tags_liste.emplace_back(FLDTEFD, code);
code += sizeof(FLDTEFD_);
break;
case FSTPTEFD:
# ifdef DEBUGL
mexPrintf("FSTPTEFD\n");
# endif
tags_liste.emplace_back(FSTPTEFD, code);
code += sizeof(FSTPTEFD_);
break;
case FLDTEFDD:
# ifdef DEBUGL
mexPrintf("FLDTEFDD\n");
# endif
tags_liste.emplace_back(FLDTEFDD, code);
code += sizeof(FLDTEFDD_);
break;
case FSTPTEFDD:
# ifdef DEBUGL
mexPrintf("FSTPTEFDD\n");
# endif
tags_liste.emplace_back(FSTPTEFDD, code);
code += sizeof(FSTPTEFDD_);
break;
default:
mexPrintf("Unknown Tag value=%d code=%x\n", *code, code);
done = true;
}
instruction++;
}
return tags_liste;
};
};
#endif
#pragma pack(pop)
#endif
/*
* Copyright © 2007-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 COMMON_ENUMS_HH
#define COMMON_ENUMS_HH
//! Enumeration of possible symbol types
/*! Warning: do not to change existing values for 0 to 4: the values matter for homotopy_setup
* command */
enum class SymbolType
{
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
unusedEndogenous
= 16, //!< Type to mark unused endogenous variables when `nostrict` option is passed
// Value 17 is unused for the time being (but could be reused)
epilogue = 18, //!< Variables created in epilogue block
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,
exp,
log,
log10,
cos,
sin,
tan,
acos,
asin,
atan,
cosh,
sinh,
tanh,
acosh,
asinh,
atanh,
sqrt,
cbrt,
abs,
sign,
steadyState,
steadyStateParamDeriv, // for the derivative of the STEADY_STATE operator w.r.t. to a parameter
steadyStateParam2ndDeriv, // for the 2nd derivative of the STEADY_STATE operator w.r.t. to a
// parameter
expectation,
erf,
erfc,
diff,
adl,
sum
};
enum class BinaryOpcode
{
plus,
minus,
times,
divide,
power,
powerDeriv, // for the derivative of the power function (see trac ticket #78)
equal,
max,
min,
less,
greater,
lessEqual,
greaterEqual,
equalEqual,
different
};
// Small number value used when evaluating powerDeriv opcodes.
// Put here instead of inside BinaryOpNode class, because needed by bytecode MEX.
constexpr double power_deriv_near_zero {1e-12};
enum class TrinaryOpcode
{
normcdf,
normpdf
};
enum class PriorDistributions
{
noShape = 0,
beta = 1,
gamma = 2,
normal = 3,
invGamma = 4,
invGamma1 = 4,
uniform = 5,
invGamma2 = 6,
dirichlet = 7,
weibull = 8
};
enum class EquationType
{
evaluate, //!< Simple evaluation, normalized variable on left-hand side (written as such by the
//!< user)
evaluateRenormalized, //!< Simple evaluation, normalized variable on left-hand side (normalization
//!< computed by the preprocessor)
solve //!< No simple evaluation of the equation, it has to be solved
};
enum class BlockSimulationType
{
evaluateForward = 1, //!< Simple evaluation, normalized variable on left-hand side, forward
evaluateBackward, //!< Simple evaluation, normalized variable on left-hand side, backward
solveForwardSimple, //!< Block of one equation, newton solver needed, forward
solveBackwardSimple, //!< Block of one equation, newton solver needed, backward
solveTwoBoundariesSimple, //!< Block of one equation, Newton solver needed, forward and backward
solveForwardComplete, //!< Block of several equations, Newton solver needed, forward
solveBackwardComplete, //!< Block of several equations, Newton solver needed, backward
solveTwoBoundariesComplete //!< Block of several equations, Newton solver needed, forward and
//!< backwar
};
enum class PacTargetKind
{
unspecified, // Must be the first one, because it’s the default initializer
ll,
dl,
dd
};
#endif
Source diff could not be displayed: it is too large. Options to address this: view the blob.
/*
* Copyright © 2003-2019 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -14,25 +14,28 @@
* 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 <http://www.gnu.org/licenses/>.
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _COMPUTINGTASKS_HH
#define _COMPUTINGTASKS_HH
#ifndef COMPUTING_TASKS_HH
#define COMPUTING_TASKS_HH
#include <memory>
#include <optional>
#include <ostream>
#include "SymbolList.hh"
#include "SymbolTable.hh"
#include "Statement.hh"
#include "StaticModel.hh"
#include "DynamicModel.hh"
#include "ModelEquationBlock.hh"
#include "Statement.hh"
#include "StaticModel.hh"
#include "SymbolList.hh"
#include "SymbolTable.hh"
class SteadyStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit SteadyStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -44,6 +47,7 @@ class CheckStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit CheckStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -55,6 +59,7 @@ class SimulStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit SimulStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -66,6 +71,7 @@ class PerfectForesightSetupStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit PerfectForesightSetupStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -76,6 +82,7 @@ class PerfectForesightSolverStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit PerfectForesightSolverStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -83,213 +90,197 @@ public:
void writeJsonOutput(ostream& output) const override;
};
class PriorPosteriorFunctionStatement : public Statement
class PerfectForesightWithExpectationErrorsSetupStatement : public Statement
{
private:
const bool prior_func;
const OptionsList options_list;
public:
PriorPosteriorFunctionStatement(const bool prior_func_arg, OptionsList options_list_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
explicit PerfectForesightWithExpectationErrorsSetupStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class DetCondForecast : public Statement
class PerfectForesightWithExpectationErrorsSolverStatement : public Statement
{
private:
const OptionsList options_list;
const SymbolList symbol_list;
const bool linear_decomposition;
public:
DetCondForecast(SymbolList symbol_list_arg,
OptionsList options_list_arg,
const bool linear_decompositiontion_arg);
//virtual void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings);
explicit PerfectForesightWithExpectationErrorsSolverStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class ModelInfoStatement : public Statement
class PriorPosteriorFunctionStatement : public Statement
{
private:
const bool prior_func;
const OptionsList options_list;
public:
explicit ModelInfoStatement(OptionsList options_list_arg);
PriorPosteriorFunctionStatement(const bool prior_func_arg, OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class StochSimulStatement : public Statement
class ModelInfoStatement : public Statement
{
private:
SymbolList symbol_list;
const OptionsList options_list;
public:
StochSimulStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
explicit ModelInfoStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class PacModelStatement : public Statement
class StochSimulStatement : public Statement
{
public:
const string name, aux_model_name, discount;
expr_t growth, original_growth;
private:
const double steady_state_growth_rate_number;
const int steady_state_growth_rate_symb_id;
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
vector<tuple<int, int, int, double>> growth_info;
public:
PacModelStatement(string name_arg,
string aux_model_name_arg,
string discount_arg,
expr_t growth_arg,
double steady_state_growth_rate_number_arg,
int steady_state_growth_rate_symb_id_arg,
public:
StochSimulStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void overwriteGrowth(expr_t new_growth);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class VarRestrictionsStatement : public Statement
class ForecastStatement : public Statement
{
private:
using var_restriction_eq_crosseq_t = pair<pair<int, pair<int, int>>, expr_t>;
const string var_model_name;
const map<string, vector<string>> var_map;
const map<int, map<int, SymbolList>> exclusion_restrictions;
using equation_restrictions_t = map<int, pair<pair<var_restriction_eq_crosseq_t, var_restriction_eq_crosseq_t>, double>>;
const equation_restrictions_t equation_restrictions;
using crossequation_restrictions_t = vector<pair<pair<var_restriction_eq_crosseq_t, var_restriction_eq_crosseq_t>, double>>;
const crossequation_restrictions_t crossequation_restrictions;
const map<pair<int, int>, double> covariance_number_restriction;
const map<pair<int, int>, pair<int, int>> covariance_pair_restriction;
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
int findIdxInVector(const vector<string> &vecvars, const string &var) const;
public:
VarRestrictionsStatement(string var_model_name_arg,
map<string, vector<string>> var_map_arg,
map<int, map<int, SymbolList>> exclusion_restrictions_arg,
equation_restrictions_t equation_restrictions_arg,
crossequation_restrictions_t crossequation_restrictions_arg,
map<pair<int, int>, double> covariance_number_restriction_arg,
map<pair<int, int>, pair<int, int>> covariance_pair_restriction_arg,
public:
ForecastStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class VarEstimationStatement : public Statement
class RamseyModelStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit VarEstimationStatement(OptionsList options_list_arg);
explicit RamseyModelStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class ForecastStatement : public Statement
class RamseyPolicyStatement : public Statement
{
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
ForecastStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
RamseyPolicyStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class RamseyModelStatement : public Statement
class EvaluatePlannerObjectiveStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit RamseyModelStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
explicit EvaluatePlannerObjectiveStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class RamseyConstraintsStatement : public Statement
class OccbinSetupStatement : public Statement
{
private:
const OptionsList options_list;
public:
struct Constraint
{
int endo;
BinaryOpcode code;
expr_t expression;
explicit OccbinSetupStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
using constraints_t = vector<Constraint>;
class OccbinSolverStatement : public Statement
{
private:
const SymbolTable &symbol_table;
const constraints_t constraints;
const OptionsList options_list;
public:
RamseyConstraintsStatement(const SymbolTable &symbol_table_arg, constraints_t constraints_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
explicit OccbinSolverStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class RamseyPolicyStatement : public Statement
class OccbinWriteRegimesStatement : public Statement
{
private:
const SymbolTable &symbol_table;
const vector<string> ramsey_policy_list;
const OptionsList options_list;
public:
RamseyPolicyStatement(const SymbolTable &symbol_table_arg,
vector<string> ramsey_policy_list_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
void checkRamseyPolicyList();
explicit OccbinWriteRegimesStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class DiscretionaryPolicyStatement : public Statement
class OccbinGraphStatement : public Statement
{
private:
const SymbolList symbol_list;
const OptionsList options_list;
public:
DiscretionaryPolicyStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
OccbinGraphStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class RplotStatement : public Statement
class DiscretionaryPolicyStatement : public Statement
{
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
explicit RplotStatement(SymbolList symbol_list_arg);
DiscretionaryPolicyStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class UnitRootVarsStatement : public Statement
class RplotStatement : public Statement
{
private:
const SymbolList symbol_list;
const SymbolTable& symbol_table;
public:
RplotStatement(SymbolList symbol_list_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class PeriodsStatement : public Statement
class UnitRootVarsStatement : public Statement
{
private:
const int periods;
public:
explicit PeriodsStatement(int periods_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -298,6 +289,7 @@ class DsampleStatement : public Statement
{
private:
const int val1, val2;
public:
explicit DsampleStatement(int val1_arg);
DsampleStatement(int val1_arg, int val2_arg);
......@@ -308,22 +300,25 @@ public:
class EstimationStatement : public Statement
{
private:
const SymbolTable& symbol_table;
const SymbolList symbol_list;
const OptionsList options_list;
public:
EstimationStatement(SymbolList symbol_list_arg,
EstimationStatement(const SymbolTable& symbol_table_arg, SymbolList symbol_list_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class DynareSensitivityStatement : public Statement
class SensitivityStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit DynareSensitivityStatement(OptionsList options_list_arg);
explicit SensitivityStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -333,9 +328,11 @@ class ObservationTrendsStatement : public Statement
{
public:
using trend_elements_t = map<string, expr_t>;
private:
const trend_elements_t trend_elements;
const SymbolTable& symbol_table;
public:
ObservationTrendsStatement(trend_elements_t trend_elements_arg,
const SymbolTable& symbol_table_arg);
......@@ -343,11 +340,44 @@ public:
void writeJsonOutput(ostream& output) const override;
};
class DeterministicTrendsStatement : public Statement
{
public:
using trend_elements_t = map<string, expr_t>;
private:
const trend_elements_t trend_elements;
const SymbolTable& symbol_table;
public:
DeterministicTrendsStatement(trend_elements_t trend_elements_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class FilterInitialStateStatement : public Statement
{
public:
using filter_initial_state_elements_t = map<pair<int, int>, expr_t>;
private:
const filter_initial_state_elements_t filter_initial_state_elements;
const SymbolTable& symbol_table;
public:
FilterInitialStateStatement(filter_initial_state_elements_t filter_initial_state_elements_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class OsrParamsStatement : public Statement
{
private:
const SymbolList symbol_list;
const SymbolTable& symbol_table;
public:
OsrParamsStatement(SymbolList symbol_list_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -360,9 +390,11 @@ class OsrStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
OsrStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
OsrStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -388,6 +420,7 @@ class OsrParamsBoundsStatement : public Statement
{
private:
const vector<OsrParams> osr_params_list;
public:
explicit OsrParamsBoundsStatement(vector<OsrParams> osr_params_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -400,9 +433,12 @@ class DynaTypeStatement : public Statement
private:
const SymbolList symbol_list;
const string filename;
const SymbolTable& symbol_table;
public:
DynaTypeStatement(SymbolList symbol_list_arg,
string filename_arg);
DynaTypeStatement(SymbolList symbol_list_arg, string filename_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -412,9 +448,12 @@ class DynaSaveStatement : public Statement
private:
const SymbolList symbol_list;
const string filename;
const SymbolTable& symbol_table;
public:
DynaSaveStatement(SymbolList symbol_list_arg,
string filename_arg);
DynaSaveStatement(SymbolList symbol_list_arg, string filename_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -423,12 +462,13 @@ class ModelComparisonStatement : public Statement
{
public:
using filename_list_t = vector<pair<string, string>>;
private:
filename_list_t filename_list;
OptionsList options_list;
public:
ModelComparisonStatement(filename_list_t filename_list_arg,
OptionsList options_list_arg);
ModelComparisonStatement(filename_list_t filename_list_arg, OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -460,42 +500,77 @@ public:
}
};
class EstimatedParamsStatement : public Statement
class AbstractEstimatedParamsStatement : public Statement
{
private:
protected:
const vector<EstimationParams> estim_params_list;
const SymbolTable& symbol_table;
AbstractEstimatedParamsStatement(vector<EstimationParams> estim_params_list_arg,
const SymbolTable& symbol_table_arg);
[[nodiscard]] virtual string blockName() const = 0;
// Part of the check pass that is common to the three estimated_params{,_init,bounds} blocks
void commonCheckPass() const;
};
class EstimatedParamsStatement : public AbstractEstimatedParamsStatement
{
private:
const bool overwrite;
public:
EstimatedParamsStatement(vector<EstimationParams> estim_params_list_arg,
const SymbolTable &symbol_table_arg);
const SymbolTable& symbol_table_arg, bool overwrite_arg);
[[nodiscard]] string
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;
};
class EstimatedParamsInitStatement : public Statement
class EstimatedParamsInitStatement : public AbstractEstimatedParamsStatement
{
private:
const vector<EstimationParams> estim_params_list;
const SymbolTable &symbol_table;
const bool use_calibration;
public:
EstimatedParamsInitStatement(vector<EstimationParams> estim_params_list_arg,
const SymbolTable &symbol_table_arg,
const bool use_calibration_arg);
const SymbolTable& symbol_table_arg, const bool use_calibration_arg);
[[nodiscard]] string
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;
};
class EstimatedParamsBoundsStatement : public Statement
class EstimatedParamsBoundsStatement : public AbstractEstimatedParamsStatement
{
private:
const vector<EstimationParams> estim_params_list;
const SymbolTable &symbol_table;
public:
EstimatedParamsBoundsStatement(vector<EstimationParams> estim_params_list_arg,
const SymbolTable& symbol_table_arg);
[[nodiscard]] string
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;
};
class EstimatedParamsRemoveStatement : public Statement
{
public:
// Only the type, name and name2 fields of EstimationParams are used
const vector<EstimationParams> estim_params_list;
const SymbolTable& symbol_table;
EstimatedParamsRemoveStatement(vector<EstimationParams> estim_params_list_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -505,13 +580,14 @@ class OptimWeightsStatement : public Statement
public:
using var_weights_t = map<string, expr_t>;
using covar_weights_t = map<pair<string, string>, expr_t>;
private:
const var_weights_t var_weights;
const covar_weights_t covar_weights;
const SymbolTable& symbol_table;
public:
OptimWeightsStatement(var_weights_t var_weights_arg,
covar_weights_t covar_weights_arg,
OptimWeightsStatement(var_weights_t var_weights_arg, covar_weights_t covar_weights_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -521,19 +597,20 @@ public:
class PlannerObjectiveStatement : public Statement
{
private:
StaticModel model_tree;
unique_ptr<PlannerObjective> model_tree;
bool computing_pass_called {false};
public:
PlannerObjectiveStatement(const StaticModel &model_tree_arg);
explicit PlannerObjectiveStatement(unique_ptr<PlannerObjective> model_tree_arg);
/*! \todo check there are only endogenous variables at the current period in the objective
(no exogenous, no lead/lag) */
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
/*! \todo allow for the possibility of disabling temporary terms */
void computingPass() override;
void computingPass(const ModFileStructure& mod_file_struct) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
//! Return a reference the Planner Objective model tree
const StaticModel &getPlannerObjective() const;
[[nodiscard]] const PlannerObjective& getPlannerObjective() const;
};
class BVARDensityStatement : public Statement
......@@ -541,6 +618,7 @@ class BVARDensityStatement : public Statement
private:
const int maxnlags;
const OptionsList options_list;
public:
BVARDensityStatement(int maxnlags_arg, OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -553,6 +631,7 @@ class BVARForecastStatement : public Statement
private:
const int nlags;
const OptionsList options_list;
public:
BVARForecastStatement(int nlags_arg, OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -560,10 +639,24 @@ public:
void writeJsonOutput(ostream& output) const override;
};
class BVARIRFStatement : public Statement
{
private:
const int nirf;
const string identificationname;
public:
BVARIRFStatement(int nirf_arg, string identificationname_arg);
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;
};
class SBVARStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit SBVARStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -575,6 +668,7 @@ class MSSBVAREstimationStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVAREstimationStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -586,6 +680,7 @@ class MSSBVARSimulationStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVARSimulationStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -597,6 +692,7 @@ class MSSBVARComputeMDDStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVARComputeMDDStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -608,6 +704,7 @@ class MSSBVARComputeProbabilitiesStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVARComputeProbabilitiesStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -620,9 +717,11 @@ class MSSBVARIrfStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
MSSBVARIrfStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
MSSBVARIrfStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -632,6 +731,7 @@ class MSSBVARForecastStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVARForecastStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -643,6 +743,7 @@ class MSSBVARVarianceDecompositionStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit MSSBVARVarianceDecompositionStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -654,6 +755,7 @@ class IdentificationStatement : public Statement
{
private:
OptionsList options_list;
public:
explicit IdentificationStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -666,8 +768,10 @@ class WriteLatexDynamicModelStatement : public Statement
private:
const DynamicModel& dynamic_model;
const bool write_equation_tags;
public:
WriteLatexDynamicModelStatement(const DynamicModel &dynamic_model_arg, bool write_equation_tags_arg);
WriteLatexDynamicModelStatement(const DynamicModel& dynamic_model_arg,
bool write_equation_tags_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -677,6 +781,7 @@ class WriteLatexStaticModelStatement : public Statement
private:
const StaticModel& static_model;
const bool write_equation_tags;
public:
WriteLatexStaticModelStatement(const StaticModel& static_model_arg, bool write_equation_tags_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -688,8 +793,10 @@ class WriteLatexOriginalModelStatement : public Statement
private:
const DynamicModel& original_model;
const bool write_equation_tags;
public:
WriteLatexOriginalModelStatement(const DynamicModel &original_model_arg, bool write_equation_tags_arg);
WriteLatexOriginalModelStatement(const DynamicModel& original_model_arg,
bool write_equation_tags_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -698,6 +805,7 @@ class WriteLatexSteadyStateModelStatement : public Statement
{
private:
const SteadyStateModel& steady_state_model;
public:
explicit WriteLatexSteadyStateModelStatement(const SteadyStateModel& steady_state_model_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -710,9 +818,12 @@ class ShockDecompositionStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
ShockDecompositionStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
ShockDecompositionStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -722,9 +833,12 @@ class RealtimeShockDecompositionStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
RealtimeShockDecompositionStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
RealtimeShockDecompositionStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -734,9 +848,12 @@ class PlotShockDecompositionStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
PlotShockDecompositionStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
PlotShockDecompositionStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -746,9 +863,26 @@ class InitialConditionDecompositionStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
InitialConditionDecompositionStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
InitialConditionDecompositionStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class SqueezeShockDecompositionStatement : public Statement
{
private:
const SymbolList symbol_list;
const SymbolTable& symbol_table;
public:
SqueezeShockDecompositionStatement(SymbolList symbol_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -757,6 +891,7 @@ class ConditionalForecastStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit ConditionalForecastStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -767,11 +902,14 @@ public:
class PlotConditionalForecastStatement : public Statement
{
private:
//! A value of -1 indicates that the user didn't specify a value
const int periods;
const optional<int> periods; // The user is allowed not to declare periods
const SymbolList symbol_list;
const SymbolTable& symbol_table;
public:
PlotConditionalForecastStatement(int periods_arg, SymbolList symbol_list_arg);
PlotConditionalForecastStatement(const optional<int>& periods_arg, SymbolList symbol_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -781,9 +919,11 @@ class CalibSmootherStatement : public Statement
private:
const SymbolList symbol_list;
const OptionsList options_list;
const SymbolTable& symbol_table;
public:
CalibSmootherStatement(SymbolList symbol_list_arg,
OptionsList options_list_arg);
CalibSmootherStatement(SymbolList symbol_list_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -793,6 +933,7 @@ class ExtendedPathStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit ExtendedPathStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -814,17 +955,16 @@ public:
};
using svar_identification_restrictions_t = vector<svar_identification_restriction>;
private:
const svar_identification_restrictions_t restrictions;
const bool upper_cholesky_present;
const bool lower_cholesky_present;
const bool constants_exclusion_present;
const bool upper_cholesky_present, lower_cholesky_present, constants_exclusion_present;
const SymbolTable& symbol_table;
int getMaxLag() const;
[[nodiscard]] int getMaxLag() const;
public:
SvarIdentificationStatement(svar_identification_restrictions_t restrictions_arg,
bool upper_cholesky_present_arg,
bool lower_cholesky_present_arg,
bool upper_cholesky_present_arg, bool lower_cholesky_present_arg,
bool constants_exclusion_present_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -837,6 +977,7 @@ class MarkovSwitchingStatement : public Statement
private:
const OptionsList options_list;
map<pair<int, int>, double> restriction_map;
public:
explicit MarkovSwitchingStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -848,6 +989,7 @@ class SvarStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit SvarStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -865,9 +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;
};
......@@ -876,6 +1019,7 @@ class EstimationDataStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit EstimationDataStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -888,17 +1032,16 @@ class SubsamplesStatement : public Statement
public:
//! Storage for declaring subsamples: map<subsample_name, <date1, date2 >
using subsample_declaration_map_t = map<string, pair<string, string>>;
private:
const string name1;
const string name2;
const string name1, name2;
const subsample_declaration_map_t subsample_declaration_map;
const SymbolTable& symbol_table;
public:
SubsamplesStatement(string name1_arg,
string name2_arg,
SubsamplesStatement(string name1_arg, string name2_arg,
subsample_declaration_map_t subsample_declaration_map_arg,
const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -906,17 +1049,12 @@ public:
class SubsamplesEqualStatement : public Statement
{
private:
const string to_name1;
const string to_name2;
const string from_name1;
const string from_name2;
const string to_name1, to_name2, from_name1, from_name2;
const SymbolTable& symbol_table;
public:
SubsamplesEqualStatement(string to_name1_arg,
string to_name2_arg,
string from_name1_arg,
string from_name2_arg,
const SymbolTable &symbol_table_arg);
SubsamplesEqualStatement(string to_name1_arg, string to_name2_arg, string from_name1_arg,
string from_name2_arg, const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -927,35 +1065,32 @@ private:
const vector<string> joint_parameters;
const PriorDistributions prior_shape;
const OptionsList options_list;
void writeOutputHelper(ostream& output, const string& field, const string& lhs_field) const;
public:
JointPriorStatement(vector<string> joint_parameters_arg,
PriorDistributions prior_shape_arg,
JointPriorStatement(vector<string> joint_parameters_arg, PriorDistributions prior_shape_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeOutputHelper(ostream &output, const string &field, const string &lhs_field) const;
void writeJsonOutput(ostream& output) const override;
};
class BasicPriorStatement : public Statement
{
protected:
const string name;
const string subsample_name;
const string name, subsample_name;
const PriorDistributions prior_shape;
const expr_t variance;
const OptionsList options_list;
BasicPriorStatement(string name_arg,
string subsample_name_arg,
PriorDistributions prior_shape_arg,
expr_t variance_arg,
BasicPriorStatement(string name_arg, string subsample_name_arg,
PriorDistributions prior_shape_arg, expr_t variance_arg,
OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void get_base_name(const SymbolType symb_type, string& lhs_field) const;
void writeCommonOutput(ostream& output, const string& lhs_field) const;
void writeCommonOutputHelper(ostream& output, const string& field, const string& lhs_field) const;
void writePriorOutput(ostream& output, string& lhs_field, const string& name2) const;
bool is_structural_innovation(const SymbolType symb_type) const;
[[nodiscard]] bool is_structural_innovation(const SymbolType symb_type) const;
void writePriorIndex(ostream& output, const string& lhs_field) const;
void writeVarianceOption(ostream& output, const string& lhs_field) const;
void writeOutputHelper(ostream& output, const string& field, const string& lhs_field) const;
......@@ -967,11 +1102,8 @@ protected:
class PriorStatement : public BasicPriorStatement
{
public:
PriorStatement(string name_arg,
string subsample_name_arg,
PriorDistributions prior_shape_arg,
expr_t variance_arg,
OptionsList options_list_arg);
PriorStatement(string name_arg, string subsample_name_arg, PriorDistributions prior_shape_arg,
expr_t variance_arg, OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
......@@ -980,12 +1112,10 @@ class StdPriorStatement : public BasicPriorStatement
{
private:
const SymbolTable& symbol_table;
public:
StdPriorStatement(string name_arg,
string subsample_name_arg,
PriorDistributions prior_shape_arg,
expr_t variance_arg,
OptionsList options_list_arg,
StdPriorStatement(string name_arg, string subsample_name_arg, PriorDistributions prior_shape_arg,
expr_t variance_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -996,14 +1126,11 @@ class CorrPriorStatement : public BasicPriorStatement
private:
const string name1;
const SymbolTable& symbol_table;
public:
CorrPriorStatement(string name_arg1,
string name_arg2,
string subsample_name_arg,
PriorDistributions prior_shape_arg,
expr_t variance_arg,
OptionsList options_list_arg,
const SymbolTable &symbol_table_arg);
CorrPriorStatement(string name_arg1, string name_arg2, string subsample_name_arg,
PriorDistributions prior_shape_arg, expr_t variance_arg,
OptionsList options_list_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -1012,24 +1139,14 @@ public:
class PriorEqualStatement : public Statement
{
private:
const string to_declaration_type;
const string to_name1;
const string to_name2;
const string to_subsample_name;
const string from_declaration_type;
const string from_name1;
const string from_name2;
const string from_subsample_name;
const string to_declaration_type, to_name1, to_name2, to_subsample_name;
const string from_declaration_type, from_name1, from_name2, from_subsample_name;
const SymbolTable& symbol_table;
public:
PriorEqualStatement(string to_declaration_type_arg,
string to_name1_arg,
string to_name2_arg,
string to_subsample_name_arg,
string from_declaration_type_arg,
string from_name1_arg,
string from_name2_arg,
string from_subsample_name_arg,
PriorEqualStatement(string to_declaration_type_arg, string to_name1_arg, string to_name2_arg,
string to_subsample_name_arg, string from_declaration_type_arg,
string from_name1_arg, string from_name2_arg, string from_subsample_name_arg,
const SymbolTable& symbol_table_arg);
void get_base_name(const SymbolType symb_type, string& lhs_field) const;
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
......@@ -1040,18 +1157,14 @@ public:
class BasicOptionsStatement : public Statement
{
protected:
const string name;
const string subsample_name;
const string name, subsample_name;
const OptionsList options_list;
BasicOptionsStatement(string name_arg,
string subsample_name_arg,
OptionsList options_list_arg);
BasicOptionsStatement(string name_arg, string subsample_name_arg, OptionsList options_list_arg);
void get_base_name(const SymbolType symb_type, string& lhs_field) const;
void checkPass(ModFileStructure &mod_file_struct, WarningConsolidation &warnings) override;
void writeOptionsOutput(ostream& output, string& lhs_field, const string& name2) const;
void writeCommonOutput(ostream& output, const string& lhs_field) const;
void writeCommonOutputHelper(ostream& output, const string& field, const string& lhs_field) const;
bool is_structural_innovation(const SymbolType symb_type) const;
[[nodiscard]] bool is_structural_innovation(const SymbolType symb_type) const;
void writeOptionsIndex(ostream& output, const string& lhs_field) const;
void writeOutputHelper(ostream& output, const string& field, const string& lhs_field) const;
void writeJsonOptionsOutput(ostream& output) const;
......@@ -1069,10 +1182,9 @@ class StdOptionsStatement : public BasicOptionsStatement
{
private:
const SymbolTable& symbol_table;
public:
StdOptionsStatement(string name_arg,
string subsample_name_arg,
OptionsList options_list_arg,
StdOptionsStatement(string name_arg, string subsample_name_arg, OptionsList options_list_arg,
const SymbolTable& symbol_table_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -1083,11 +1195,10 @@ class CorrOptionsStatement : public BasicOptionsStatement
private:
const string name1;
const SymbolTable& symbol_table;
public:
CorrOptionsStatement(string name_arg1, string name_arg2,
string subsample_name_arg,
OptionsList options_list_arg,
const SymbolTable &symbol_table_arg);
CorrOptionsStatement(string name_arg1, string name_arg2, string subsample_name_arg,
OptionsList options_list_arg, const SymbolTable& symbol_table_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
......@@ -1096,25 +1207,15 @@ public:
class OptionsEqualStatement : public Statement
{
private:
const string to_declaration_type;
const string to_name1;
const string to_name2;
const string to_subsample_name;
const string from_declaration_type;
const string from_name1;
const string from_name2;
const string from_subsample_name;
const string to_declaration_type, to_name1, to_name2, to_subsample_name;
const string from_declaration_type, from_name1, from_name2, from_subsample_name;
const SymbolTable& symbol_table;
public:
OptionsEqualStatement(string to_declaration_type_arg,
string to_name1_arg,
string to_name2_arg,
string to_subsample_name_arg,
string from_declaration_type_arg,
string from_name1_arg,
string from_name2_arg,
string from_subsample_name_arg,
const SymbolTable &symbol_table_arg);
OptionsEqualStatement(string to_declaration_type_arg, string to_name1_arg, string to_name2_arg,
string to_subsample_name_arg, string from_declaration_type_arg,
string from_name1_arg, string from_name2_arg,
string from_subsample_name_arg, const SymbolTable& symbol_table_arg);
void get_base_name(const SymbolType symb_type, string& lhs_field) const;
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
......@@ -1132,74 +1233,110 @@ class Smoother2histvalStatement : public Statement
{
private:
const OptionsList options_list;
public:
explicit Smoother2histvalStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class GMMEstimationStatement : public Statement
class MethodOfMomentsStatement : public Statement
{
private:
const SymbolList symbol_list;
const OptionsList options_list;
public:
GMMEstimationStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
explicit MethodOfMomentsStatement(OptionsList options_list_arg);
void checkPass(ModFileStructure& mod_file_struct, WarningConsolidation& warnings) override;
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class SMMEstimationStatement : public Statement
class GenerateIRFsStatement : public Statement
{
public:
private:
const SymbolList symbol_list;
const OptionsList options_list;
const vector<string> generate_irf_names;
const vector<map<string, double>> generate_irf_elements;
public:
SMMEstimationStatement(SymbolList symbol_list_arg, OptionsList options_list_arg);
GenerateIRFsStatement(OptionsList options_list_arg, vector<string> generate_irf_names_arg,
vector<map<string, double>> generate_irf_elements_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class GenerateIRFsStatement : public Statement
class MatchedMomentsStatement : public Statement
{
public:
private:
const OptionsList options_list;
const vector<string> generate_irf_names;
const vector<map<string, double>> generate_irf_elements;
const SymbolTable& symbol_table;
public:
GenerateIRFsStatement(OptionsList options_list_arg,
vector<string> generate_irf_names_arg,
vector<map<string, double>> generate_irf_elements_arg);
/* Each moment is represented by a three vectors: symb_ids, lags, powers.
See the definition of ExprNode::matchMatchedMoment() for more details */
const vector<tuple<vector<int>, vector<int>, vector<int>>> moments;
MatchedMomentsStatement(const SymbolTable& symbol_table_arg,
vector<tuple<vector<int>, vector<int>, vector<int>>> moments_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class VarExpectationModelStatement : public Statement
class OccbinConstraintsStatement : public Statement
{
private:
DataTree data_tree;
public:
const string model_name;
// The tuple is (name, bind, relax, error_bind, error_relax) (where relax and error_{bind,relax}
// can be nullptr)
const vector<tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>> constraints;
OccbinConstraintsStatement(
const DataTree& data_tree_arg,
vector<tuple<string, BinaryOpNode*, BinaryOpNode*, expr_t, expr_t>> constraints_arg);
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;
};
class ResidStatement : public Statement
{
private:
expr_t expression;
const OptionsList options_list;
public:
const string aux_model_name, horizon;
const expr_t discount;
const SymbolTable &symbol_table;
// List of generated auxiliary param ids, in variable-major order
vector<int> aux_params_ids; // TODO: move this to some new VarModelTable object
explicit ResidStatement(OptionsList options_list_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
};
class MatchedIrfsStatement : public Statement
{
public:
// (endo name, exo name) → vector of (period start, period end, value, weight)
using matched_irfs_t = map<pair<string, string>, vector<tuple<int, int, expr_t, expr_t>>>;
MatchedIrfsStatement(matched_irfs_t values_weights_arg, bool overwrite_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
private:
vector<tuple<int, int, double>> vars_params_constants;
const matched_irfs_t values_weights;
const bool overwrite;
};
class MatchedIrfsWeightsStatement : public Statement
{
public:
VarExpectationModelStatement(string model_name_arg, expr_t expression_arg, string aux_model_name_arg,
string horizon_arg, expr_t discount_arg, const SymbolTable &symbol_table_arg);
void substituteUnaryOpNodes(const lag_equivalence_table_t &nodes, ExprNode::subst_table_t &subst_table);
void substituteDiff(const lag_equivalence_table_t &diff_table, ExprNode::subst_table_t &subst_table);
// Analyzes the linear combination contained in the 'expression' option
/* Must be called after substituteUnaryOpNodes() and substituteDiff() (in
that order) */
void matchExpression();
/* (endo1 name, period index or range for endo1, exo1 name, endo2 name, period index or range for
endo2, exo2 name) → weight */
using matched_irfs_weights_t = map<tuple<string, string, string, string, string, string>, expr_t>;
MatchedIrfsWeightsStatement(matched_irfs_weights_t weights_arg, bool overwrite_arg);
void writeOutput(ostream& output, const string& basename, bool minimal_workspace) const override;
void writeJsonOutput(ostream& output) const override;
private:
const matched_irfs_weights_t weights;
const bool overwrite;
};
#endif
/*
* Copyright © 2010-2017 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 <http://www.gnu.org/licenses/>.
*/
#ifndef _CONFIG_FILE_HH
#define _CONFIG_FILE_HH
#include <map>
#include <vector>
#include "WarningConsolidation.hh"
using namespace std;
using member_nodes_t = map<string, double>;
class Hook
{
public:
explicit Hook(string global_init_file_arg);
private:
map<string, string> hooks;
public:
inline map<string, string>
get_hooks() const
{
return hooks;
};
};
class Path
{
public:
explicit Path(vector<string> includepath_arg);
private:
map<string, vector<string>> paths;
public:
inline map<string, vector<string>>
get_paths() const
{
return paths;
};
};
class SlaveNode
{
friend class ConfigFile;
public:
SlaveNode(string computerName_arg, string port_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string userName_arg,
string password_arg, string remoteDrive_arg, string remoteDirectory_arg,
string dynarePath_arg, string matlabOctavePath_arg, bool singleCompThread_arg, int numberOfThreadsPerJob_arg,
string operatingSystem_arg);
protected:
const string computerName;
const string port;
int minCpuNbr;
int maxCpuNbr;
const string userName;
const string password;
const string remoteDrive;
const string remoteDirectory;
const string dynarePath;
const string matlabOctavePath;
const bool singleCompThread;
const int numberOfThreadsPerJob;
const string operatingSystem;
};
class Cluster
{
friend class ConfigFile;
public:
explicit Cluster(member_nodes_t member_nodes_arg);
protected:
member_nodes_t member_nodes;
};
//! The abstract representation of a "config" file
class ConfigFile
{
public:
ConfigFile(bool parallel_arg, bool parallel_test_arg, bool parallel_slave_open_mode_arg, string cluster_name);
private:
const bool parallel;
const bool parallel_test;
const bool parallel_slave_open_mode;
const string cluster_name;
string firstClusterName;
//! Hooks
vector<Hook> hooks;
//! Paths
vector<Path> paths;
//! Cluster Table
map<string, Cluster> clusters;
//! Node Map
map<string, SlaveNode> slave_nodes;
//! Add Hooks
void addHooksConfFileElement(string global_init_file);
//! Add Paths
void addPathsConfFileElement(vector<string> includepath);
//! Add a SlaveNode or a Cluster object
void addParallelConfFileElement(bool inNode, bool inCluster, const member_nodes_t &member_nodes, const string &name,
const string &computerName, const string &port, int minCpuNbr, int maxCpuNbr, const string &userName,
const string &password, const string &remoteDrive, const string &remoteDirectory,
const string &dynarePath, const string &matlabOctavePath, bool singleCompThread, int numberOfThreadsPerJob,
const string &operatingSystem);
public:
//! Parse config file
void getConfigFileInfo(const string &parallel_config_file);
//! Check Pass
void checkPass(WarningConsolidation &warnings) const;
//! Check Pass
void transformPass();
//! Get Path Info
vector<filesystem::path> getIncludePaths() const;
//! Write any hooks
void writeHooks(ostream &output) const;
//! Create options_.parallel structure, write options
void writeCluster(ostream &output) const;
//! Close slave nodes if needed
void writeEndParallel(ostream &output) const;
};
#endif // ! CONFIG_FILE_HH
/*
* Copyright © 2010-2019 Dynare Team
* Copyright © 2010-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -14,37 +14,28 @@
* 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 <http://www.gnu.org/licenses/>.
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <fstream>
#include <iostream>
#include <utility>
#include <vector>
#include <filesystem>
#include "ConfigFile.hh"
#ifdef _WIN32
# include <shlobj.h>
#endif
#include "Configuration.hh"
#include "DataTree.hh" // For strsplit()
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#include <boost/algorithm/string/trim.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/trim.hpp>
#include <boost/tokenizer.hpp>
#pragma GCC diagnostic pop
using namespace std;
Hook::Hook(string global_init_file_arg)
{
if (global_init_file_arg.empty())
{
cerr << "ERROR: The Hook must have a Global Initialization File argument." << endl;
exit(EXIT_FAILURE);
}
hooks["global_init_file"] = move(global_init_file_arg);
}
Path::Path(vector<string> includepath_arg)
Configuration::Path::Path(vector<string> includepath_arg)
{
if (includepath_arg.empty())
{
......@@ -54,9 +45,12 @@ Path::Path(vector<string> includepath_arg)
paths["include"] = move(includepath_arg);
}
SlaveNode::SlaveNode(string computerName_arg, string port_arg, int minCpuNbr_arg, int maxCpuNbr_arg, string userName_arg,
string password_arg, string remoteDrive_arg, string remoteDirectory_arg,
string dynarePath_arg, string matlabOctavePath_arg, bool singleCompThread_arg, int numberOfThreadsPerJob_arg,
Configuration::FollowerNode::FollowerNode(string computerName_arg, string port_arg,
int minCpuNbr_arg, int maxCpuNbr_arg, string userName_arg,
string password_arg, string remoteDrive_arg,
string remoteDirectory_arg, string programPath_arg,
string programConfig_arg, string matlabOctavePath_arg,
bool singleCompThread_arg, int numberOfThreadsPerJob_arg,
string operatingSystem_arg) :
computerName {move(computerName_arg)},
port {move(port_arg)},
......@@ -66,7 +60,8 @@ SlaveNode::SlaveNode(string computerName_arg, string port_arg, int minCpuNbr_arg
password {move(password_arg)},
remoteDrive {move(remoteDrive_arg)},
remoteDirectory {move(remoteDirectory_arg)},
dynarePath{move(dynarePath_arg)},
programPath {move(programPath_arg)},
programConfig {move(programConfig_arg)},
matlabOctavePath {move(matlabOctavePath_arg)},
singleCompThread {singleCompThread_arg},
numberOfThreadsPerJob {numberOfThreadsPerJob_arg},
......@@ -79,14 +74,15 @@ SlaveNode::SlaveNode(string computerName_arg, string port_arg, int minCpuNbr_arg
}
if (!operatingSystem.empty())
if (operatingSystem.compare("windows") != 0 && operatingSystem.compare("unix") != 0)
if (operatingSystem != "windows" && operatingSystem != "unix")
{
cerr << "ERROR: The OperatingSystem must be either 'unix' or 'windows' (Case Sensitive)." << endl;
cerr << "ERROR: The OperatingSystem must be either 'unix' or 'windows' (Case Sensitive)."
<< endl;
exit(EXIT_FAILURE);
}
}
Cluster::Cluster(member_nodes_t member_nodes_arg) :
Configuration::Cluster::Cluster(member_nodes_t member_nodes_arg) :
member_nodes {move(member_nodes_arg)}
{
if (member_nodes.empty())
......@@ -96,90 +92,82 @@ Cluster::Cluster(member_nodes_t member_nodes_arg) :
}
}
ConfigFile::ConfigFile(bool parallel_arg, bool parallel_test_arg,
bool parallel_slave_open_mode_arg, string cluster_name_arg) :
parallel{parallel_arg}, parallel_test{parallel_test_arg},
parallel_slave_open_mode{parallel_slave_open_mode_arg}, cluster_name{move(cluster_name_arg)}
Configuration::Configuration(bool parallel_arg, bool parallel_test_arg,
bool parallel_follower_open_mode_arg, bool parallel_use_psexec_arg,
string cluster_name_arg) :
parallel {parallel_arg},
parallel_test {parallel_test_arg},
parallel_follower_open_mode {parallel_follower_open_mode_arg},
parallel_use_psexec {parallel_use_psexec_arg},
cluster_name {move(cluster_name_arg)}
{
}
void
ConfigFile::getConfigFileInfo(const string &config_file)
Configuration::getConfigFileInfo(const filesystem::path& conffile_option,
WarningConsolidation& warnings)
{
using namespace boost;
ifstream configFile;
filesystem::path config_file {conffile_option};
if (config_file.empty())
{
string defaultConfigFile;
// Test OS and try to open default file
#if defined(_WIN32) || defined(__CYGWIN32__)
if (getenv("APPDATA") == nullptr)
{
if (parallel || parallel_test)
cerr << "ERROR: ";
else
cerr << "WARNING: ";
cerr << "APPDATA environment variable not found." << endl;
config_file = findConfigFile("dynare.ini");
if (parallel || parallel_test)
exit(EXIT_FAILURE);
}
else
if (config_file.empty()) // Try old default location (Dynare ⩽ 5) for backward compatibility
{
defaultConfigFile += getenv("APPDATA");
defaultConfigFile += "\\dynare.ini";
}
filesystem::path old_default_config_file;
#ifdef _WIN32
array<wchar_t, MAX_PATH + 1> appdata;
if (SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY, nullptr,
SHGFP_TYPE_CURRENT, appdata.data())
== S_OK)
old_default_config_file = filesystem::path {appdata.data()} / "dynare.ini";
#else
if (getenv("HOME") == nullptr)
if (auto home = getenv("HOME"); home)
old_default_config_file = filesystem::path {home} / ".dynare";
#endif
if (!old_default_config_file.empty() && exists(old_default_config_file))
{
if (parallel || parallel_test)
cerr << "ERROR: ";
else
cerr << "WARNING: ";
cerr << "HOME environment variable not found." << endl;
if (parallel || parallel_test)
exit(EXIT_FAILURE);
warnings << "WARNING: the location " << old_default_config_file.string()
<< " for the configuration file is obsolete; please see the reference"
<< " manual for the new location." << endl;
config_file = old_default_config_file;
}
else
{
defaultConfigFile += getenv("HOME");
defaultConfigFile += "/.dynare";
}
#endif
configFile.open(defaultConfigFile, fstream::in);
if (!configFile.is_open())
}
if (config_file.empty())
{
if (parallel || parallel_test)
{
cerr << "ERROR: Could not open the default config file (" << defaultConfigFile << ")" << endl;
cerr << "ERROR: the parallel or parallel_test option was passed but no configuration "
<< "file was found" << endl;
exit(EXIT_FAILURE);
}
else
return;
}
else
{
ifstream configFile;
configFile.open(config_file, fstream::in);
if (!configFile.is_open())
{
cerr << "ERROR: Couldn't open file " << config_file << endl;;
cerr << "ERROR: Couldn't open configuration file " << config_file.string() << endl;
exit(EXIT_FAILURE);
}
}
string name, computerName, port, userName, password, remoteDrive,
remoteDirectory, dynarePath, matlabOctavePath, operatingSystem,
global_init_file;
string name, computerName, port, userName, password, remoteDrive, remoteDirectory, programPath,
programConfig, matlabOctavePath, operatingSystem;
vector<string> includepath;
int minCpuNbr {0}, maxCpuNbr {0};
int numberOfThreadsPerJob {1};
bool singleCompThread {false};
member_nodes_t member_nodes;
bool inHooks{false};
bool inNode{false};
bool inCluster{false};
bool inPaths{false};
bool inHooks {false}, inNode {false}, inCluster {false}, inPaths {false};
while (configFile.good())
{
......@@ -189,41 +177,34 @@ ConfigFile::getConfigFileInfo(const string &config_file)
if (line.empty() || !line.compare(0, 1, "#"))
continue;
if (!line.compare("[node]")
|| !line.compare("[cluster]")
|| !line.compare("[hooks]")
|| !line.compare("[paths]"))
if (line == "[node]" || line == "[cluster]" || line == "[hooks]" || line == "[paths]")
{
if (!global_init_file.empty())
// we were just in [hooks]
addHooksConfFileElement(global_init_file);
else if (!includepath.empty())
if (!includepath.empty())
// we were just in [paths]
addPathsConfFileElement(includepath);
else
// we were just in [node] or [cluster]
addParallelConfFileElement(inNode, inCluster, member_nodes, name,
computerName, port, minCpuNbr, maxCpuNbr, userName,
password, remoteDrive, remoteDirectory,
dynarePath, matlabOctavePath, singleCompThread, numberOfThreadsPerJob,
operatingSystem);
addParallelConfFileElement(
inNode, inCluster, member_nodes, name, computerName, port, minCpuNbr, maxCpuNbr,
userName, password, remoteDrive, remoteDirectory, programPath, programConfig,
matlabOctavePath, singleCompThread, numberOfThreadsPerJob, operatingSystem);
//! Reset communication vars / option defaults
if (!line.compare("[hooks]"))
if (line == "[hooks]")
{
inHooks = true;
inNode = false;
inCluster = false;
inPaths = false;
}
else if (!line.compare("[node]"))
else if (line == "[node]")
{
inHooks = false;
inNode = true;
inCluster = false;
inPaths = false;
}
else if (!line.compare("[paths]"))
else if (line == "[paths]")
{
inHooks = false;
inNode = false;
......@@ -238,9 +219,8 @@ ConfigFile::getConfigFileInfo(const string &config_file)
inPaths = false;
}
name = userName = computerName = port = password = remoteDrive
= remoteDirectory = dynarePath = matlabOctavePath
= operatingSystem = global_init_file = "";
name = userName = computerName = port = password = remoteDrive = remoteDirectory
= programPath = programConfig = matlabOctavePath = operatingSystem = "";
includepath.clear();
minCpuNbr = maxCpuNbr = 0;
numberOfThreadsPerJob = 1;
......@@ -253,28 +233,32 @@ ConfigFile::getConfigFileInfo(const string &config_file)
split(tokenizedLine, line, is_any_of("="));
if (tokenizedLine.size() != 2)
{
cerr << "ERROR (in config file): Options should be formatted as 'option = value'." << endl;
cerr << "ERROR (in config file): Options should be formatted as 'option = value'."
<< endl;
exit(EXIT_FAILURE);
}
trim(tokenizedLine.front());
trim(tokenizedLine.back());
if (inHooks)
if (!tokenizedLine.front().compare("GlobalInitFile"))
if (tokenizedLine.front() == "GlobalInitFile")
if (global_init_file.empty())
global_init_file = tokenizedLine.back();
else
{
cerr << "ERROR: May not have more than one GlobalInitFile option in [hooks] block." << endl;
cerr
<< "ERROR: May not have more than one GlobalInitFile option in [hooks] block."
<< endl;
exit(EXIT_FAILURE);
}
else
{
cerr << "ERROR: Unrecognized option " << tokenizedLine.front() << " in [hooks] block." << endl;
cerr << "ERROR: Unrecognized option " << tokenizedLine.front()
<< " in [hooks] block." << endl;
exit(EXIT_FAILURE);
}
else if (inPaths)
if (!tokenizedLine.front().compare("Include"))
if (tokenizedLine.front() == "Include")
if (includepath.empty())
{
vector<string> tokenizedPath;
......@@ -288,18 +272,19 @@ ConfigFile::getConfigFileInfo(const string &config_file)
}
else
{
cerr << "ERROR: May not have more than one Include option in [paths] block." << endl;
cerr << "ERROR: May not have more than one Include option in [paths] block."
<< endl;
exit(EXIT_FAILURE);
}
else
{
cerr << "ERROR: Unrecognized option " << tokenizedLine.front() << " in [paths] block." << endl;
cerr << "ERROR: Unrecognized option " << tokenizedLine.front()
<< " in [paths] block." << endl;
exit(EXIT_FAILURE);
}
else
if (!tokenizedLine.front().compare("Name"))
else if (tokenizedLine.front() == "Name")
name = tokenizedLine.back();
else if (!tokenizedLine.front().compare("CPUnbr"))
else if (tokenizedLine.front() == "CPUnbr")
{
vector<string> tokenizedCpuNbr;
split(tokenizedCpuNbr, tokenizedLine.back(), is_any_of(":"));
......@@ -310,8 +295,7 @@ ConfigFile::getConfigFileInfo(const string &config_file)
minCpuNbr = 1;
maxCpuNbr = stoi(tokenizedCpuNbr.front());
}
else if (tokenizedCpuNbr.size() == 2
&& tokenizedCpuNbr[0].at(0) == '['
else if (tokenizedCpuNbr.size() == 2 && tokenizedCpuNbr[0].at(0) == '['
&& tokenizedCpuNbr[1].at(tokenizedCpuNbr[1].size() - 1) == ']')
{
tokenizedCpuNbr[0].erase(0, 1);
......@@ -344,50 +328,53 @@ ConfigFile::getConfigFileInfo(const string &config_file)
minCpuNbr = tmp;
}
}
else if (!tokenizedLine.front().compare("Port"))
else if (tokenizedLine.front() == "Port")
port = tokenizedLine.back();
else if (!tokenizedLine.front().compare("ComputerName"))
else if (tokenizedLine.front() == "ComputerName")
computerName = tokenizedLine.back();
else if (!tokenizedLine.front().compare("UserName"))
else if (tokenizedLine.front() == "UserName")
userName = tokenizedLine.back();
else if (!tokenizedLine.front().compare("Password"))
else if (tokenizedLine.front() == "Password")
password = tokenizedLine.back();
else if (!tokenizedLine.front().compare("RemoteDrive"))
else if (tokenizedLine.front() == "RemoteDrive")
remoteDrive = tokenizedLine.back();
else if (!tokenizedLine.front().compare("RemoteDirectory"))
else if (tokenizedLine.front() == "RemoteDirectory")
remoteDirectory = tokenizedLine.back();
else if (!tokenizedLine.front().compare("DynarePath"))
dynarePath = tokenizedLine.back();
else if (!tokenizedLine.front().compare("MatlabOctavePath"))
else if (tokenizedLine.front() == "DynarePath" || tokenizedLine.front() == "ProgramPath")
programPath = tokenizedLine.back();
else if (tokenizedLine.front() == "ProgramConfig")
programConfig = tokenizedLine.back();
else if (tokenizedLine.front() == "MatlabOctavePath")
matlabOctavePath = tokenizedLine.back();
else if (!tokenizedLine.front().compare("NumberOfThreadsPerJob"))
else if (tokenizedLine.front() == "NumberOfThreadsPerJob")
numberOfThreadsPerJob = stoi(tokenizedLine.back());
else if (!tokenizedLine.front().compare("SingleCompThread"))
if (tokenizedLine.back().compare("true") == 0)
else if (tokenizedLine.front() == "SingleCompThread")
if (tokenizedLine.back() == "true")
singleCompThread = true;
else if (tokenizedLine.back().compare("false") == 0)
else if (tokenizedLine.back() == "false")
singleCompThread = false;
else
{
cerr << "ERROR (in config file): The value passed to SingleCompThread may only be 'true' or 'false'." << endl;
cerr << "ERROR (in config file): The value passed to SingleCompThread may only be "
"'true' or 'false'."
<< endl;
exit(EXIT_FAILURE);
}
else if (!tokenizedLine.front().compare("OperatingSystem"))
else if (tokenizedLine.front() == "OperatingSystem")
operatingSystem = tokenizedLine.back();
else if (!tokenizedLine.front().compare("Members"))
else if (tokenizedLine.front() == "Members")
{
char_separator<char> sep(" ,;", "()", drop_empty_tokens);
tokenizer<char_separator<char>> tokens(tokenizedLine.back(), sep);
bool begin_weight = false;
char_separator sep(" ,;", "()", drop_empty_tokens);
tokenizer tokens(tokenizedLine.back(), sep);
string node_name;
for (const auto & token : tokens)
for (bool begin_weight {false}; const auto& token : tokens)
{
if (token.compare("(") == 0)
if (token == "(")
{
begin_weight = true;
continue;
}
else if (token.compare(")") == 0)
else if (token == ")")
{
node_name.clear();
begin_weight = false;
......@@ -397,13 +384,17 @@ ConfigFile::getConfigFileInfo(const string &config_file)
if (!begin_weight)
{
if (!node_name.empty())
if (member_nodes.find(node_name) != member_nodes.end())
{
cerr << "ERROR (in config file): Node entered twice in specification of cluster." << endl;
if (member_nodes.contains(node_name))
{
cerr << "ERROR (in config file): Node entered twice in specification "
"of cluster."
<< endl;
exit(EXIT_FAILURE);
}
else
member_nodes[node_name] = 1.0;
}
node_name = token;
}
else
......@@ -412,62 +403,56 @@ ConfigFile::getConfigFileInfo(const string &config_file)
auto weight = stod(token);
if (weight <= 0)
{
cerr << "ERROR (in config file): Misspecification of weights passed to Members option." << endl;
cerr << "ERROR (in config file): Misspecification of weights passed to "
"Members option."
<< endl;
exit(EXIT_FAILURE);
}
member_nodes[node_name] = weight;
}
catch (const invalid_argument&)
{
cerr << "ERROR (in config file): Misspecification of weights passed to Members option." << endl;
cerr << "ERROR (in config file): Misspecification of weights passed to "
"Members option."
<< endl;
exit(EXIT_FAILURE);
}
}
if (!node_name.empty())
if (member_nodes.find(node_name) == member_nodes.end())
{
if (!member_nodes.contains(node_name))
member_nodes[node_name] = 1.0;
else
{
cerr << "ERROR (in config file): Node entered twice in specification of cluster." << endl;
cerr << "ERROR (in config file): Node entered twice in specification of "
"cluster."
<< endl;
exit(EXIT_FAILURE);
}
}
}
else
{
cerr << "ERROR (in config file): Option " << tokenizedLine.front() << " is invalid." << endl;
cerr << "ERROR (in config file): Option " << tokenizedLine.front() << " is invalid."
<< endl;
exit(EXIT_FAILURE);
}
}
}
if (!global_init_file.empty())
addHooksConfFileElement(global_init_file);
else if (!includepath.empty())
if (!includepath.empty())
addPathsConfFileElement(includepath);
else
addParallelConfFileElement(inNode, inCluster, member_nodes, name,
computerName, port, minCpuNbr, maxCpuNbr, userName,
password, remoteDrive, remoteDirectory,
dynarePath, matlabOctavePath, singleCompThread, numberOfThreadsPerJob,
operatingSystem);
addParallelConfFileElement(inNode, inCluster, member_nodes, name, computerName, port, minCpuNbr,
maxCpuNbr, userName, password, remoteDrive, remoteDirectory,
programPath, programConfig, matlabOctavePath, singleCompThread,
numberOfThreadsPerJob, operatingSystem);
configFile.close();
}
void
ConfigFile::addHooksConfFileElement(string global_init_file)
{
if (global_init_file.empty())
{
cerr << "ERROR: The global initialization file must be passed to the GlobalInitFile option." << endl;
exit(EXIT_FAILURE);
}
else
hooks.emplace_back(move(global_init_file));
}
void
ConfigFile::addPathsConfFileElement(vector<string> includepath)
Configuration::addPathsConfFileElement(vector<string> includepath)
{
if (includepath.empty())
{
......@@ -479,11 +464,15 @@ ConfigFile::addPathsConfFileElement(vector<string> includepath)
}
void
ConfigFile::addParallelConfFileElement(bool inNode, bool inCluster, const member_nodes_t &member_nodes, const string &name,
const string &computerName, const string &port, int minCpuNbr, int maxCpuNbr, const string &userName,
const string &password, const string &remoteDrive, const string &remoteDirectory,
const string &dynarePath, const string &matlabOctavePath, bool singleCompThread, int numberOfThreadsPerJob,
const string &operatingSystem)
Configuration::addParallelConfFileElement(bool inNode, bool inCluster,
const member_nodes_t& member_nodes, const string& name,
const string& computerName, const string& port,
int minCpuNbr, int maxCpuNbr, const string& userName,
const string& password, const string& remoteDrive,
const string& remoteDirectory, const string& programPath,
const string& programConfig,
const string& matlabOctavePath, bool singleCompThread,
int numberOfThreadsPerJob, const string& operatingSystem)
{
//! ADD NODE
if (inNode)
......@@ -492,28 +481,27 @@ ConfigFile::addParallelConfFileElement(bool inNode, bool inCluster, const member
cerr << "Invalid option passed to [node]." << endl;
exit(EXIT_FAILURE);
}
else
if (name.empty() || slave_nodes.find(name) != slave_nodes.end())
else if (name.empty() || follower_nodes.contains(name))
{
cerr << "ERROR: Every node must be assigned a unique name." << endl;
exit(EXIT_FAILURE);
}
else
slave_nodes.emplace(name, SlaveNode{computerName, port, minCpuNbr, maxCpuNbr, userName,
password, remoteDrive, remoteDirectory, dynarePath,
follower_nodes.try_emplace(name, computerName, port, minCpuNbr, maxCpuNbr, userName, password,
remoteDrive, remoteDirectory, programPath, programConfig,
matlabOctavePath, singleCompThread, numberOfThreadsPerJob,
operatingSystem});
operatingSystem);
//! ADD CLUSTER
else if (inCluster)
if (minCpuNbr > 0 || maxCpuNbr > 0 || !userName.empty()
|| !password.empty() || !remoteDrive.empty() || !remoteDirectory.empty()
|| !dynarePath.empty() || !matlabOctavePath.empty() || !operatingSystem.empty())
{
if (minCpuNbr > 0 || maxCpuNbr > 0 || !userName.empty() || !password.empty()
|| !remoteDrive.empty() || !remoteDirectory.empty() || !programPath.empty()
|| !programConfig.empty() || !matlabOctavePath.empty() || !operatingSystem.empty())
{
cerr << "Invalid option passed to [cluster]." << endl;
exit(EXIT_FAILURE);
}
else
if (name.empty() || clusters.find(name) != clusters.end())
else if (name.empty() || clusters.contains(name))
{
cerr << "ERROR: The cluster must be assigned a unique name." << endl;
exit(EXIT_FAILURE);
......@@ -522,107 +510,111 @@ ConfigFile::addParallelConfFileElement(bool inNode, bool inCluster, const member
{
if (clusters.empty())
firstClusterName = name;
clusters.emplace(name, Cluster{member_nodes});
clusters.emplace(name, member_nodes);
}
}
}
void
ConfigFile::checkPass(WarningConsolidation &warnings) const
{
bool global_init_file_declared = false;
for (const auto & hook : hooks)
{
for (const auto & mapit : hook.get_hooks())
if (mapit.first.compare("global_init_file") == 0)
if (global_init_file_declared == true)
Configuration::checkPass([[maybe_unused]] WarningConsolidation& warnings) const
{
cerr << "ERROR: Only one global initialization file may be provided." << endl;
exit(EXIT_FAILURE);
}
else
global_init_file_declared = true;
}
if (!parallel && !parallel_test)
return;
//! Check Slave Nodes
if (slave_nodes.empty())
//! Check Follower Nodes
if (follower_nodes.empty())
{
cerr << "ERROR: At least one node must be defined in the config file." << endl;
exit(EXIT_FAILURE);
}
for (const auto & slave_node : slave_nodes)
for (const auto& follower_node : follower_nodes)
{
#if !defined(_WIN32) && !defined(__CYGWIN32__)
// For Linux/Mac, check that cpuNbr starts at 0
if (slave_node.second.minCpuNbr != 0)
if (follower_node.second.minCpuNbr != 0)
warnings << "WARNING: On Unix-based operating systems, you cannot specify the CPU that is "
<< "used in parallel processing. This will be adjusted for you such that the "
<< "same number of CPUs are used." << endl;
#endif
if (!slave_node.second.port.empty())
if (!follower_node.second.port.empty())
try
{
stoi(slave_node.second.port);
stoi(follower_node.second.port);
}
catch (const invalid_argument&)
{
cerr << "ERROR (node " << slave_node.first << "): the port must be an integer." << endl;
cerr << "ERROR (node " << follower_node.first << "): the port must be an integer."
<< endl;
exit(EXIT_FAILURE);
}
if (!slave_node.second.computerName.compare("localhost")) // We are working locally
if (follower_node.second.computerName == "localhost") // We are working locally
{
if (!slave_node.second.remoteDrive.empty())
if (!follower_node.second.remoteDrive.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the RemoteDrive option may not be passed for a local node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the RemoteDrive option may not be passed for a local node." << endl;
exit(EXIT_FAILURE);
}
if (!slave_node.second.remoteDirectory.empty())
if (!follower_node.second.remoteDirectory.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the RemoteDirectory option may not be passed for a local node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the RemoteDirectory option may not be passed for a local node." << endl;
exit(EXIT_FAILURE);
}
}
else
{
if (slave_node.second.userName.empty())
if (follower_node.second.userName.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the UserName option must be passed for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the UserName option must be passed for every remote node." << endl;
exit(EXIT_FAILURE);
}
if (slave_node.second.operatingSystem.compare("windows") == 0)
if (follower_node.second.operatingSystem == "windows")
{
if (slave_node.second.password.empty())
if (follower_node.second.password.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the Password option must be passed under Windows for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the Password option must be passed under Windows for every remote "
"node."
<< endl;
exit(EXIT_FAILURE);
}
if (slave_node.second.remoteDrive.empty())
if (follower_node.second.remoteDrive.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the RemoteDrive option must be passed under Windows for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the RemoteDrive option must be passed under Windows for every remote "
"node."
<< endl;
exit(EXIT_FAILURE);
}
}
#if defined(_WIN32) || defined(__CYGWIN32__)
if (slave_node.second.operatingSystem.empty())
if (follower_node.second.operatingSystem.empty())
{
if (slave_node.second.password.empty())
if (follower_node.second.password.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the Password option must be passed under Windows for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the Password option must be passed under Windows for every remote "
"node."
<< endl;
exit(EXIT_FAILURE);
}
if (slave_node.second.remoteDrive.empty())
if (follower_node.second.remoteDrive.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the RemoteDrive option must be passed under Windows for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the RemoteDrive option must be passed under Windows for every remote "
"node."
<< endl;
exit(EXIT_FAILURE);
}
}
#endif
if (slave_node.second.remoteDirectory.empty())
if (follower_node.second.remoteDirectory.empty())
{
cerr << "ERROR (node " << slave_node.first << "): the RemoteDirectory must be specified for every remote node." << endl;
cerr << "ERROR (node " << follower_node.first
<< "): the RemoteDirectory must be specified for every remote node." << endl;
exit(EXIT_FAILURE);
}
}
......@@ -635,30 +627,38 @@ ConfigFile::checkPass(WarningConsolidation &warnings) const
exit(EXIT_FAILURE);
}
if (!cluster_name.empty() && clusters.find(cluster_name) == clusters.end())
if (!cluster_name.empty() && !clusters.contains(cluster_name))
{
cerr << "ERROR: Cluster Name " << cluster_name << " was not found in the config file." << endl;
cerr << "ERROR: Cluster Name " << cluster_name << " was not found in the config file."
<< endl;
exit(EXIT_FAILURE);
}
for (const auto& cluster : clusters)
for (const auto& itmn : cluster.second.member_nodes)
if (slave_nodes.find(itmn.first) == slave_nodes.end())
if (!follower_nodes.contains(itmn.first))
{
cerr << "Error: node " << itmn.first << " specified in cluster " << cluster.first << " was not found" << endl;
cerr << "Error: node " << itmn.first << " specified in cluster " << cluster.first
<< " was not found" << endl;
exit(EXIT_FAILURE);
}
}
void
ConfigFile::transformPass()
Configuration::transformPass()
{
/* If the user did not specify the GlobalInitFile option, use global_init.m in configuration
directory if it exists */
if (auto default_global_init_file = findConfigFile("global_init.m");
global_init_file.empty() && !default_global_init_file.empty())
global_init_file = default_global_init_file.string();
if (!parallel && !parallel_test)
return;
#if !defined(_WIN32) && !defined(__CYGWIN32__)
// For Linux/Mac, check that cpuNbr starts at 0
for (auto & it : slave_nodes)
for (auto& it : follower_nodes)
if (it.second.minCpuNbr != 0)
{
it.second.maxCpuNbr = it.second.maxCpuNbr - it.second.minCpuNbr;
......@@ -666,109 +666,142 @@ ConfigFile::transformPass()
}
#endif
map<string, Cluster>::iterator cluster_it;
if (cluster_name.empty())
cluster_it = clusters.find(firstClusterName);
else
cluster_it = clusters.find(cluster_name);
auto& cluster = cluster_name.empty() ? clusters.at(firstClusterName) : clusters.at(cluster_name);
double weight_denominator {0.0};
for (const auto & it : cluster_it->second.member_nodes)
weight_denominator += it.second;
for (const auto& [name, weight] : cluster.member_nodes)
weight_denominator += weight;
for (auto & member_node : cluster_it->second.member_nodes)
member_node.second /= weight_denominator;
for (auto& [name, weight] : cluster.member_nodes)
weight /= weight_denominator;
}
vector<filesystem::path>
ConfigFile::getIncludePaths() const
Configuration::getIncludePaths() const
{
vector<filesystem::path> include_paths;
for (auto path : paths)
for (const auto& path : paths)
for (const auto& mapit : path.get_paths())
for (const auto& vecit : mapit.second)
include_paths.push_back(vecit);
include_paths.emplace_back(vecit);
return include_paths;
}
void
ConfigFile::writeHooks(ostream &output) const
Configuration::writeHooks(ostream& output) const
{
for (auto hook : hooks)
for (const auto & mapit : hook.get_hooks())
output << "options_." << mapit.first << " = '" << mapit.second << "';" << endl;
if (!global_init_file.empty())
output << "options_.global_init_file = '" << global_init_file << "';" << endl;
}
void
ConfigFile::writeCluster(ostream &output) const
Configuration::writeCluster(ostream& output) const
{
if (!parallel && !parallel_test)
return;
map<string, Cluster>::const_iterator cluster_it;
if (cluster_name.empty())
cluster_it = clusters.find(firstClusterName);
else
cluster_it = clusters.find(cluster_name);
const auto& cluster
= cluster_name.empty() ? clusters.at(firstClusterName) : clusters.at(cluster_name);
int i{1};
for (const auto & slave_node : slave_nodes)
for (int i {1}; const auto& [name, node] : follower_nodes)
{
bool slave_node_in_member_nodes = false;
for (const auto & itmn : cluster_it->second.member_nodes)
if (!slave_node.first.compare(itmn.first))
slave_node_in_member_nodes = true;
if (!slave_node_in_member_nodes)
continue;
if (!cluster.member_nodes.contains(name))
continue; // Skip nodes not in the selected cluster
output << "options_.parallel";
if (i > 1)
output << "(" << i << ")";
i++;
output << " = struct('Local', ";
if (slave_node.second.computerName.compare("localhost"))
output << "0, ";
else
output << "1, ";
output << "'ComputerName', '" << slave_node.second.computerName << "', "
<< "'Port', '" << slave_node.second.port << "', "
<< "'CPUnbr', [" << slave_node.second.minCpuNbr << ":" << slave_node.second.maxCpuNbr << "], "
<< "'UserName', '" << slave_node.second.userName << "', "
<< "'Password', '" << slave_node.second.password << "', "
<< "'RemoteDrive', '" << slave_node.second.remoteDrive << "', "
<< "'RemoteDirectory', '" << slave_node.second.remoteDirectory << "', "
<< "'DynarePath', '" << slave_node.second.dynarePath << "', "
<< "'MatlabOctavePath', '" << slave_node.second.matlabOctavePath << "', "
<< "'OperatingSystem', '" << slave_node.second.operatingSystem << "', "
<< "'NodeWeight', '" << (cluster_it->second.member_nodes.find(slave_node.first))->second << "', "
<< "'NumberOfThreadsPerJob', " << slave_node.second.numberOfThreadsPerJob << ", ";
if (slave_node.second.singleCompThread)
output << "'SingleCompThread', 'true');" << endl;
else
output << "'SingleCompThread', 'false');" << endl;
}
if (parallel_slave_open_mode)
output << " = struct('Local', " << noboolalpha << (node.computerName == "localhost") << ", "
<< "'ComputerName', '" << node.computerName << "', "
<< "'Port', '" << node.port << "', "
<< "'CPUnbr', [" << node.minCpuNbr << ":" << node.maxCpuNbr << "], "
<< "'UserName', '" << node.userName << "', "
<< "'Password', '" << node.password << "', "
<< "'RemoteDrive', '" << node.remoteDrive << "', "
<< "'RemoteDirectory', '" << node.remoteDirectory
<< "', "
// The following should be switched back to “ProgramPath” once we move to Dragonfly
<< "'DynarePath', '" << node.programPath << "', "
<< "'ProgramConfig', '" << node.programConfig << "', "
<< "'MatlabOctavePath', '" << node.matlabOctavePath << "', "
<< "'OperatingSystem', '" << node.operatingSystem << "', "
<< "'NodeWeight', '" << cluster.member_nodes.at(name) << "', "
<< "'NumberOfThreadsPerJob', " << node.numberOfThreadsPerJob << ", "
<< "'SingleCompThread', '" << boolalpha << node.singleCompThread << "');" << endl;
}
// Default values for the following two are both in DynareMain.cc and
// matlab/default_option_values.m
if (parallel_follower_open_mode)
output << "options_.parallel_info.leaveSlaveOpen = 1;" << endl;
if (!parallel_use_psexec)
output << "options_.parallel_info.use_psexec = false;" << endl;
output << "options_.parallel_info.console_mode= isoctave;" << endl;
output << "InitializeComputationalEnvironment();" << endl;
if (parallel_test)
output << "ErrorCode = AnalyseComputationalEnvironment(options_.parallel, options_.parallel_info);" << endl
<< "disp(['AnalyseComputationalEnvironment returned with Error Code: ' num2str(ErrorCode)]);" << endl
output
<< "ErrorCode = AnalyseComputationalEnvironment(options_.parallel, options_.parallel_info);"
<< endl
<< "disp(['AnalyseComputationalEnvironment returned with Error Code: ' "
"num2str(ErrorCode)]);"
<< endl
<< "diary off;" << endl
<< "return;" << endl;
}
void
ConfigFile::writeEndParallel(ostream &output) const
Configuration::writeEndParallel(ostream& output) const
{
if ((!parallel && !parallel_test) || !parallel_slave_open_mode)
if ((!parallel && !parallel_test) || !parallel_follower_open_mode)
return;
output << "if options_.parallel_info.leaveSlaveOpen == 1" << endl
<< " closeSlave(options_.parallel,options_.parallel_info.RemoteTmpFolder);" << endl
<< "end" << endl;
}
filesystem::path
Configuration::findConfigFile(const string& filename)
{
#ifdef _WIN32
array<wchar_t, MAX_PATH + 1> appdata;
if (SHGetFolderPathW(nullptr, CSIDL_APPDATA | CSIDL_FLAG_DONT_VERIFY, nullptr, SHGFP_TYPE_CURRENT,
appdata.data())
== S_OK)
{
filesystem::path candidate {filesystem::path {appdata.data()} / "dynare" / filename};
if (exists(candidate))
return candidate;
}
#else
filesystem::path xdg_config_home;
if (auto xdg_config_home_env = getenv("XDG_CONFIG_HOME"); xdg_config_home_env)
xdg_config_home = xdg_config_home_env;
if (auto home = getenv("HOME"); xdg_config_home.empty() && home)
xdg_config_home = filesystem::path {home} / ".config";
if (!xdg_config_home.empty())
{
filesystem::path candidate {xdg_config_home / "dynare" / filename};
if (exists(candidate))
return candidate;
}
string xdg_config_dirs;
if (auto xdg_config_dirs_env = getenv("XDG_CONFIG_DIRS"); xdg_config_dirs_env)
xdg_config_dirs = xdg_config_dirs_env;
if (xdg_config_dirs.empty())
xdg_config_dirs = "/etc/xdg";
for (const auto& dir : DataTree::strsplit(xdg_config_dirs, ':'))
{
filesystem::path candidate {filesystem::path {dir} / "dynare" / filename};
if (exists(candidate))
return candidate;
}
#endif
return {};
}
/*
* Copyright © 2010-2023 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 CONFIGURATION_HH
#define CONFIGURATION_HH
#include <filesystem>
#include <map>
#include <vector>
#include "WarningConsolidation.hh"
using namespace std;
/* The abstract representation of the configuration.
Merges information from the command-line and from the configuration file. */
class Configuration
{
public:
Configuration(bool parallel_arg, bool parallel_test_arg, bool parallel_follower_open_mode_arg,
bool parallel_use_psexec_arg, string cluster_name);
private:
using member_nodes_t = map<string, double>;
class Path
{
public:
explicit Path(vector<string> includepath_arg);
[[nodiscard]] map<string, vector<string>>
get_paths() const
{
return paths;
}
private:
map<string, vector<string>> paths;
};
struct FollowerNode
{
FollowerNode(string computerName_arg, string port_arg, int minCpuNbr_arg, int maxCpuNbr_arg,
string userName_arg, string password_arg, string remoteDrive_arg,
string remoteDirectory_arg, string programPath_arg, string programConfig_arg,
string matlabOctavePath_arg, bool singleCompThread_arg,
int numberOfThreadsPerJob_arg, string operatingSystem_arg);
const string computerName, port;
int minCpuNbr, maxCpuNbr;
const string userName, password;
const string remoteDrive, remoteDirectory;
const string programPath, programConfig, matlabOctavePath;
const bool singleCompThread;
const int numberOfThreadsPerJob;
const string operatingSystem;
};
struct Cluster
{
explicit Cluster(member_nodes_t member_nodes_arg);
member_nodes_t member_nodes;
};
const bool parallel, parallel_test, parallel_follower_open_mode, parallel_use_psexec;
const string cluster_name;
string firstClusterName;
//! Hooks
string global_init_file;
//! Paths
vector<Path> paths;
//! Cluster Table
map<string, Cluster> clusters;
//! Node Map
map<string, FollowerNode> follower_nodes;
//! Add Paths
void addPathsConfFileElement(vector<string> includepath);
//! Add a FollowerNode or a Cluster object
void addParallelConfFileElement(bool inNode, bool inCluster, const member_nodes_t& member_nodes,
const string& name, const string& computerName,
const string& port, int minCpuNbr, int maxCpuNbr,
const string& userName, const string& password,
const string& remoteDrive, const string& remoteDirectory,
const string& programPath, const string& programConfig,
const string& matlabOctavePath, bool singleCompThread,
int numberOfThreadsPerJob, const string& operatingSystem);
/* Given a filename (e.g. dynare.ini), looks for it in the configuration directory:
– if under Linux or macOS, look into the “dynare” subdirectory of the XDG
configuration directories (following the default values and the precedence order specified in
the XDG specification)
– if under Windows, look into %APPDATA%\dynare\
The returned path will be empty if the file is not found. */
[[nodiscard]] static filesystem::path findConfigFile(const string& filename);
public:
//! Parse config file
void getConfigFileInfo(const filesystem::path& conffile_option, WarningConsolidation& warnings);
//! Check Pass
void checkPass(WarningConsolidation& warnings) const;
//! Check Pass
void transformPass();
//! Get Path Info
[[nodiscard]] vector<filesystem::path> getIncludePaths() const;
//! Write any hooks
void writeHooks(ostream& output) const;
//! Create options_.parallel structure, write options
void writeCluster(ostream& output) const;
//! Close follower nodes if needed
void writeEndParallel(ostream& output) const;
};
#endif
/*
* Copyright © 2003-2019 Dynare Team
* Copyright © 2003-2025 Dynare Team
*
* This file is part of Dynare.
*
......@@ -14,18 +14,22 @@
* 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 <http://www.gnu.org/licenses/>.
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#include <cstdlib>
#include <algorithm>
#include <cassert>
#include <iostream>
#include <regex>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <iostream>
#include <iterator>
#include <ranges>
#include "DataTree.hh"
bool DataTree::no_commutativity = false;
void
DataTree::initConstants()
{
......@@ -43,13 +47,13 @@ DataTree::initConstants()
Pi = AddNonNegativeConstant("3.141592653589793");
}
DataTree::DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
DataTree::DataTree(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
bool is_dynamic_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();
......@@ -59,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 & it : d.local_variables_table)
local_variables_table[it.first] = it.second->clone(*this);
}
DataTree&
......@@ -80,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();
......@@ -90,6 +97,7 @@ DataTree::operator=(const DataTree &d)
external_function_node_map.clear();
var_expectation_node_map.clear();
pac_expectation_node_map.clear();
pac_target_nonstationary_node_map.clear();
first_deriv_external_function_node_map.clear();
second_deriv_external_function_node_map.clear();
......@@ -98,6 +106,14 @@ DataTree::operator=(const DataTree &d)
// Constants must be initialized first because they are used in some Add* methods
initConstants();
/* Model local variables must be next, because they can be evaluated in Add*
methods when the model equations are added. They need to be cloned in
order of appearance in the model block (hence with
local_variables_vector), because if there is a model_local_variable statement
the symbol IDs ordering may not be the right one (see dynare#1782) */
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);
......@@ -105,25 +121,21 @@ DataTree::operator=(const DataTree &d)
local_variables_vector = d.local_variables_vector;
for (const auto & it : d.local_variables_table)
local_variables_table[it.first] = it.second->clone(*this);
return *this;
}
expr_t
NumConstNode*
DataTree::AddNonNegativeConstant(const string& value)
{
int id = num_constants.AddNonNegativeConstant(value);
auto it = num_const_node_map.find(id);
if (it != num_const_node_map.end())
if (auto it = num_const_node_map.find(id); it != num_const_node_map.end())
return it->second;
auto sp = make_unique<NumConstNode>(*this, node_list.size(), id);
auto p = sp.get();
node_list.push_back(move(sp));
num_const_node_map[id] = p;
num_const_node_map.emplace(id, p);
return p;
}
......@@ -136,14 +148,13 @@ DataTree::AddVariable(int symb_id, int lag)
exit(EXIT_FAILURE);
}
auto it = variable_node_map.find({ symb_id, lag });
if (it != variable_node_map.end())
if (auto it = variable_node_map.find({symb_id, lag}); it != variable_node_map.end())
return it->second;
auto sp = make_unique<VariableNode>(*this, node_list.size(), symb_id, lag);
auto p = sp.get();
node_list.push_back(move(sp));
variable_node_map[{ symb_id, lag }] = p;
variable_node_map.try_emplace({symb_id, lag}, p);
return p;
}
......@@ -153,7 +164,8 @@ DataTree::getVariable(int symb_id, int lag) const
auto it = variable_node_map.find({symb_id, lag});
if (it == variable_node_map.end())
{
cerr << "DataTree::getVariable: unknown variable node for symb_id=" << symb_id << " and lag=" << lag << endl;
cerr << "DataTree::getVariable: unknown variable node for symb_id=" << symb_id
<< " and lag=" << lag << endl;
exit(EXIT_FAILURE);
}
return it->second;
......@@ -162,8 +174,8 @@ DataTree::getVariable(int symb_id, int lag) const
bool
DataTree::ParamUsedWithLeadLagInternal() const
{
for (const auto & it : variable_node_map)
if (symbol_table.getType(it.first.first) == SymbolType::parameter && it.first.second != 0)
for (const auto& [symb_lag, expr] : variable_node_map)
if (symbol_table.getType(symb_lag.first) == SymbolType::parameter && symb_lag.second != 0)
return true;
return false;
}
......@@ -171,32 +183,38 @@ DataTree::ParamUsedWithLeadLagInternal() const
expr_t
DataTree::AddPlus(expr_t iArg1, expr_t iArg2)
{
if (iArg1 != Zero && iArg2 != Zero)
{
if (iArg2 == Zero)
return iArg1;
if (iArg1 == Zero)
return iArg2;
// Simplify x+(-y) in x-y
auto uarg2 = dynamic_cast<UnaryOpNode *>(iArg2);
if (uarg2 != nullptr && uarg2->op_code == UnaryOpcode::uminus)
if (auto uarg2 = dynamic_cast<UnaryOpNode*>(iArg2);
uarg2 && uarg2->op_code == UnaryOpcode::uminus)
return AddMinus(iArg1, uarg2->arg);
// Simplify (-x)+y in y-x
auto uarg1 = dynamic_cast<UnaryOpNode *>(iArg1);
if (uarg1 != nullptr && uarg1->op_code == UnaryOpcode::uminus)
if (auto uarg1 = dynamic_cast<UnaryOpNode*>(iArg1);
uarg1 && uarg1->op_code == UnaryOpcode::uminus)
return AddMinus(iArg2, uarg1->arg);
// Simplify (x-y)+y in x
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::minus && barg1->arg2 == iArg2)
return barg1->arg1;
// Simplify y+(x-y) in x
if (auto barg2 = dynamic_cast<BinaryOpNode*>(iArg2);
barg2 && barg2->op_code == BinaryOpcode::minus && barg2->arg2 == iArg1)
return barg2->arg1;
// To treat commutativity of "+"
// Nodes iArg1 and iArg2 are sorted by index
if (iArg1->idx > iArg2->idx)
if (iArg1->idx > iArg2->idx && !no_commutativity) // NOLINT(clang-analyzer-core.NullDereference)
swap(iArg1, iArg2);
return AddBinaryOp(iArg1, BinaryOpcode::plus, iArg2);
}
else if (iArg1 != Zero)
return iArg1;
else if (iArg2 != Zero)
return iArg2;
else
return Zero;
}
expr_t
DataTree::AddMinus(expr_t iArg1, expr_t iArg2)
......@@ -210,49 +228,71 @@ DataTree::AddMinus(expr_t iArg1, expr_t iArg2)
if (iArg1 == iArg2)
return Zero;
// Simplify x-(-y) in x+y
if (auto uarg2 = dynamic_cast<UnaryOpNode*>(iArg2);
uarg2 && uarg2->op_code == UnaryOpcode::uminus)
return AddPlus(iArg1, uarg2->arg);
// Simplify (x+y)-y and (y+x)-y in x
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::plus)
{
if (barg1->arg2 == iArg2)
return barg1->arg1;
if (barg1->arg1 == iArg2)
return barg1->arg2;
}
return AddBinaryOp(iArg1, BinaryOpcode::minus, iArg2);
}
expr_t
DataTree::AddUMinus(expr_t iArg1)
{
if (iArg1 != Zero)
{
if (iArg1 == Zero)
return Zero;
// Simplify -(-x) in x
auto *uarg = dynamic_cast<UnaryOpNode *>(iArg1);
if (uarg != nullptr && uarg->op_code == UnaryOpcode::uminus)
if (auto uarg = dynamic_cast<UnaryOpNode*>(iArg1); uarg && uarg->op_code == UnaryOpcode::uminus)
return uarg->arg;
return AddUnaryOp(UnaryOpcode::uminus, iArg1);
}
else
return Zero;
}
expr_t
DataTree::AddTimes(expr_t iArg1, expr_t iArg2)
{
if (iArg1 == Zero || iArg2 == Zero)
return Zero;
if (iArg1 == One)
return iArg2;
if (iArg2 == One)
return iArg1;
if (iArg1 == MinusOne)
return AddUMinus(iArg2);
else if (iArg2 == MinusOne)
if (iArg2 == MinusOne)
return AddUMinus(iArg1);
else if (iArg1 != Zero && iArg1 != One && iArg2 != Zero && iArg2 != One)
{
// Simplify (x/y)*y in x
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::divide && barg1->arg2 == iArg2)
return barg1->arg1;
// Simplify y*(x/y) in x
if (auto barg2 = dynamic_cast<BinaryOpNode*>(iArg2);
barg2 && barg2->op_code == BinaryOpcode::divide && barg2->arg2 == iArg1)
return barg2->arg1;
// To treat commutativity of "*"
// Nodes iArg1 and iArg2 are sorted by index
if (iArg1->idx > iArg2->idx)
if (iArg1->idx > iArg2->idx && !no_commutativity) // NOLINT(clang-analyzer-core.NullDereference)
swap(iArg1, iArg2);
return AddBinaryOp(iArg1, BinaryOpcode::times, iArg2);
}
else if (iArg1 != Zero && iArg1 != One && iArg2 == One)
return iArg1;
else if (iArg2 != Zero && iArg2 != One && iArg1 == One)
return iArg2;
else if (iArg2 == One && iArg1 == One)
return One;
else
return Zero;
}
expr_t
DataTree::AddDivide(expr_t iArg1, expr_t iArg2) noexcept(false)
......@@ -273,6 +313,21 @@ DataTree::AddDivide(expr_t iArg1, expr_t iArg2) noexcept(false)
if (iArg1 == iArg2)
return One;
// Simplify x/(1/y) in x*y
if (auto barg2 = dynamic_cast<BinaryOpNode*>(iArg2);
barg2 && barg2->op_code == BinaryOpcode::divide && barg2->arg1 == One)
return AddTimes(iArg1, barg2->arg2);
// Simplify (x*y)/y and (y*x)/y in x
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::times)
{
if (barg1->arg2 == iArg2)
return barg1->arg1;
if (barg1->arg1 == iArg2)
return barg1->arg2;
}
return AddBinaryOp(iArg1, BinaryOpcode::divide, iArg2);
}
......@@ -315,16 +370,20 @@ DataTree::AddDifferent(expr_t iArg1, expr_t iArg2)
expr_t
DataTree::AddPower(expr_t iArg1, expr_t iArg2)
{
if (iArg1 != Zero && iArg2 != Zero && iArg1 != One && iArg2 != One)
return AddBinaryOp(iArg1, BinaryOpcode::power, iArg2);
else if (iArg1 == One)
return One;
else if (iArg2 == One)
return iArg1;
else if (iArg2 == Zero)
// This one comes first, because 0⁰=1
if (iArg2 == Zero)
return One;
else
if (iArg1 == Zero)
return Zero;
if (iArg1 == One)
return One;
if (iArg2 == One)
return iArg1;
return AddBinaryOp(iArg1, BinaryOpcode::power, iArg2);
}
expr_t
......@@ -346,16 +405,16 @@ DataTree::AddDiff(expr_t iArg1)
expr_t
DataTree::AddAdl(expr_t iArg1, const string& name, const vector<int>& lags)
{
return AddUnaryOp(UnaryOpcode::adl, iArg1, 0, 0, 0, string(name), lags);
return AddUnaryOp(UnaryOpcode::adl, iArg1, 0, 0, 0, name, lags);
}
expr_t
DataTree::AddExp(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::exp, iArg1);
else
if (iArg1 == Zero)
return One;
return AddUnaryOp(UnaryOpcode::exp, iArg1);
}
expr_t
......@@ -370,9 +429,9 @@ DataTree::AddLog(expr_t iArg1)
exit(EXIT_FAILURE);
}
// Try to simplify log(1/x) into -log(x)
auto barg1 = dynamic_cast<BinaryOpNode *>(iArg1);
if (barg1 && barg1->op_code == BinaryOpcode::divide && barg1->arg1 == One)
// Simplify log(1/x) inlog(x)
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::divide && barg1->arg1 == One)
return AddUMinus(AddLog(barg1->arg2));
return AddUnaryOp(UnaryOpcode::log, iArg1);
......@@ -390,9 +449,9 @@ DataTree::AddLog10(expr_t iArg1)
exit(EXIT_FAILURE);
}
// Try to simplify log10(1/x) into -log10(x)
auto barg1 = dynamic_cast<BinaryOpNode *>(iArg1);
if (barg1 && barg1->op_code == BinaryOpcode::divide && barg1->arg1 == One)
// Simplify log₁₀(1/x) inlog₁₀(x)
if (auto barg1 = dynamic_cast<BinaryOpNode*>(iArg1);
barg1 && barg1->op_code == BinaryOpcode::divide && barg1->arg1 == One)
return AddUMinus(AddLog10(barg1->arg2));
return AddUnaryOp(UnaryOpcode::log10, iArg1);
......@@ -401,118 +460,121 @@ DataTree::AddLog10(expr_t iArg1)
expr_t
DataTree::AddCos(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::cos, iArg1);
else
if (iArg1 == Zero)
return One;
return AddUnaryOp(UnaryOpcode::cos, iArg1);
}
expr_t
DataTree::AddSin(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::sin, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::sin, iArg1);
}
expr_t
DataTree::AddTan(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::tan, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::tan, iArg1);
}
expr_t
DataTree::AddAcos(expr_t iArg1)
{
if (iArg1 != One)
return AddUnaryOp(UnaryOpcode::acos, iArg1);
else
if (iArg1 == One)
return Zero;
return AddUnaryOp(UnaryOpcode::acos, iArg1);
}
expr_t
DataTree::AddAsin(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::asin, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::asin, iArg1);
}
expr_t
DataTree::AddAtan(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::atan, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::atan, iArg1);
}
expr_t
DataTree::AddCosh(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::cosh, iArg1);
else
if (iArg1 == Zero)
return One;
return AddUnaryOp(UnaryOpcode::cosh, iArg1);
}
expr_t
DataTree::AddSinh(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::sinh, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::sinh, iArg1);
}
expr_t
DataTree::AddTanh(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::tanh, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::tanh, iArg1);
}
expr_t
DataTree::AddAcosh(expr_t iArg1)
{
if (iArg1 != One)
return AddUnaryOp(UnaryOpcode::acosh, iArg1);
else
if (iArg1 == One)
return Zero;
return AddUnaryOp(UnaryOpcode::acosh, iArg1);
}
expr_t
DataTree::AddAsinh(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::asinh, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::asinh, iArg1);
}
expr_t
DataTree::AddAtanh(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::atanh, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::atanh, iArg1);
}
expr_t
DataTree::AddSqrt(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::sqrt, iArg1);
else
if (iArg1 == Zero)
return Zero;
if (iArg1 == One)
return One;
return AddUnaryOp(UnaryOpcode::sqrt, iArg1);
}
expr_t
......@@ -520,9 +582,10 @@ DataTree::AddCbrt(expr_t iArg1)
{
if (iArg1 == Zero)
return Zero;
else if (iArg1 == One)
if (iArg1 == One)
return One;
else
return AddUnaryOp(UnaryOpcode::cbrt, iArg1);
}
......@@ -531,9 +594,10 @@ DataTree::AddAbs(expr_t iArg1)
{
if (iArg1 == Zero)
return Zero;
if (iArg1 == One)
return One;
else
return AddUnaryOp(UnaryOpcode::abs, iArg1);
}
......@@ -542,19 +606,29 @@ DataTree::AddSign(expr_t iArg1)
{
if (iArg1 == Zero)
return Zero;
if (iArg1 == One)
return One;
else
return AddUnaryOp(UnaryOpcode::sign, iArg1);
}
expr_t
DataTree::AddErf(expr_t iArg1)
{
if (iArg1 != Zero)
return AddUnaryOp(UnaryOpcode::erf, iArg1);
else
if (iArg1 == Zero)
return Zero;
return AddUnaryOp(UnaryOpcode::erf, iArg1);
}
expr_t
DataTree::AddErfc(expr_t iArg1)
{
if (iArg1 == Zero)
return One;
return AddUnaryOp(UnaryOpcode::erfc, iArg1);
}
expr_t
......@@ -596,7 +670,8 @@ DataTree::AddSteadyStateParamDeriv(expr_t iArg1, int param_symb_id)
expr_t
DataTree::AddSteadyStateParam2ndDeriv(expr_t iArg1, int param1_symb_id, int param2_symb_id)
{
return AddUnaryOp(UnaryOpcode::steadyStateParam2ndDeriv, iArg1, 0, param1_symb_id, param2_symb_id);
return AddUnaryOp(UnaryOpcode::steadyStateParam2ndDeriv, iArg1, 0, param1_symb_id,
param2_symb_id);
}
expr_t
......@@ -608,35 +683,49 @@ DataTree::AddExpectation(int iArg1, expr_t iArg2)
expr_t
DataTree::AddVarExpectation(const string& model_name)
{
auto it = var_expectation_node_map.find(model_name);
if (it != var_expectation_node_map.end())
if (auto it = var_expectation_node_map.find(model_name); it != var_expectation_node_map.end())
return it->second;
auto sp = make_unique<VarExpectationNode>(*this, node_list.size(), model_name);
auto p = sp.get();
node_list.push_back(move(sp));
var_expectation_node_map[model_name] = p;
var_expectation_node_map.emplace(model_name, p);
return p;
}
expr_t
DataTree::AddPacExpectation(const string& model_name)
{
auto it = pac_expectation_node_map.find(model_name);
if (it != pac_expectation_node_map.end())
if (auto it = pac_expectation_node_map.find(model_name); it != pac_expectation_node_map.end())
return it->second;
auto sp = make_unique<PacExpectationNode>(*this, node_list.size(), model_name);
auto p = sp.get();
node_list.push_back(move(sp));
pac_expectation_node_map[model_name] = p;
pac_expectation_node_map.emplace(model_name, p);
return p;
}
expr_t
DataTree::AddPacTargetNonstationary(const string& model_name)
{
if (auto it = pac_target_nonstationary_node_map.find(model_name);
it != pac_target_nonstationary_node_map.end())
return it->second;
auto sp = make_unique<PacTargetNonstationaryNode>(*this, node_list.size(), model_name);
auto p = sp.get();
node_list.push_back(move(sp));
pac_target_nonstationary_node_map.emplace(model_name, p);
return p;
}
BinaryOpNode*
DataTree::AddEqual(expr_t iArg1, expr_t iArg2)
{
return AddBinaryOp(iArg1, BinaryOpcode::equal, iArg2);
/* We know that we can safely cast to BinaryOpNode because
BinaryOpCode::equal can never be reduced to a constant. */
return dynamic_cast<BinaryOpNode*>(AddBinaryOp(iArg1, BinaryOpcode::equal, iArg2));
}
void
......@@ -645,11 +734,10 @@ DataTree::AddLocalVariable(int symb_id, expr_t value) noexcept(false)
assert(symbol_table.getType(symb_id) == SymbolType::modelLocalVariable);
// Throw an exception if symbol already declared
auto it = local_variables_table.find(symb_id);
if (it != local_variables_table.end())
throw LocalVariableException(symbol_table.getName(symb_id));
if (local_variables_table.contains(symb_id))
throw LocalVariableException {symbol_table.getName(symb_id)};
local_variables_table[symb_id] = value;
local_variables_table.emplace(symb_id, value);
local_variables_vector.push_back(symb_id);
}
......@@ -658,118 +746,126 @@ DataTree::AddExternalFunction(int symb_id, const vector<expr_t> &arguments)
{
assert(symbol_table.getType(symb_id) == SymbolType::externalFunction);
auto it = external_function_node_map.find({ arguments, symb_id });
if (it != external_function_node_map.end())
if (auto it = external_function_node_map.find({arguments, symb_id});
it != external_function_node_map.end())
return it->second;
auto sp = make_unique<ExternalFunctionNode>(*this, node_list.size(), symb_id, arguments);
auto p = sp.get();
node_list.push_back(move(sp));
external_function_node_map[{ arguments, symb_id }] = p;
external_function_node_map.try_emplace({arguments, symb_id}, p);
return p;
}
expr_t
DataTree::AddFirstDerivExternalFunction(int top_level_symb_id, const vector<expr_t> &arguments, int input_index)
DataTree::AddFirstDerivExternalFunction(int top_level_symb_id, const vector<expr_t>& arguments,
int input_index)
{
assert(symbol_table.getType(top_level_symb_id) == SymbolType::externalFunction);
auto it
if (auto it
= first_deriv_external_function_node_map.find({arguments, input_index, top_level_symb_id});
if (it != first_deriv_external_function_node_map.end())
it != first_deriv_external_function_node_map.end())
return it->second;
auto sp = make_unique<FirstDerivExternalFunctionNode>(*this, node_list.size(), top_level_symb_id, arguments, input_index);
auto sp = make_unique<FirstDerivExternalFunctionNode>(*this, node_list.size(), top_level_symb_id,
arguments, input_index);
auto p = sp.get();
node_list.push_back(move(sp));
first_deriv_external_function_node_map[{ arguments, input_index, top_level_symb_id }] = p;
first_deriv_external_function_node_map.try_emplace({arguments, input_index, top_level_symb_id},
p);
return p;
}
expr_t
DataTree::AddSecondDerivExternalFunction(int top_level_symb_id, const vector<expr_t> &arguments, int input_index1, int input_index2)
DataTree::AddSecondDerivExternalFunction(int top_level_symb_id, const vector<expr_t>& arguments,
int input_index1, int input_index2)
{
assert(symbol_table.getType(top_level_symb_id) == SymbolType::externalFunction);
auto it
= second_deriv_external_function_node_map.find({ arguments, input_index1, input_index2,
top_level_symb_id });
if (it != second_deriv_external_function_node_map.end())
if (auto it = second_deriv_external_function_node_map.find(
{arguments, input_index1, input_index2, top_level_symb_id});
it != second_deriv_external_function_node_map.end())
return it->second;
auto sp = make_unique<SecondDerivExternalFunctionNode>(*this, node_list.size(), top_level_symb_id, arguments, input_index1, input_index2);
auto sp = make_unique<SecondDerivExternalFunctionNode>(*this, node_list.size(), top_level_symb_id,
arguments, input_index1, input_index2);
auto p = sp.get();
node_list.push_back(move(sp));
second_deriv_external_function_node_map[{ arguments, input_index1, input_index2, top_level_symb_id }] = p;
second_deriv_external_function_node_map.try_emplace(
{arguments, input_index1, input_index2, top_level_symb_id}, p);
return p;
}
expr_t
DataTree::AddSum(expr_t arg)
{
return AddUnaryOp(UnaryOpcode::sum, arg);
}
bool
DataTree::isSymbolUsed(int symb_id) const
{
for (const auto & it : variable_node_map)
if (it.first.first == symb_id)
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.find(symb_id) != local_variables_table.end())
if (local_variables_table.contains(symb_id))
return true;
return false;
}
int
DataTree::getDerivID(int symb_id, int lag) const noexcept(false)
DataTree::getDerivID([[maybe_unused]] int symb_id, [[maybe_unused]] int lag) const noexcept(false)
{
throw UnknownDerivIDException();
}
SymbolType
DataTree::getTypeByDerivID(int deriv_id) const noexcept(false)
DataTree::getTypeByDerivID([[maybe_unused]] int deriv_id) const noexcept(false)
{
throw UnknownDerivIDException();
}
int
DataTree::getLagByDerivID(int deriv_id) const noexcept(false)
DataTree::getLagByDerivID([[maybe_unused]] int deriv_id) const noexcept(false)
{
throw UnknownDerivIDException();
}
int
DataTree::getSymbIDByDerivID(int deriv_id) const noexcept(false)
DataTree::getSymbIDByDerivID([[maybe_unused]] int deriv_id) const noexcept(false)
{
throw UnknownDerivIDException();
}
void
DataTree::addAllParamDerivId(set<int> &deriv_id_set)
int
DataTree::getTypeSpecificIDByDerivID([[maybe_unused]] int deriv_id) const
{
throw UnknownDerivIDException();
}
int
DataTree::getDynJacobianCol(int deriv_id) const noexcept(false)
void
DataTree::addAllParamDerivId([[maybe_unused]] set<int>& deriv_id_set)
{
throw UnknownDerivIDException();
}
bool
DataTree::isUnaryOpUsed(UnaryOpcode opcode) const
{
for (const auto & it : unary_op_node_map)
if (get<1>(it.first) == opcode)
return true;
return false;
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;
}
......@@ -779,114 +875,116 @@ DataTree::isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const
bool
DataTree::isBinaryOpUsed(BinaryOpcode opcode) const
{
for (const auto & it : binary_op_node_map)
if (get<2>(it.first) == opcode)
return true;
return false;
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;
}
return false;
}
bool
DataTree::isTrinaryOpUsed(TrinaryOpcode opcode) const
{
for (const auto & it : trinary_op_node_map)
if (get<3>(it.first) == opcode)
return true;
return false;
}
bool
DataTree::isExternalFunctionUsed(int symb_id) const
{
for (const auto & it : external_function_node_map)
if (it.first.second == symb_id)
return true;
return false;
}
bool
DataTree::isFirstDerivExternalFunctionUsed(int symb_id) const
{
for (const auto & it : first_deriv_external_function_node_map)
if (get<2>(it.first) == symb_id)
return true;
return false;
}
bool
DataTree::isSecondDerivExternalFunctionUsed(int symb_id) const
{
for (const auto & it : second_deriv_external_function_node_map)
if (get<3>(it.first) == symb_id)
return true;
return false;
}
int
DataTree::minLagForSymbol(int symb_id) const
{
int r = 0;
for (const auto & it : variable_node_map)
if (it.first.first == symb_id && it.first.second < r)
r = it.first.second;
for (const auto& [symb_lag, expr] : variable_node_map)
if (symb_lag.first == symb_id)
r = min(r, symb_lag.second);
return r;
}
void
DataTree::writePowerDerivCHeader(ostream &output) const
DataTree::writeCHelpersDefinition(ostream& output) const
{
if (isBinaryOpUsed(BinaryOpcode::powerDeriv))
output << "double getPowerDeriv(double, double, int);" << endl;
}
void
DataTree::writePowerDeriv(ostream &output) const
{
if (isBinaryOpUsed(BinaryOpcode::powerDeriv))
output << "/*" << endl
<< " * The k-th derivative of x^p" << endl
<< " */" << endl
<< "double getPowerDeriv(double x, double p, int k)" << endl
output << "// The k-th derivative of x^p" << endl
<< "inline double" << endl
<< "getPowerDeriv(double x, double p, int k)" << endl
<< "{" << endl
<< "#ifdef _MSC_VER" << endl
<< "# define nearbyint(x) (fabs((x)-floor(x)) < fabs((x)-ceil(x)) ? floor(x) : ceil(x))" << endl
<< "#endif" << endl
<< " if ( fabs(x) < " << near_zero << " && p > 0 && k > p && fabs(p-nearbyint(p)) < " << near_zero << " )" << endl
<< " if (fabs(x) < " << power_deriv_near_zero
<< " && p >= 0 && k > p && fabs(p-nearbyint(p)) < " << power_deriv_near_zero << ')'
<< endl
<< " return 0.0;" << endl
<< " else" << endl
<< " {" << endl
<< " int i = 0;" << endl
<< " double dxp = pow(x, p-k);" << endl
<< " for (; i<k; i++)" << endl
<< " for (int i = 0; i<k; i++)" << endl
<< " dxp *= p--;" << endl
<< " return dxp;" << endl
<< " }" << endl
<< "}" << endl;
if (isUnaryOpUsed(UnaryOpcode::sign))
output << "inline double" << endl
<< "sign(double x)" << endl
<< "{" << endl
<< " return (x > 0) ? 1 : ((x < 0) ? -1 : 0);" << endl
<< "}" << endl;
}
void
DataTree::writeCHelpersDeclaration(ostream& output) const
{
if (isBinaryOpUsed(BinaryOpcode::powerDeriv))
output << "extern inline double getPowerDeriv(double x, double p, int k);" << endl;
if (isUnaryOpUsed(UnaryOpcode::sign))
output << "extern inline double sign(double x);" << endl;
}
string
DataTree::packageDir(const string &package)
vector<string>
DataTree::strsplit(string_view str, char delim)
{
regex pat{R"(\.)"};
string dirname = "+" + regex_replace(package, pat, "/+");
filesystem::create_directories(dirname);
return dirname;
vector<string> result;
while (true)
{
size_t idx {str.find(delim)};
if (auto sub {str.substr(0, idx)}; !sub.empty())
result.emplace_back(sub);
if (idx == string_view::npos)
break;
str.remove_prefix(idx + 1);
}
return result;
}
filesystem::path
DataTree::packageDir(const string_view& package)
{
filesystem::path d;
for (const auto& it : strsplit(package, '.'))
d /= "+" + it;
return d;
}
void
DataTree::writeToFileIfModified(stringstream& new_contents, const filesystem::path& filename)
{
ifstream old_file {filename, ios::in | ios::binary};
if (old_file.is_open()
&& ranges::equal(istreambuf_iterator<char> {old_file}, istreambuf_iterator<char> {},
istreambuf_iterator<char> {new_contents}, istreambuf_iterator<char> {}))
return;
old_file.close();
new_contents.seekg(0);
ofstream new_file {filename, ios::out | ios::binary};
if (!new_file.is_open())
{
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
ranges::copy(istreambuf_iterator<char> {new_contents}, istreambuf_iterator<char> {},
ostreambuf_iterator<char> {new_file});
new_file.close();
}
/*
* Copyright © 2003-2019 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -14,27 +14,31 @@
* 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 <http://www.gnu.org/licenses/>.
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DATATREE_HH
#define _DATATREE_HH
#ifndef DATA_TREE_HH
#define DATA_TREE_HH
using namespace std;
#include <string>
#include <cmath>
#include <filesystem>
#include <iomanip>
#include <map>
#include <vector>
#include <memory>
#include <sstream>
#include <iomanip>
#include <cmath>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "SymbolTable.hh"
#include "NumericalConstants.hh"
#include "ExternalFunctionsTable.hh"
#include "ExprNode.hh"
#include "ExternalFunctionsTable.hh"
#include "HeterogeneityTable.hh"
#include "NumericalConstants.hh"
#include "SubModel.hh"
#include "SymbolTable.hh"
using namespace std;
class DataTree
{
......@@ -45,7 +49,11 @@ 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. */
const bool is_dynamic;
private:
......@@ -57,8 +65,10 @@ private:
using variable_node_map_t = map<pair<int, int>, VariableNode*>;
variable_node_map_t variable_node_map;
//! (arg, op_code, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags) -> UnaryOpNode
using unary_op_node_map_t = map<tuple<expr_t, UnaryOpcode, int, int, int, string, vector<int>>, UnaryOpNode *>;
//! (arg, op_code, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags) ->
//! UnaryOpNode
using unary_op_node_map_t
= map<tuple<expr_t, UnaryOpcode, int, int, int, string, vector<int>>, UnaryOpNode*>;
unary_op_node_map_t unary_op_node_map;
//! ( arg1, arg2, opCode, order of Power Derivative) -> BinaryOpNode
......@@ -81,29 +91,37 @@ private:
using pac_expectation_node_map_t = map<string, PacExpectationNode*>;
pac_expectation_node_map_t pac_expectation_node_map;
// model_name -> PacTargetNonstationaryNode
using pac_target_nonstationary_node_map_t = map<string, PacTargetNonstationaryNode*>;
pac_target_nonstationary_node_map_t pac_target_nonstationary_node_map;
// (arguments, deriv_idx, symb_id) -> FirstDerivExternalFunctionNode
using first_deriv_external_function_node_map_t = map<tuple<vector<expr_t>, int, int>, FirstDerivExternalFunctionNode *>;
using first_deriv_external_function_node_map_t
= map<tuple<vector<expr_t>, int, int>, FirstDerivExternalFunctionNode*>;
first_deriv_external_function_node_map_t first_deriv_external_function_node_map;
// (arguments, deriv_idx1, deriv_idx2, symb_id) -> SecondDerivExternalFunctionNode
using second_deriv_external_function_node_map_t = map<tuple<vector<expr_t>, int, int, int>, SecondDerivExternalFunctionNode *>;
using second_deriv_external_function_node_map_t
= map<tuple<vector<expr_t>, int, int, int>, SecondDerivExternalFunctionNode*>;
second_deriv_external_function_node_map_t second_deriv_external_function_node_map;
// Flag to disable simplifications related to commutativity of addition and multiplication
static bool no_commutativity;
protected:
//! Stores local variables value (maps symbol ID to corresponding node)
map<int, expr_t> local_variables_table;
//! Stores the order of appearance of local variables in the model block. Needed following change in #563
//! Stores the order of appearance of local variables in the model block. Needed following change
//! in #563
vector<int> local_variables_vector;
//! Internal implementation of ParamUsedWithLeadLag()
bool ParamUsedWithLeadLagInternal() const;
[[nodiscard]] bool ParamUsedWithLeadLagInternal() const;
/*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
and returns the name of the corresponding filesystem directory (which
is created by the function if it does not exist).
In practice the package nesting is used for the planner_objective (stored
inside +objective subdir). */
static string packageDir(const string &package);
/* Writes the contents of “new_contents” to the file “filename”. However, if
the file already exists and would not be modified by this operation, then do
nothing. */
static void writeToFileIfModified(stringstream& new_contents, const filesystem::path& filename);
private:
constexpr static int constants_precision {16};
......@@ -111,37 +129,35 @@ private:
//! The list of nodes
vector<unique_ptr<ExprNode>> node_list;
inline expr_t AddUnaryOp(UnaryOpcode op_code, expr_t arg, int arg_exp_info_set = 0, int param1_symb_id = 0, int param2_symb_id = 0, const string &adl_param_name = "", const vector<int> &adl_lags = vector<int>());
inline expr_t AddBinaryOp(expr_t arg1, BinaryOpcode op_code, expr_t arg2, int powerDerivOrder = 0);
inline expr_t AddUnaryOp(UnaryOpcode op_code, expr_t arg, int arg_exp_info_set = 0,
int param1_symb_id = 0, int param2_symb_id = 0,
const string& adl_param_name = "",
const vector<int>& adl_lags = vector<int>());
inline expr_t AddBinaryOp(expr_t arg1, BinaryOpcode op_code, expr_t arg2,
int powerDerivOrder = 0);
inline expr_t AddTrinaryOp(expr_t arg1, TrinaryOpcode op_code, expr_t arg2, expr_t arg3);
//! Initializes the predefined constants, used only from the constructors
void initConstants();
public:
DataTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
DataTree(SymbolTable& symbol_table_arg, NumericalConstants& num_constants_arg,
ExternalFunctionsTable& external_functions_table_arg,
bool is_static_args = false);
HeterogeneityTable& heterogeneity_table_arg, bool is_dynamic_arg = false);
virtual ~DataTree() = default;
DataTree(const DataTree& d);
DataTree(DataTree &&) = delete;
DataTree& operator=(const DataTree& d);
DataTree & operator=(DataTree &&) = delete;
//! Some predefined constants
expr_t Zero, One, Two, Three, MinusOne, NaN, Infinity, MinusInfinity, Pi;
NumConstNode *Zero, *One, *Two, *Three, *NaN, *Infinity, *Pi;
expr_t MinusOne, MinusInfinity;
//! Raised when a local parameter is declared twice
class LocalVariableException
struct LocalVariableException
{
public:
string name;
explicit LocalVariableException(string name_arg) : name{move(name_arg)}
{
}
};
class DivisionByZeroException
......@@ -150,13 +166,13 @@ public:
inline expr_t AddPossiblyNegativeConstant(double val);
//! Adds a non-negative numerical constant (possibly Inf or NaN)
expr_t AddNonNegativeConstant(const string &value);
NumConstNode* AddNonNegativeConstant(const string& value);
//! Adds a variable
VariableNode* AddVariable(int symb_id, int lag = 0);
//! Gets a variable
/*! Same as AddVariable, except that it fails if the variable node has not
already been created */
VariableNode *getVariable(int symb_id, int lag = 0) const;
[[nodiscard]] VariableNode* getVariable(int symb_id, int lag = 0) const;
//! Adds "arg1+arg2" to model tree
expr_t AddPlus(expr_t iArg1, expr_t iArg2);
//! Adds "arg1-arg2" to model tree
......@@ -229,6 +245,8 @@ public:
expr_t AddSign(expr_t iArg1);
//! Adds "erf(arg)" to model tree
expr_t AddErf(expr_t iArg1);
//! Adds "erfc(arg)" to model tree
expr_t AddErfc(expr_t iArg1);
//! Adds "max(arg1,arg2)" to model tree
expr_t AddMax(expr_t iArg1, expr_t iArg2);
//! Adds "min(arg1,arg2)" to model tree
......@@ -244,94 +262,136 @@ public:
//! Add 2nd derivative of steady state w.r.t. parameter to model tree
expr_t AddSteadyStateParam2ndDeriv(expr_t iArg1, int param1_symb_id, int param2_symb_id);
//! Adds "arg1=arg2" to model tree
expr_t AddEqual(expr_t iArg1, expr_t iArg2);
BinaryOpNode* AddEqual(expr_t iArg1, expr_t iArg2);
//! Adds "var_expectation(model_name)" to model tree
expr_t AddVarExpectation(const string& model_name);
//! Adds pac_expectation command to model tree
expr_t AddPacExpectation(const string& model_name);
//! Adds a pac_target_nonstationary node to model tree
expr_t AddPacTargetNonstationary(const string& model_name);
//! Adds a model local variable with its value
void AddLocalVariable(int symb_id, expr_t value) noexcept(false);
//! Adds an external function node
expr_t AddExternalFunction(int symb_id, const vector<expr_t>& arguments);
//! Adds an external function node for the first derivative of an external function
expr_t AddFirstDerivExternalFunction(int top_level_symb_id, const vector<expr_t> &arguments, int input_index);
expr_t AddFirstDerivExternalFunction(int top_level_symb_id, const vector<expr_t>& arguments,
int input_index);
//! 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);
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
bool isSymbolUsed(int symb_id) const;
[[nodiscard]] bool isSymbolUsed(int symb_id) const;
//! Checks if a given unary op is used somewhere in the data tree
bool isUnaryOpUsed(UnaryOpcode opcode) const;
[[nodiscard]] bool isUnaryOpUsed(UnaryOpcode opcode) const;
//! Checks if a given unary op is used somewhere in the data tree on an endogenous variable
bool isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const;
[[nodiscard]] bool isUnaryOpUsedOnType(SymbolType type, UnaryOpcode opcode) const;
//! Checks if a given binary op is used somewhere in the data tree
bool isBinaryOpUsed(BinaryOpcode opcode) const;
[[nodiscard]] bool isBinaryOpUsed(BinaryOpcode opcode) const;
//! Checks if a given binary op is used somewhere in the data tree on an endogenous variable
bool isBinaryOpUsedOnType(SymbolType type, BinaryOpcode opcode) const;
//! Checks if a given trinary op is used somewhere in the data tree
bool isTrinaryOpUsed(TrinaryOpcode opcode) const;
//! Checks if a given external function is used somewhere in the data tree
bool isExternalFunctionUsed(int symb_id) const;
//! Checks if a given first derivative external function is used somewhere in the data tree
bool isFirstDerivExternalFunctionUsed(int symb_id) const;
//! Checks if a given second derivative external function is used somewhere in the data tree
bool isSecondDerivExternalFunctionUsed(int symb_id) const;
//! Returns the minimum lag (as a negative number) of the given symbol in the whole data tree (and not only in the equations !!)
[[nodiscard]] bool isBinaryOpUsedOnType(SymbolType type, BinaryOpcode opcode) const;
//! Returns the minimum lag (as a negative number) of the given symbol in the whole data tree (and
//! not only in the equations !!)
/*! Returns 0 if the symbol is not used */
int minLagForSymbol(int symb_id) const;
//! Write the C Header for getPowerDeriv when use_dll is used
void writePowerDerivCHeader(ostream &output) const;
//! Write getPowerDeriv in C
void writePowerDeriv(ostream &output) const;
[[nodiscard]] int minLagForSymbol(int symb_id) const;
/* Writes definitions of C function helpers (getPowerDeriv(), sign()) as
inline functions */
void writeCHelpersDefinition(ostream& output) const;
/* Writes declarations of C function helpers (getPowerDeriv(), sign()) as
extern inline (external definition). Those need to be included in exactly
one translation unit. That external definition will be used or not,
depending on the optimization decision by the compiler.
See https://en.cppreference.com/w/c/language/inline */
void writeCHelpersDeclaration(ostream& output) const;
//! Thrown when trying to access an unknown variable by deriv_id
class UnknownDerivIDException
{
};
//! Raised when a trend is declared twice
class TrendException
struct TrendException
{
public:
string name;
explicit TrendException(string name_arg) : name{move(name_arg)}
};
// Returns the derivation ID, or throws an exception if the derivation ID does not exist
[[nodiscard]] virtual int getDerivID(int symb_id, int lag) const noexcept(false);
// Get the type corresponding to a derivation ID
[[nodiscard]] virtual SymbolType getTypeByDerivID(int deriv_id) const noexcept(false);
// Get the lag corresponding to a derivation ID
[[nodiscard]] virtual int getLagByDerivID(int deriv_id) const noexcept(false);
// Get the symbol ID corresponding to a derivation ID
[[nodiscard]] virtual int getSymbIDByDerivID(int deriv_id) const noexcept(false);
// Get the type-specific ID corresponding to a derivation ID
[[nodiscard]] virtual int getTypeSpecificIDByDerivID(int deriv_id) const;
// Get the symbol name corresponding to a derivation ID
[[nodiscard]] string
getNameByDerivID(int deriv_id) const
{
return symbol_table.getName(getSymbIDByDerivID(deriv_id));
}
};
//! Returns the derivation ID, or throws an exception if the derivation ID does not exist
virtual int getDerivID(int symb_id, int lag) const noexcept(false);
virtual SymbolType getTypeByDerivID(int deriv_id) const noexcept(false);
virtual int getLagByDerivID(int deriv_id) const noexcept(false);
virtual int getSymbIDByDerivID(int deriv_id) const noexcept(false);
//! Returns the column of the dynamic Jacobian associated to a derivation ID
virtual int getDynJacobianCol(int deriv_id) const noexcept(false);
//! Adds to the set all the deriv IDs corresponding to parameters
virtual void addAllParamDerivId(set<int> &deriv_id_set);
/* Returns the column of the Jacobian associated to a derivation ID.
The “sparse” argument selects between the legacy representation and the
sparse representation. */
[[nodiscard]] virtual int
getJacobianCol([[maybe_unused]] int deriv_id, [[maybe_unused]] bool sparse) const
{
throw UnknownDerivIDException();
}
//! Returns bool indicating whether DataTree represents a Dynamic Model (returns true in DynamicModel.hh)
virtual bool
isDynamic() const
/* Returns the number of columns of the Jacobian
The “sparse” argument selects between the legacy representation and the
sparse representation. */
[[nodiscard]] virtual int
getJacobianColsNbr([[maybe_unused]] bool sparse) const
{
return false;
};
throw UnknownDerivIDException();
}
//! Adds to the set all the deriv IDs corresponding to parameters
virtual void addAllParamDerivId(set<int>& deriv_id_set);
class UnknownLocalVariableException
struct UnknownLocalVariableException
{
public:
//! Symbol ID
int id;
explicit UnknownLocalVariableException(int id_arg) : id(id_arg)
{
}
};
expr_t getLocalVariable(int symb_id) const
[[nodiscard]] expr_t
getLocalVariable(int symb_id, int lead_lag) const
{
auto it = local_variables_table.find(symb_id);
if (it == local_variables_table.end())
throw UnknownLocalVariableException(symb_id);
throw UnknownLocalVariableException {symb_id};
/* 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
setNoCommutativity()
{
no_commutativity = true;
}
/* Equivalent of MATLAB/Octave’s strsplit, except that it ignores empty
substring components (MATLAB/Octave adds them to the output); in
particular, returns an empty vector given an empty string. */
static vector<string> strsplit(string_view str, char delim);
/*! Takes a MATLAB/Octave package name (possibly with several levels nested using dots),
and returns the path to the corresponding filesystem directory.
In practice the package nesting is used for the planner_objective (stored
inside +objective subdir). */
static filesystem::path packageDir(const string_view& package);
};
inline expr_t
......@@ -342,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)
......@@ -362,21 +422,23 @@ DataTree::AddPossiblyNegativeConstant(double v)
}
inline expr_t
DataTree::AddUnaryOp(UnaryOpcode op_code, expr_t arg, int arg_exp_info_set, int param1_symb_id, int param2_symb_id, const string &adl_param_name, const vector<int> &adl_lags)
DataTree::AddUnaryOp(UnaryOpcode op_code, expr_t arg, int arg_exp_info_set, int param1_symb_id,
int param2_symb_id, const string& adl_param_name, const vector<int>& adl_lags)
{
// If the node already exists in tree, share it
auto it = unary_op_node_map.find({ arg, op_code, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags });
if (it != unary_op_node_map.end())
if (auto it = unary_op_node_map.find({arg, op_code, arg_exp_info_set, param1_symb_id,
param2_symb_id, adl_param_name, adl_lags});
it != unary_op_node_map.end())
return it->second;
// Try to reduce to a constant
// Case where arg is a constant and op_code == UnaryOpcode::uminus (i.e. we're adding a negative constant) is skipped
auto *carg = dynamic_cast<NumConstNode *>(arg);
if (op_code != UnaryOpcode::uminus || carg == nullptr)
// Case where arg is a constant and op_code == UnaryOpcode::uminus (i.e. we're adding a negative
// constant) is skipped
if (auto carg = dynamic_cast<NumConstNode*>(arg); op_code != UnaryOpcode::uminus || !carg)
{
try
{
double argval = arg->eval(eval_context_t());
double argval = arg->eval({}); // NOLINT(clang-analyzer-core.CallAndMessage)
double val = UnaryOpNode::eval_opcode(op_code, argval);
return AddPossiblyNegativeConstant(val);
}
......@@ -385,25 +447,28 @@ DataTree::AddUnaryOp(UnaryOpcode op_code, expr_t arg, int arg_exp_info_set, int
}
}
auto sp = make_unique<UnaryOpNode>(*this, node_list.size(), op_code, arg, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags);
auto sp = make_unique<UnaryOpNode>(*this, node_list.size(), op_code, arg, arg_exp_info_set,
param1_symb_id, param2_symb_id, adl_param_name, adl_lags);
auto p = sp.get();
node_list.push_back(move(sp));
unary_op_node_map[{ arg, op_code, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags }] = p;
unary_op_node_map.try_emplace(
{arg, op_code, arg_exp_info_set, param1_symb_id, param2_symb_id, adl_param_name, adl_lags},
p);
return p;
}
inline expr_t
DataTree::AddBinaryOp(expr_t arg1, BinaryOpcode op_code, expr_t arg2, int powerDerivOrder)
{
auto it = binary_op_node_map.find({ arg1, arg2, op_code, powerDerivOrder });
if (it != binary_op_node_map.end())
if (auto it = binary_op_node_map.find({arg1, arg2, op_code, powerDerivOrder});
it != binary_op_node_map.end())
return it->second;
// Try to reduce to a constant
try
{
double argval1 = arg1->eval(eval_context_t());
double argval2 = arg2->eval(eval_context_t());
double argval1 = arg1->eval({}); // NOLINT(clang-analyzer-core.CallAndMessage)
double argval2 = arg2->eval({}); // NOLINT(clang-analyzer-core.CallAndMessage)
double val = BinaryOpNode::eval_opcode(argval1, op_code, argval2, powerDerivOrder);
return AddPossiblyNegativeConstant(val);
}
......@@ -411,26 +476,27 @@ DataTree::AddBinaryOp(expr_t arg1, BinaryOpcode op_code, expr_t arg2, int powerD
{
}
auto sp = make_unique<BinaryOpNode>(*this, node_list.size(), arg1, op_code, arg2, powerDerivOrder);
auto sp
= make_unique<BinaryOpNode>(*this, node_list.size(), arg1, op_code, arg2, powerDerivOrder);
auto p = sp.get();
node_list.push_back(move(sp));
binary_op_node_map[{ arg1, arg2, op_code, powerDerivOrder }] = p;
binary_op_node_map.try_emplace({arg1, arg2, op_code, powerDerivOrder}, p);
return p;
}
inline expr_t
DataTree::AddTrinaryOp(expr_t arg1, TrinaryOpcode op_code, expr_t arg2, expr_t arg3)
{
auto it = trinary_op_node_map.find({ arg1, arg2, arg3, op_code });
if (it != trinary_op_node_map.end())
if (auto it = trinary_op_node_map.find({arg1, arg2, arg3, op_code});
it != trinary_op_node_map.end())
return it->second;
// Try to reduce to a constant
try
{
double argval1 = arg1->eval(eval_context_t());
double argval2 = arg2->eval(eval_context_t());
double argval3 = arg3->eval(eval_context_t());
double argval1 = arg1->eval({});
double argval2 = arg2->eval({});
double argval3 = arg3->eval({});
double val = TrinaryOpNode::eval_opcode(argval1, op_code, argval2, argval3);
return AddPossiblyNegativeConstant(val);
}
......@@ -441,7 +507,7 @@ DataTree::AddTrinaryOp(expr_t arg1, TrinaryOpcode op_code, expr_t arg2, expr_t a
auto sp = make_unique<TrinaryOpNode>(*this, node_list.size(), arg1, op_code, arg2, arg3);
auto p = sp.get();
node_list.push_back(move(sp));
trinary_op_node_map[{ arg1, arg2, arg3, op_code }] = p;
trinary_op_node_map.try_emplace({arg1, arg2, arg3, op_code}, p);
return p;
}
......
Source diff could not be displayed: it is too large. Options to address this: view the blob.
/*
* Copyright © 2003-2019 Dynare Team
* Copyright © 2003-2024 Dynare Team
*
* This file is part of Dynare.
*
......@@ -14,22 +14,24 @@
* 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 <http://www.gnu.org/licenses/>.
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef _DYNAMICMODEL_HH
#define _DYNAMICMODEL_HH
#ifndef DYNAMIC_MODEL_HH
#define DYNAMIC_MODEL_HH
using namespace std;
#include <fstream>
#include <filesystem>
#include <fstream>
#include "Bytecode.hh"
#include "StaticModel.hh"
using namespace std;
//! Stores a dynamic model
class DynamicModel : public ModelTree
{
friend class StaticModel; // For reading static_mfs from converting constructor
public:
//! A reference to the trend component model table
TrendComponentModelTable& trend_component_model_table;
......@@ -40,6 +42,41 @@ public:
variable is zero. Controlled by option “balanced_growth_test_tol” of the
“model” block. The default should not be too small (see dynare#1389). */
double balanced_growth_test_tol {1e-6};
/* For a given equation, tracks all the regimes and the declared alternatives with combinations of
bind and relax tags */
class OccbinRegimeTracker
{
private:
// The list of constraints used for this equation
vector<string> constraints;
/* The list of regimes present for this equation; each regime is a vector of boolean, of same
length as “constraints”; each boolean represents a constraint (in the order of
“constraints”): false for relax, true for bind */
set<vector<bool>> regimes_present;
public:
struct ConstraintInBothBindAndRelaxException
{
const string constraint;
};
struct RegimeAlreadyPresentException
{
const vector<string> constraints_bind, constraints_relax;
};
void addRegime(const vector<string>& constraints_bind,
const vector<string>& constraints_relax) noexcept(false);
struct MissingRegimeException
{
const vector<string> constraints_bind, constraints_relax;
};
void checkAllRegimesPresent() const noexcept(false);
private:
[[nodiscard]] pair<vector<string>, vector<string>>
convertBitVectorToRegimes(const vector<bool>& r) const;
};
private:
/* Used in the balanced growth test, for skipping equations where the test
cannot be performed (i.e. when LHS=RHS at the initial values). Should not
......@@ -51,13 +88,13 @@ private:
vector<BinaryOpNode*> static_only_equations;
//! Stores line numbers of equations declared as [static]
vector<int> static_only_equations_lineno;
vector<optional<int>> static_only_equations_lineno;
//! Stores the equation tags of equations declared as [static]
vector<vector<pair<string, string>>> static_only_equations_equation_tags;
EquationTags static_only_equations_equation_tags;
//! Stores mapping from equation tags to equation number
multimap<pair<string, string>, int> static_only_equation_tags_xref;
// Complementarity conditions of equations declared as [static]
vector<optional<tuple<int, expr_t, expr_t>>> static_only_complementarity_conditions;
using deriv_id_table_t = map<pair<int, int>, int>;
//! Maps a pair (symbol_id, lag) to a deriv ID
......@@ -65,9 +102,12 @@ private:
//! Maps a deriv ID to a pair (symbol_id, lag)
vector<pair<int, int>> inv_deriv_id_table;
//! Maps a deriv_id to the column index of the dynamic Jacobian
/*! Contains only endogenous, exogenous and exogenous deterministic */
/* Maps a deriv_id to the column index of the dynamic Jacobian, in the legacy
representation.
Contains only endogenous, exogenous and exogenous deterministic */
map<int, int> dyn_jacobian_cols_table;
// Number of columns of the dynamic Jacobian (legacy representation)
int dyn_jacobian_ncols;
//! Maximum lag and lead over all types of variables (positive values)
/*! Set by computeDerivIDs() */
......@@ -87,225 +127,211 @@ private:
int max_endo_lag_orig {0}, max_endo_lead_orig {0};
//! Maximum lag and lead over exogenous variables (positive values) of original model
int max_exo_lag_orig {0}, max_exo_lead_orig {0};
//! Maximum lag and lead over deterministic exogenous variables (positive values) of original model
//! Maximum lag and lead over deterministic exogenous variables (positive values) of original
//! model
int max_exo_det_lag_orig {0}, max_exo_det_lead_orig {0};
//! Cross reference information
// Cross reference information: eq → set of (symb_id, lag) for each symbol type
map<int, ExprNode::EquationInfo> xrefs;
map<pair<int, int>, set<int>> xref_param;
map<pair<int, int>, set<int>> xref_endo;
map<pair<int, int>, set<int>> xref_exo;
map<pair<int, int>, set<int>> xref_exo_det;
// Reverse cross reference information: (symb_id, lag) → eqs
map<pair<int, int>, set<int>> xref_param, xref_endo, xref_exo, xref_exo_det;
//! Nonzero equations in the Hessian
map<int, string> nonzero_hessian_eqs;
//! Number of columns of dynamic jacobian
/*! Set by computeDerivID()s and computeDynJacobianCols() */
int dynJacobianColsNbr{0};
//! Temporary terms for block decomposed models
vector< vector<temporary_terms_t>> v_temporary_terms;
vector<temporary_terms_inuse_t> v_temporary_terms_inuse;
set<int> nonzero_hessian_eqs;
//! Creates mapping for variables and equations they are present in
map<int, set<int>> variableMapping;
//! Store the derivatives or the chainrule derivatives:map<tuple<equation, variable, lead_lag>, expr_t>
using first_chain_rule_derivatives_t = map<tuple<int, int, int>, expr_t>;
first_chain_rule_derivatives_t first_chain_rule_derivatives;
/* For each block, and for each variable type, maps (variable ID, lag) to
Jacobian column. The variable ID is the index within the block. */
vector<map<pair<int, int>, int>> blocks_jacob_cols_endo;
//! Used for var_expectation and var_model
map<string, set<int>> var_expectation_functions_to_write;
//! Writes dynamic model file (Matlab version)
// Value of the “mfs” option of “model” block (or ”model_options” command)
int mfs {1};
/* Value of the “static_mfs” option of “model” block (or the “model_options”
command).
Only used when converting to StaticModel class. */
int static_mfs {0};
// Writes dynamic model file (MATLAB/Octave version, legacy representation)
void writeDynamicMFile(const string& basename) const;
//! Writes dynamic model file (Julia version)
void writeDynamicJuliaFile(const string &dynamic_basename) const;
//! Writes dynamic model file (C version)
/*! \todo add third derivatives handling */
void writeDynamicCFile(const string &basename, const int order) const;
//! Writes dynamic model file when SparseDLL option is on
void writeSparseDynamicMFile(const string &basename) const;
//! Writes the dynamic model equations and its derivatives
/*! \todo add third derivatives handling in C output */
void writeDynamicModel(ostream &DynamicOutput, bool use_dll, bool julia) const;
void writeDynamicModel(const string &basename, bool use_dll, bool julia) const;
void writeDynamicModel(const string &basename, ostream &DynamicOutput, bool use_dll, bool julia) const;
//! Writes the Block reordred structure of the model in M output
void writeModelEquationsOrdered_M(const string &basename) const;
//! Writes the code of the Block reordred structure of the model in virtual machine bytecode
void writeModelEquationsCode_Block(const string &basename, const map_idx_t &map_idx, const bool linear_decomposition) const;
//! Writes the code of the block-decomposed model in virtual machine bytecode
void writeDynamicBlockBytecode(const string& basename) const;
//! Writes the code of the model in virtual machine bytecode
void writeModelEquationsCode(const string &basename, const map_idx_t &map_idx) const;
void writeDynamicBytecode(const string& basename) const;
void writeSetAuxiliaryVariables(const string &basename, const bool julia) const;
void writeAuxVarRecursiveDefinitions(ostream &output, ExprNodeOutputType output_type) const;
//! Computes jacobian and prepares for equation normalization
/*! Using values from initval/endval blocks and parameter initializations:
- computes the jacobian for the model w.r. to contemporaneous variables
- removes edges of the incidence matrix when derivative w.r. to the corresponding variable is too close to zero (below the cutoff)
*/
//void evaluateJacobian(const eval_context_t &eval_context, jacob_map *j_m, bool dynamic);
// Write the block structure of the model in the driver file
void writeBlockDriverOutput(ostream& output) const;
//! return a map on the block jacobian
map<tuple<int, int, int, int, int>, int> get_Derivatives(int block);
//! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables
void computeChainRuleJacobian(blocks_derivatives_t &blocks_derivatives);
// Used by determineBlockDerivativesType()
enum class BlockDerivativeType
{
standard,
chainRule,
normalizedChainRule
};
string reform(string name) const;
map_idx_t map_idx;
/* For each tuple (lag, eq, var) within the given block, determine the type
of the derivative to be computed. Indices are within the block (i.e.
between 0 and blocks[blk].size-1). */
map<tuple<int, int, int>, BlockDerivativeType> determineBlockDerivativesType(int blk);
//! sorts the temporary terms in the blocks order
void computeTemporaryTermsOrdered();
void computeChainRuleJacobian() override;
//! creates a mapping from the index of temporary terms to a natural index
void computeTemporaryTermsMapping();
//! Write derivative code of an equation w.r. to a variable
void compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const;
//! Write chain rule derivative code of an equation w.r. to a variable
void compileChainRuleDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int var, int lag, const map_idx_t &map_idx) const;
string reform(const string& name) const;
//! Get the type corresponding to a derivation ID
SymbolType getTypeByDerivID(int deriv_id) const noexcept(false) override;
//! Get the lag corresponding to a derivation ID
int getLagByDerivID(int deriv_id) const noexcept(false) override;
//! Get the symbol ID corresponding to a derivation ID
int getSymbIDByDerivID(int deriv_id) const noexcept(false) override;
int getTypeSpecificIDByDerivID(int deriv_id) const override;
//! Compute the column indices of the dynamic Jacobian
void computeDynJacobianCols(bool jacobianExo);
void computeDynJacobianCols();
//! Computes derivatives of the Jacobian w.r. to trend vars and tests that they are equal to zero
void testTrendDerivativesEqualToZero(const eval_context_t& eval_context);
//! Collect only the first derivatives
map<tuple<int, int, int>, expr_t> collect_first_order_derivatives_endogenous();
//! Allocates the derivation IDs for all dynamic variables of the model
/*! Also computes max_{endo,exo}_{lead_lag}, and initializes dynJacobianColsNbr to the number of dynamic endos */
/*! Also computes max_{endo,exo}_{lead_lag}, and initializes dynJacobianColsNbr to the number of
* dynamic endos */
void computeDerivIDs();
//! Collecte the derivatives w.r. to endogenous of the block, to endogenous of previouys blocks and to exogenous
void collect_block_first_order_derivatives();
//! Collecte the informations about exogenous, deterministic exogenous and endogenous from the previous block for each block
void collectBlockVariables();
/* Compute the Jacobian column indices in the block decomposition case
(stored in blocks_jacob_cols_*).
Also fills auxiliary structures related to “other” endogenous and
exogenous: blocks{,_derivatives}_{other_endo,exo_exo_det} */
void computeBlockDynJacobianCols();
//! Factorized code for substitutions of leads/lags
/*! \param[in] type determines which type of variables is concerned
\param[in] deterministic_model whether we are in a deterministic model (only for exogenous leads/lags)
\param[in] subset variables to which to apply the transformation (only for diff of forward vars)
\param[in] deterministic_model whether we are in a deterministic model (only for exogenous
leads/lags) \param[in] subset variables to which to apply the transformation (only for diff of
forward vars)
*/
void substituteLeadLagInternal(AuxVarType type, bool deterministic_model, const vector<string> &subset);
//! Indicate if the temporary terms are computed for the overall model (true) or not (false). Default value true
bool global_temporary_terms{true};
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
equation_type_and_normalized_equation_t equation_type_and_normalized_equation;
//! for each block contains pair< Simulation_Type, pair < Block_Size, Recursive_part_Size >>
block_type_firstequation_size_mfs_t block_type_firstequation_size_mfs;
//! for all blocks derivatives description
blocks_derivatives_t blocks_derivatives;
//! The jacobian without the elements below the cutoff
dynamic_jacob_map_t dynamic_jacobian;
//! Vector indicating if the block is linear in endogenous variable (true) or not (false)
vector<bool> blocks_linear;
//! Map the derivatives for a block tuple<lag, eq, var>
using derivative_t = map<tuple<int, int, int>, expr_t>;
//! Vector of derivative for each blocks
vector<derivative_t> derivative_endo, derivative_other_endo, derivative_exo, derivative_exo_det;
//!List for each block and for each lag-lead all the other endogenous variables and exogenous variables
using var_t = set<int>;
using lag_var_t = map<int, var_t>;
vector<lag_var_t> other_endo_block, exo_block, exo_det_block;
//!List for each block the exogenous variables
vector<pair<var_t, int>> block_var_exo;
map< int, map<int, int>> block_exo_index, block_det_exo_index, block_other_endo_index;
//! for each block described the number of static, forward, backward and mixed variables in the block
/*! tuple<static, forward, backward, mixed> */
vector<tuple<int, int, int, int>> block_col_type;
void substituteLeadLagInternal(AuxVarType type, bool deterministic_model,
const vector<string>& subset);
//! Help computeXrefs to compute the reverse references (i.e. param->eqs, endo->eqs, etc)
void computeRevXref(map<pair<int, int>, set<int>> &xrefset, const set<pair<int, int>> &eiref, int eqn);
void computeRevXref(map<pair<int, int>, set<int>>& xrefset, const set<pair<int, int>>& eiref,
int eqn);
//! Write reverse cross references
void writeRevXrefs(ostream &output, const map<pair<int, int>, set<int>> &xrefmap, const string &type) const;
//! List for each variable its block number and its maximum lag and lead inside the block
vector<tuple<int, int, int>> variable_block_lead_lag;
//! List for each equation its block number
vector<int> equation_block;
//! Used for var_expectation and var_model
map<string, set<int>> var_expectation_functions_to_write;
//!Maximum lead and lag for each block on endogenous of the block, endogenous of the previous blocks, exogenous and deterministic exogenous
vector<pair<int, int>> endo_max_leadlag_block, other_endo_max_leadlag_block, exo_max_leadlag_block, exo_det_max_leadlag_block, max_leadlag_block;
void writeWrapperFunctions(const string &name, const string &ending) const;
void writeDynamicModelHelper(const string &basename,
const string &name, const string &retvalname,
const string &name_tt, size_t ttlen,
const string &previous_tt_name,
const ostringstream &init_s,
const ostringstream &end_s,
void writeRevXrefs(ostream& output, const map<pair<int, int>, set<int>>& xrefmap,
const string& type) const;
/* Writes MATLAB/Octave wrapper function for computing residuals and
derivatives at the same time (legacy representation) */
void writeDynamicMWrapperFunction(const string& name, const string& ending) const;
/* Helper for writing MATLAB/Octave functions for residuals/derivatives and
their temporary terms (legacy representation) */
void writeDynamicMFileHelper(const string& basename, const string& name, const string& retvalname,
const string& name_tt, size_t ttlen, const string& previous_tt_name,
const ostringstream& init_s, const ostringstream& end_s,
const ostringstream& s, const ostringstream& s_tt) const;
//! Create a legacy *_dynamic.m file for Matlab/Octave not yet using the temporary terms array interface
void writeDynamicMatlabCompatLayer(const string &basename) const;
vector<int> getEquationNumbersFromTags(const set<string> &eqtags) const;
void findPacExpectationEquationNumbers(vector<int> &eqnumber) const;
/* Create the compatibility dynamic.m file for MATLAB/Octave not yet using
the temporary terms array interface (legacy representation) */
void writeDynamicMCompatFile(const string& basename) const;
//! Internal helper for the copy constructor and assignment operator
/*! Copies all the structures that contain ExprNode*, by the converting the
pointers into their equivalent in the new tree */
void copyHelper(const DynamicModel& m);
// Internal helper functions for includeExcludeEquations()
/*! Handles parsing of argument passed to exclude_eqs/include_eqs*/
/*
Expects command line arguments of the form:
/* Handles parsing of argument passed to exclude_eqs/include_eqs.
The argument inc_exc_option_value should be of one of the following forms:
* filename.txt
* eq1
* ['eq 1', 'eq 2']
* [tagname='eq 1']
* [tagname=('eq 1', 'eq 2')]
If argument is a file, the file should be formatted as:
If argument is a filename, the file should be formatted as:
eq 1
eq 2
OR
tagname=
X
Y
The boolean exclude_eqs should be true if we are in the exclude_eqs case,
false in the include_eqs case (this only affects error messages).
Returns a set of pairs (tag name, tag value) corresponding to the set of
equations to be included or excluded.
*/
void parseIncludeExcludeEquations(const string &inc_exc_eq_tags, set<pair<string, string>> & eq_tag_set, bool exclude_eqs);
static vector<map<string, string>>
parseIncludeExcludeEquations(const string& inc_exc_option_value, bool exclude_eqs);
/* Helper for the removeEquations() method.
listed_eqs_by_tag describes a list of equations to remove (identified by
one or more tags; if multiple tags are present for a single equation, they
are understood as a conjunction), exclude_eqs is a boolean indicating whether we’re
excluding or including, and excluded_vars_change_type is a boolean
indicating whether to compute variables to be excluded.
The all_equations* arguments will be modified by the routine by excluding
equations. They are either the main structures for storing equations in
ModelTree, or their counterpart for static-only equations. The
static_equations boolean indicates when we are in the latter case.
The listed_eqs_by_tag structure will be updated by removing the tags
matched with equations in the all_equations* argument*.
Returns a list of excluded variables (empty if
excluded_vars_change_type=false) */
vector<int> removeEquationsHelper(
set<map<string, string>>& listed_eqs_by_tag, bool exclude_eqs, bool excluded_vars_change_type,
vector<BinaryOpNode*>& all_equations, vector<optional<int>>& all_equations_lineno,
vector<optional<tuple<int, expr_t, expr_t>>>& all_complementarity_conditions,
EquationTags& all_equation_tags, bool static_equations) const;
//! Compute autoregressive matrices of trend component models
/* The algorithm uses matching rules over expression trees. It cannot handle
arbitrarily-written expressions. */
map<string, map<tuple<int, int, int>, expr_t>> computeAutoregressiveMatrices() const;
//! Compute error component matrices of trend component_models
/*! Returns a pair (A0r, A0starr) */
pair<map<string, map<tuple<int, int>, expr_t>>, map<string, map<tuple<int, int>, expr_t>>>
computeErrorComponentMatrices(const ExprNode::subst_table_t& diff_subst_table) const;
/* For a VAR model, given the symbol ID of a LHS variable, and a (negative)
lag, returns all the corresponding deriv_ids (by properly dealing with two
types of auxiliary variables: endo lags and diff lags). It returns a
vector because in some cases there may be sereval corresponding deriv_ids
(for example, in the deriv_id table, AUX_DIFF_nn(-1) may appear as itself
(with a lag), and also as a contemporaneous diff lag auxvar). */
vector<int> getVARDerivIDs(int lhs_symb_id, int lead_lag) const;
int
getBlockJacobianEndoCol(int blk, int var, int lag) const override
{
return blocks_jacob_cols_endo[blk].at({var, lag});
}
// Used to check consistency of bind/relax tags; the keys are equation names
map<string, OccbinRegimeTracker> occbin_regime_trackers;
// General function that removes leading/trailing whitespace from a string
inline void removeLeadingTrailingWhitespace(string & str)
protected:
string
modelClassName() const override
{
str.erase(0, str.find_first_not_of("\t\n\v\f\r "));
str.erase(str.find_last_not_of("\t\n\v\f\r ") + 1);
return "dynamic model";
}
public:
DynamicModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg,
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);
DynamicModel(const DynamicModel& m);
DynamicModel(DynamicModel &&) = delete;
DynamicModel& operator=(const DynamicModel& m);
DynamicModel & operator=(DynamicModel &&) = delete;
//! Compute cross references
void computeXrefs();
......@@ -313,18 +339,18 @@ public:
//! Write cross references
void writeXrefs(ostream& output) const;
//! Execute computations (variable sorting + derivation)
//! Execute computations (variable sorting + derivation + block decomposition)
/*!
\param jacobianExo whether derivatives w.r. to exo and exo_det should be in the Jacobian (derivatives w.r. to endo are always computed)
\param derivsOrder order of derivatives w.r. to exo, exo_det and endo should be computed (implies jacobianExo = true when order >= 2)
\param paramsDerivsOrder order of derivatives w.r. to a pair (endo/exo/exo_det, parameter) to be computed (>0 implies jacobianExo = true)
\param eval_context evaluation context for normalization
\param no_tmp_terms if true, no temporary terms will be computed in the dynamic files
\param derivsOrder order of derivatives w.r. to exo, exo_det and endo should be computed
(implies jacobianExo = true when order >= 2) \param paramsDerivsOrder order of derivatives w.r.
to a pair (endo/exo/exo_det, parameter) to be computed (>0 implies jacobianExo = true) \param
eval_context evaluation context for normalization \param no_tmp_terms if true, no temporary
terms will be computed in the dynamic files
*/
void computingPass(bool jacobianExo, int derivsOrder, int paramsDerivsOrder,
const eval_context_t &eval_context, bool no_tmp_terms, bool block, bool use_dll, bool bytecode, bool linear_decomposition);
//! Writes model initialization and lead/lag incidence matrix to output
void writeOutput(ostream &output, const string &basename, bool block, bool linear_decomposition, bool byte_code, bool use_dll, int order, bool estimation_present, bool compute_xrefs, bool julia) const;
void computingPass(int derivsOrder, int paramsDerivsOrder, const eval_context_t& eval_context,
bool no_tmp_terms, bool block, bool use_dll);
//! Writes information about the dynamic model to the driver file
void writeDriverOutput(ostream& output, bool compute_xrefs) const;
//! Write JSON AST
void writeJsonAST(ostream& output) const;
......@@ -344,78 +370,69 @@ public:
//! Write JSON Output representation of dynamic model after computing pass
void writeJsonComputingPassOutput(ostream& output, bool writeDetails) const;
//! Write JSON prams derivatives file
void writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const;
//! Write JSON params derivatives
void writeJsonParamsDerivatives(ostream& output, bool writeDetails) const;
//! Write cross reference output if the xref maps have been filed
void writeJsonXrefs(ostream& output) const;
void writeJsonXrefsHelper(ostream &output, const map<pair<int, int>, set<int>> &xrefs) const;
void writeJsonXrefsHelper(ostream& output, const map<pair<int, int>, set<int>>& xrefmap) const;
//! Print equations that have non-zero second derivatives
void printNonZeroHessianEquations(ostream& output) const;
//! Set the equations that have non-zero second derivatives
void setNonZeroHessianEquations(map<int, string> &eqs);
//! Tells whether Hessian has been computed
/*! This is needed to know whether no non-zero equation in Hessian means a
zero Hessian or Hessian not computed */
bool
isHessianComputed() const
{
return computed_derivs_order >= 2;
}
//! Fill Autoregressive Matrix for var_model
map<string, map<tuple<int, int, int>, expr_t>> fillAutoregressiveMatrix(bool is_var) const;
/* Check whether the model is linear, by verifying that the hessian is zero,
and error out otherwise.
Must be called after computingPass().
FIXME: this check always passes if derivsOrder = 1, i.e. for a perfect
foresight model, because the Hessian is not computed in that case. */
void checkIsLinear() const;
//! Fill Error Component Matrix for trend_component_model
/*! Returns a pair (A0r, A0starr) */
pair<map<string, map<tuple<int, int, int>, expr_t>>, map<string, map<tuple<int, int, int>, expr_t>>> fillErrorComponentMatrix(const ExprNode::subst_table_t &diff_subst_table) const;
//! Fill the Trend Component Model Table
//! Fill the trend component model table with information available from the transformed model
void fillTrendComponentModelTable() const;
//! Fill the trend component model table with information available from the original model
void fillTrendComponentModelTableFromOrigModel() const;
void fillTrendComponentmodelTableAREC(const ExprNode::subst_table_t &diff_subst_table) const;
//! Fill the Var Model Table
/* Fill the trend component model table with information about AR/EC
components, available from the transformed model. Needs to be called after
fillTrendComponentModelTableFromOrigModel() has been called on the
original model */
void fillTrendComponentModelTableAREC(const ExprNode::subst_table_t& diff_subst_table) const;
//! Fill the VAR model table with information available from the transformed model
// NB: Does not fill the AR and A0 matrices
void fillVarModelTable() const;
//! Fill the VAR model table with information available from the original model
void fillVarModelTableFromOrigModel() const;
//! Fill the AR and A0 matrices of the VAR model table
// Uses derivatives, hence must be called after computingPass()
void fillVarModelTableMatrices();
//! Update the rhs references in the var model and trend component tables
//! after substitution of auxiliary variables and find the trend variables
//! in the trend_component model
void updateVarAndTrendModel() const;
//! Add aux equations (and aux variables) for variables declared in var_model
//! at max order if they don't already exist
void addEquationsForVar();
//! Get Pac equation parameter info
map<pair<string, string>, pair<string, int>> walkPacParameters(const string &name);
//! Add var_model info to pac_expectation nodes
void fillPacModelInfo(const string &pac_model_name,
vector<int> lhs,
int max_lag,
string aux_model_type,
const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
const vector<bool> &nonstationary,
expr_t growth);
//! Writes dynamic model file (+ bytecode)
void writeDynamicFile(const string& basename, bool use_dll, const string& mexext,
const filesystem::path& matlabroot, bool julia) const;
//! Substitutes pac_expectation operator with expectation based on auxiliary model
void substitutePacExpectation(const string & pac_model_name);
//! Adds informations for simulation in a binary file
void Write_Inf_To_Bin_File_Block(const string &basename,
const int &num, int &u_count_int, bool &file_open, bool is_two_boundaries, const bool linear_decomposition) const;
//! Writes dynamic model file
void writeDynamicFile(const string &basename, bool block, bool linear_decomposition, bool bytecode, bool use_dll, const string &mexext, const filesystem::path &matlabroot, const filesystem::path &dynareroot, int order, bool julia) const;
//! Writes file containing parameters derivatives
void writeParamsDerivativesFile(const string &basename, bool julia) const;
//! Writes file containing coordinates of non-zero elements in the Jacobian
/*! Used by the perfect_foresight_problem MEX */
void writeDynamicJacobianNonZeroElts(const string &basename) const;
//! Converts to nonlinear model (only the equations)
/*! It assumes that the nonlinear model given in argument has just been allocated */
void toNonlinearPart(DynamicModel &non_linear_equations_dynamic_model) const;
template<bool julia>
void writeParamsDerivativesFile(const string& basename) const;
//! Creates mapping for variables and equations they are present in
void createVariableMapping(int orig_eq_nbr);
void createVariableMapping();
//! Expands equation tags with default equation names (available "name" tag or LHS variable or equation ID)
//! Expands equation tags with default equation names (available "name" tag or LHS variable or
//! equation ID)
void expandEqTags();
//! Find endogenous variables not used in model
......@@ -426,16 +443,36 @@ public:
//! Set the max leads/lags of the original model
void setLeadsLagsOrig();
//! Removes equations from the model according to name tags
void includeExcludeEquations(const string & eqs, bool exclude_eqs);
//! Implements the include_eqs/exclude_eqs options
void includeExcludeEquations(const string& inc_exc_option_value, bool exclude_eqs);
/* Removes equations from the model (identified by one or more tags; if
multiple tags are present for a single equation, they are understood as a
conjunction).
Used for include_eqs/exclude_eqs options and for model_remove and
model_replace blocks */
void removeEquations(const vector<map<string, string>>& listed_eqs_by_tag, bool exclude_eqs,
bool excluded_vars_change_type);
/* Replaces model equations with derivatives of Lagrangian w.r.t. endogenous.
The optimality FOCs (derivatives w.r.t. ordinary endogenous) will appear
first, followed by the constraints (derivatives w.r.t. multipliers).
Returns the number of optimality FOCs, which is by construction equal to
the number of endogenous before adding the Lagrange multipliers
(internally called ramsey_endo_nbr). */
int computeRamseyPolicyFOCs(const StaticModel& planner_objective,
map<int, pair<expr_t, expr_t>> cloned_ramsey_constraints);
//! Clears all equations
void clearEquations();
//! Replaces model equations with derivatives of Lagrangian w.r.t. endogenous
void computeRamseyPolicyFOCs(const StaticModel &static_model);
//! Replaces the model equations in dynamic_model with those in this model
void replaceMyEquations(DynamicModel& dynamic_model) const;
//! Adds an equation marked as [static]
void addStaticOnlyEquation(expr_t eq, int lineno, const vector<pair<string, string>> &eq_tags);
void addStaticOnlyEquation(expr_t eq, const optional<int>& lineno,
optional<tuple<int, expr_t, expr_t>> complementarity_condition,
map<string, string> eq_tags);
//! Returns number of static only equations
size_t staticOnlyEquationsNbr() const;
......@@ -443,22 +480,66 @@ public:
//! Returns number of dynamic only equations
size_t dynamicOnlyEquationsNbr() const;
// Adds an occbin equation (with “bind” and/or “relax” tag)
/* This function assumes that there is a “name” tag, and that the relevant
auxiliary parameters have already been added to the symbol table.
It also assumes that the “bind” and “relax” tags have been cleared from
eq_tags. */
void addOccbinEquation(expr_t eq, const optional<int>& lineno, map<string, string> eq_tags,
const vector<string>& constraints_bind,
const vector<string>& constraints_relax);
//! Writes LaTeX file with the equations of the dynamic model
void writeLatexFile(const string &basename, const bool write_equation_tags) const;
void writeLatexFile(const string& basename, bool write_equation_tags) const;
//! Writes LaTeX file with the equations of the dynamic model (for the original model)
void writeLatexOriginalFile(const string &basename, const bool write_equation_tags) const;
void writeLatexOriginalFile(const string& basename, bool write_equation_tags) const;
int getDerivID(int symb_id, int lag) const noexcept(false) override;
int getDynJacobianCol(int deriv_id) const noexcept(false) override;
void addAllParamDerivId(set<int> &deriv_id_set) override;
//! Returns true indicating that this is a dynamic model
bool
isDynamic() const override
int
getJacobianCol(int deriv_id, bool sparse) const override
{
return true;
};
if (sparse)
{
SymbolType type {getTypeByDerivID(deriv_id)};
int tsid {getTypeSpecificIDByDerivID(deriv_id)};
int lag {getLagByDerivID(deriv_id)};
if (type == SymbolType::endogenous)
{
assert(lag >= -1 && lag <= 1);
return tsid + (lag + 1) * symbol_table.endo_nbr();
}
else if (type == SymbolType::exogenous)
{
assert(lag == 0);
return tsid + 3 * symbol_table.endo_nbr();
}
else if (type == SymbolType::exogenousDet)
{
assert(lag == 0);
return tsid + 3 * symbol_table.endo_nbr() + symbol_table.exo_nbr();
}
else
throw UnknownDerivIDException();
}
else
{
if (auto it = dyn_jacobian_cols_table.find(deriv_id); it == dyn_jacobian_cols_table.end())
throw UnknownDerivIDException();
else
return it->second;
}
}
int
getJacobianColsNbr(bool sparse) const override
{
return sparse
? 3 * symbol_table.endo_nbr() + symbol_table.exo_nbr() + symbol_table.exo_det_nbr()
: dyn_jacobian_ncols;
}
void addAllParamDerivId(set<int>& deriv_id_set) override;
//! Drive test of detrended equations
void runTrendTest(const eval_context_t& eval_context);
......@@ -480,69 +561,130 @@ public:
//! 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
//! Transforms the model by decreasing the lead/lag of predetermined variables in model equations
//! by one
void transformPredeterminedVariables();
// 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);
//! Transforms the model by removing trends specified by the user
void detrendEquations();
const nonstationary_symbols_map_t&
getNonstationarySymbolsMap() const
{
return nonstationary_symbols_map;
}
const map<int, expr_t>&
getTrendSymbolsMap() const
{
return trend_symbols_map;
}
//! Substitutes adl operator
void substituteAdl();
//! Creates aux vars for all unary operators
pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps();
//! Substitutes out all model-local variables
void substituteModelLocalVariables();
//! Creates aux vars for unary operators in certain equations: originally implemented for support of VARs
pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps(const set<string> &eq_tags);
/* Creates aux vars for all unary operators in all equations. Also makes the
substitution in growth terms of pac_model/pac_target_info and in
expressions of var_expectation_model. */
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteUnaryOps(VarExpectationModelTable& var_expectation_model_table,
PacModelTable& pac_model_table);
//! Creates aux vars for unary operators in certain equations: originally implemented for support of VARs
pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteUnaryOps(const vector<int> &eqnumbers);
/* Creates aux vars for all unary operators in specified equations. Also makes the
substitution in growth terms of pac_model/pac_target_info and in
expressions of var_expectation_model. */
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteUnaryOps(const set<int>& eqnumbers,
VarExpectationModelTable& var_expectation_model_table,
PacModelTable& pac_model_table);
//! Substitutes diff operator
pair<lag_equivalence_table_t, ExprNode::subst_table_t> substituteDiff(vector<expr_t> &pac_growth);
pair<lag_equivalence_table_t, ExprNode::subst_table_t>
substituteDiff(VarExpectationModelTable& var_expectation_model_table,
PacModelTable& pac_model_table);
//! Substitute VarExpectation operators
void substituteVarExpectation(const map<string, expr_t>& subst_table);
//! Return max lag of pac equation
void getPacMaxLag(const string &pac_model_name, map<pair<string, string>, pair<string, int>> &eqtag_and_lag) const;
void analyzePacEquationStructure(const string& name, map<string, string>& pac_eq_name,
PacModelTable::equation_info_t& pac_equation_info);
// Exception thrown by getPacTargetSymbId()
struct PacTargetNotIdentifiedException
{
const string model_name, message;
};
//! Return target of the pac equation
int getPacTargetSymbId(const string& pac_model_name) const;
//! Declare Z1 variables before creating aux vars so it comes right after the endo names declared by the user
void declarePacModelConsistentExpectationEndogs(const string &name);
//! Add model consistent expectation equation for pac model
void addPacModelConsistentExpectationEquation(const string & name, int discount,
const map<pair<string, string>, pair<string, int>> &eqtag_and_lag,
ExprNode::subst_table_t &diff_subst_table);
//! store symb_ids for alphas created in addPacModelConsistentExpectationEquation
//! (pac_model_name, standardized_eqtag) -> mce_alpha_symb_id
map<pair<string, string>, vector<int>> pac_mce_alpha_symb_ids;
//! store symb_ids for h0, h1 parameters
//! (pac_model_name, standardized_eqtag) -> parameter symb_ids
map<pair<string, string>, vector<int>> pac_h0_indices, pac_h1_indices;
//! store symb_ids for z1s created in addPacModelConsistentExpectationEquation
//! (pac_model_name, standardized_eqtag) -> mce_z1_symb_id
map<pair<string, string>, int> pac_mce_z1_symb_ids;
//! Store lag info for pac equations
//! (pac_model_name, equation_tag) -> (standardized_eqtag, lag)
map<pair<string, string>, pair<string, int>> pac_eqtag_and_lag;
//! (pac_model_name, equation_tag) -> expr_t
map<pair<string, string>, expr_t> pac_expectation_substitution;
//! Store info about pac models:
//! pac_model_name -> (lhsvars, growth_param_index, aux_model_type)
map<string, tuple<vector<int>, int, string>> pac_model_info;
//! Store info about pac models specific to the equation they appear in
//! (pac_model_name, standardized_eqtag) ->
//! (lhs, optim_share_index, ar_params_and_vars, ec_params_and_vars, non_optim_vars_params_and_constants, additive_vars_params_and_constants, optim_additive_vars_params_and_constants)
map<pair<string, string>,
tuple<pair<int, int>, int, set<pair<int, pair<int, int>>>, pair<int, vector<tuple<int, bool, int>>>, vector<tuple<int, int, int, double>>, vector<tuple<int, int, int, double>>, vector<tuple<int, int, int, double>>>> pac_equation_info;
/* For a PAC MCE model, fill pac_expectation_substitution with the
expression that will be substituted for the pac_expectation operator.
In the process, add the variable and the equation defining Z₁.
The symbol IDs of the new endogenous are added to pac_aux_var_symb_ids,
and the new auxiliary parameters to pac_mce_alpha_symb_ids.
*/
void computePacModelConsistentExpectationSubstitution(
const string& name, int discount_symb_id, int pac_eq_max_lag, expr_t growth_correction_term,
string auxname, ExprNode::subst_table_t& diff_subst_table,
map<string, int>& pac_aux_var_symb_ids, map<string, vector<int>>& pac_aux_param_symb_ids,
map<string, expr_t>& pac_expectation_substitution);
/* For a PAC MCE model with an associated pac_target_info, fill pac_expectation_substitution with
the expression that will be substituted for the pac_expectation operator. In the process, add
the variables and the equations defining Z₁ and Z₀ for each component. The new auxiliary
parameters are added to pac_mce_alpha_symb_ids. The routine also creates the auxiliary
variables for the components, and adds the corresponding equations.
*/
void computePacModelConsistentExpectationSubstitutionWithComponents(
const string& name, int discount_symb_id, int pac_eq_max_lag,
ExprNode::subst_table_t& diff_subst_table, map<string, vector<int>>& pac_aux_param_symb_ids,
vector<PacModelTable::target_component_t>& pac_target_components,
map<string, expr_t>& pac_expectation_substitution);
/* For a PAC backward model, fill pac_expectation_substitution with the
expression that will be substituted for the pac_expectation operator.
The symbol IDs of the new parameters are also added to pac_aux_param_symb_ids.
The symbol ID of the new auxiliary variable is added to pac_aux_var_symb_ids. */
void computePacBackwardExpectationSubstitution(const string& name, const vector<int>& lhs,
int max_lag, const string& aux_model_type,
expr_t growth_correction_term, string auxname,
map<string, int>& pac_aux_var_symb_ids,
map<string, vector<int>>& pac_aux_param_symb_ids,
map<string, expr_t>& pac_expectation_substitution);
/* Same as above, but for PAC models which have an associated
pac_target_info.
Contrary to the above routine, this one will create the growth correction
parameters as needed.
Those parameter IDs, as well as the IDs for the h parameters, are stored
in target_components.
The routine also creates the auxiliary variables for the components, and
adds the corresponding equations. */
void computePacBackwardExpectationSubstitutionWithComponents(
const string& name, const vector<int>& lhs, int max_lag, const string& aux_model_type,
vector<PacModelTable::target_component_t>& pac_target_components,
map<string, expr_t>& pac_expectation_substitution);
//! Substitutes pac_expectation operator with expectation based on auxiliary model
void substitutePacExpectation(const map<string, expr_t>& pac_expectation_substitution,
const map<string, string>& pac_eq_name);
//! Substitutes the pac_target_nonstationary operator of a given pac_model
void substitutePacTargetNonstationary(const string& pac_model_name, expr_t substexpr);
//! Table to undiff LHS variables for pac vector z
vector<int> getUndiffLHSForPac(const string& aux_model_name,
......@@ -559,200 +701,265 @@ public:
//! Fills eval context with values of model local variables and auxiliary variables
void fillEvalContext(eval_context_t& eval_context) const;
auto getStaticOnlyEquationsInfo() const { return tuple(static_only_equations, static_only_equations_lineno, static_only_equations_equation_tags); };
/*! Checks that all pac_expectation operators have been substituted, error
out otherwise */
void checkNoRemainingPacExpectation() const;
//! Return the number of blocks
unsigned int
getNbBlocks() const override
{
return (block_type_firstequation_size_mfs.size());
};
//! Determine the simulation type of each block
BlockSimulationType
getBlockSimulationType(int block_number) const override
{
return (get<0>(block_type_firstequation_size_mfs[block_number]));
};
//! Return the first equation number of a block
unsigned int
getBlockFirstEquation(int block_number) const override
{
return (get<1>(block_type_firstequation_size_mfs[block_number]));
};
//! Return the size of the block block_number
unsigned int
getBlockSize(int block_number) const override
{
return (get<2>(block_type_firstequation_size_mfs[block_number]));
};
//! Return the number of exogenous variable in the block block_number
unsigned int
getBlockExoSize(int block_number) const override
{
return (block_var_exo[block_number].first.size());
};
//! Return the number of colums in the jacobian matrix for exogenous variable in the block block_number
unsigned int
getBlockExoColSize(int block_number) const override
{
return (block_var_exo[block_number].second);
};
//! Return the number of feedback variable of the block block_number
unsigned int
getBlockMfs(int block_number) const override
{
return (get<3>(block_type_firstequation_size_mfs[block_number]));
};
//! Return the maximum lag in a block
unsigned int
getBlockMaxLag(int block_number) const override
{
return (block_lag_lead[block_number].first);
};
//! Return the maximum lead in a block
unsigned int
getBlockMaxLead(int block_number) const override
{
return (block_lag_lead[block_number].second);
};
//! Return the type of equation (equation_number) belonging to the block block_number
EquationType
getBlockEquationType(int block_number, int equation_number) const override
{
return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first);
};
//! Return true if the equation has been normalized
bool
isBlockEquationRenormalized(int block_number, int equation_number) const override
{
return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].first == E_EVALUATE_S);
};
//! Return the expr_t of the equation equation_number belonging to the block block_number
expr_t
getBlockEquationExpr(int block_number, int equation_number) const override
{
return (equations[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]]);
};
//! Return the expr_t of the renormalized equation equation_number belonging to the block block_number
expr_t
getBlockEquationRenormalizedExpr(int block_number, int equation_number) const override
{
return (equation_type_and_normalized_equation[equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]].second);
};
//! Return the original number of equation equation_number belonging to the block block_number
int
getBlockEquationID(int block_number, int equation_number) const override
{
return (equation_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+equation_number]);
};
//! Return the original number of variable variable_number belonging to the block block_number
int
getBlockVariableID(int block_number, int variable_number) const override
{
return (variable_reordered[get<1>(block_type_firstequation_size_mfs[block_number])+variable_number]);
};
//! Return the original number of the exogenous variable varexo_number belonging to the block block_number
int
getBlockVariableExoID(int block_number, int variable_number) const override
{
auto it = exo_block[block_number].find(variable_number);
return (it->first);
};
//! Return the position of equation_number in the block number belonging to the block block_number
int
getBlockInitialEquationID(int block_number, int equation_number) const override
{
return (static_cast<int>(inv_equation_reordered[equation_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number])));
};
//! Return the position of variable_number in the block number belonging to the block block_number
int
getBlockInitialVariableID(int block_number, int variable_number) const override
{
return (static_cast<int>(inv_variable_reordered[variable_number]) - static_cast<int>(get<1>(block_type_firstequation_size_mfs[block_number])));
};
//! Return the block number containing the endogenous variable variable_number
int
getBlockVariableID(int variable_number) const
{
return (get<0>(variable_block_lead_lag[variable_number]));
};
//! Return the position of the exogenous variable_number in the block number belonging to the block block_number
int
getBlockInitialExogenousID(int block_number, int variable_number) const override
{
auto it = block_exo_index.find(block_number);
if (it != block_exo_index.end())
/*! Checks that all pac_target_nonstationary operators have been substituted, error
out otherwise */
void checkNoRemainingPacTargetNonstationary() const;
auto
getStaticOnlyEquationsInfo() const
{
auto it1 = it->second.find(variable_number);
if (it1 != it->second.end())
return it1->second;
else
return -1;
return tuple {static_only_equations, static_only_equations_lineno,
static_only_complementarity_conditions, static_only_equations_equation_tags};
}
else
return (-1);
};
//! Return the position of the deterministic exogenous variable_number in the block number belonging to the block block_number
//! Returns true if a parameter was used in the model block with a lead or lag
bool ParamUsedWithLeadLag() const;
bool isChecksumMatching(const string& basename) const;
//! Simplify model equations: if a variable is equal to a constant, replace that variable
//! elsewhere in the model
/*! Equations with MCP tags are excluded, see dynare#1697 */
void simplifyEquations();
// Converts a set of equation tags into the corresponding set of equation numbers
set<int> getEquationNumbersFromTags(const set<string>& eqtags) const;
// Returns the set of equations (as numbers) which have a pac_expectation operator
set<int> findPacExpectationEquationNumbers() const;
int
getBlockInitialDetExogenousID(int block_number, int variable_number) const override
{
auto it = block_det_exo_index.find(block_number);
if (it != block_det_exo_index.end())
getMFS() const override
{
auto it1 = it->second.find(variable_number);
if (it1 != it->second.end())
return it1->second;
else
return -1;
return mfs;
}
else
return (-1);
};
//! Return the position of the other endogenous variable_number in the block number belonging to the block block_number
int
getBlockInitialOtherEndogenousID(int block_number, int variable_number) const override
{
auto it = block_other_endo_index.find(block_number);
if (it != block_other_endo_index.end())
void
setMFS(int mfs_arg)
{
auto it1 = it->second.find(variable_number);
if (it1 != it->second.end())
return it1->second;
else
return -1;
mfs = mfs_arg;
}
else
return (-1);
};
bool isModelLocalVariableUsed() const;
//! Returns true if a parameter was used in the model block with a lead or lag
bool ParamUsedWithLeadLag() const;
void
setStaticMFS(int static_mfs_arg)
{
static_mfs = static_mfs_arg;
}
bool isChecksumMatching(const string &basename, bool block) const;
// Checks that all alternatives are declared for all Occbin regimes in all equations
void checkOccbinRegimes() const;
};
//! Classes to re-order derivatives for various sparse storage formats
class derivative
template<bool julia>
void
DynamicModel::writeParamsDerivativesFile(const string& basename) const
{
public:
long unsigned int linear_address;
long unsigned int col_nbr;
unsigned int row_nbr;
expr_t value;
derivative(long unsigned int arg1, long unsigned int arg2, int arg3, expr_t arg4) :
linear_address(arg1), col_nbr(arg2), row_nbr(arg3), value(arg4)
{
};
};
if (!params_derivatives.size())
return;
constexpr ExprNodeOutputType output_type {julia ? ExprNodeOutputType::juliaDynamicModel
: ExprNodeOutputType::matlabDynamicModel};
auto [tt_output, rp_output, gp_output, rpp_output, gpp_output, hp_output,
g3p_output] {writeParamsDerivativesFileHelper<output_type>()};
class derivative_less_than
if constexpr (!julia)
{
public:
bool
operator()(const derivative &d1, const derivative &d2) const
filesystem::path filename {packageDir(basename) / "dynamic_params_derivs.m"};
ofstream paramsDerivsFile {filename, ios::out | ios::binary};
if (!paramsDerivsFile.is_open())
{
return d1.linear_address < d2.linear_address;
cerr << "ERROR: Can't open file " << filename.string() << " for writing" << endl;
exit(EXIT_FAILURE);
}
};
paramsDerivsFile
<< "function [rp, gp, rpp, gpp, hp, g3p] = dynamic_params_derivs(y, x, params, "
"steady_state, it_, ss_param_deriv, ss_param_2nd_deriv)"
<< endl
<< "%" << endl
<< "% Compute the derivatives of the dynamic model with respect to the parameters" << endl
<< "% Inputs :" << endl
<< "% y [#dynamic variables by 1] double vector of endogenous variables in "
"the order stored"
<< endl
<< "% in M_.lead_lag_incidence; see the "
"Manual"
<< endl
<< "% x [nperiods by M_.exo_nbr] double matrix of exogenous variables (in "
"declaration order)"
<< endl
<< "% for all simulation periods" << endl
<< "% params [M_.param_nbr by 1] double vector of parameter values in "
"declaration order"
<< endl
<< "% steady_state [M_.endo_nbr by 1] double vector of steady state values"
<< endl
<< "% it_ scalar double time period for exogenous "
"variables for which to evaluate the model"
<< endl
<< "% ss_param_deriv [M_.eq_nbr by #params] Jacobian matrix of the steady "
"states values with respect to the parameters"
<< endl
<< "% ss_param_2nd_deriv [M_.eq_nbr by #params by #params] Hessian matrix of the "
"steady states values with respect to the parameters"
<< endl
<< "%" << endl
<< "% Outputs:" << endl
<< "% rp [M_.eq_nbr by #params] double Jacobian matrix of dynamic model "
"equations with respect to parameters "
<< endl
<< "% Dynare may prepend or append "
"auxiliary equations, see M_.aux_vars"
<< endl
<< "% gp [M_.endo_nbr by #dynamic variables by #params] double Derivative of "
"the Jacobian matrix of the dynamic model equations with respect to the parameters"
<< endl
<< "% rows: equations in order "
"of declaration"
<< endl
<< "% columns: variables in "
"order stored in M_.lead_lag_incidence"
<< endl
<< "% rpp [#second_order_residual_terms by 4] double Hessian matrix of second "
"derivatives of residuals with respect to parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: number of "
"the first parameter in derivative"
<< endl
<< "% 3rd column: number of "
"the second parameter in derivative"
<< endl
<< "% 4th column: value of "
"the Hessian term"
<< endl
<< "% gpp [#second_order_Jacobian_terms by 5] double Hessian matrix of second "
"derivatives of the Jacobian with respect to the parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: column "
"number of variable in Jacobian of the dynamic model"
<< endl
<< "% 3rd column: number of "
"the first parameter in derivative"
<< endl
<< "% 4th column: number of "
"the second parameter in derivative"
<< endl
<< "% 5th column: value of "
"the Hessian term"
<< endl
<< "% hp [#first_order_Hessian_terms by 5] double Jacobian matrix of "
"derivatives of the dynamic Hessian with respect to the parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: column "
"number of first variable in Hessian of the dynamic model"
<< endl
<< "% 3rd column: column "
"number of second variable in Hessian of the dynamic model"
<< endl
<< "% 4th column: number of "
"the parameter in derivative"
<< endl
<< "% 5th column: value of "
"the Hessian term"
<< endl
<< "% g3p [#first_order_g3_terms by 6] double Jacobian matrix of derivatives of "
"g3 (dynamic 3rd derivs) with respect to the parameters;"
<< endl
<< "% rows: respective "
"derivative term"
<< endl
<< "% 1st column: equation "
"number of the term appearing"
<< endl
<< "% 2nd column: column "
"number of first variable in g3 of the dynamic model"
<< endl
<< "% 3rd column: column "
"number of second variable in g3 of the dynamic model"
<< endl
<< "% 4th column: column "
"number of third variable in g3 of the dynamic model"
<< endl
<< "% 5th column: number of "
"the parameter in derivative"
<< endl
<< "% 6th column: value of "
"the Hessian term"
<< endl
<< "%" << endl
<< "%" << endl
<< "% Warning : this file is generated automatically by Dynare" << endl
<< "% from model file (.mod)" << endl
<< endl
<< "T = NaN(" << params_derivs_temporary_terms_idxs.size() << ",1);" << endl
<< tt_output.str() << "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< rp_output.str() << "gp = zeros(" << equations.size() << ", "
<< getJacobianColsNbr(false) << ", " << symbol_table.param_nbr() << ");" << endl
<< gp_output.str() << "if nargout >= 3" << endl
<< "rpp = zeros(" << params_derivatives.at({0, 2}).size() << ",4);" << endl
<< rpp_output.str() << "gpp = zeros(" << params_derivatives.at({1, 2}).size() << ",5);"
<< endl
<< gpp_output.str() << "end" << endl
<< "if nargout >= 5" << endl
<< "hp = zeros(" << params_derivatives.at({2, 1}).size() << ",5);" << endl
<< hp_output.str() << "end" << endl
<< "if nargout >= 6" << endl
<< "g3p = zeros(" << params_derivatives.at({3, 1}).size() << ",6);" << endl
<< g3p_output.str() << "end" << endl
<< "end" << endl;
paramsDerivsFile.close();
}
else
{
stringstream output;
output << "# NB: this file was automatically generated by Dynare" << endl
<< "# from " << basename << ".mod" << endl
<< "#" << endl
<< "function dynamic_params_derivs(y, x, params, steady_state, it_,"
<< "ss_param_deriv, ss_param_2nd_deriv)" << endl
<< "@inbounds begin" << endl
<< tt_output.str() << "rp = zeros(" << equations.size() << ", "
<< symbol_table.param_nbr() << ");" << endl
<< rp_output.str() << "gp = zeros(" << equations.size() << ", "
<< getJacobianColsNbr(false) << ", " << symbol_table.param_nbr() << ");" << endl
<< gp_output.str() << "rpp = zeros(" << params_derivatives.at({0, 2}).size() << ",4);"
<< endl
<< rpp_output.str() << "gpp = zeros(" << params_derivatives.at({1, 2}).size() << ",5);"
<< endl
<< gpp_output.str() << "hp = zeros(" << params_derivatives.at({2, 1}).size() << ",5);"
<< endl
<< hp_output.str() << "g3p = zeros(" << params_derivatives.at({3, 1}).size() << ",6);"
<< endl
<< g3p_output.str() << "end" << endl
<< "return (rp, gp, rpp, gpp, hp, g3p)" << endl
<< "end" << endl;
writeToFileIfModified(output, filesystem::path {basename} / "model" / "julia"
/ "DynamicParamsDerivs.jl");
}
}
#endif