Refactor methods for writing static and dynamic files

– factorize common code between the static and the dynamic version
– reorganise language-specific code into dedicated functions
– use a function template in the main helper to do some computations
  at compile-time (using constexpr features)
master
Sébastien Villemot 2022-07-11 17:33:09 +02:00
parent c8b046ec86
commit f38c8278ae
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
9 changed files with 837 additions and 1046 deletions

View File

@ -832,12 +832,6 @@ DataTree::addAllParamDerivId([[maybe_unused]] set<int> &deriv_id_set)
{
}
int
DataTree::getDynJacobianCol([[maybe_unused]] int deriv_id) const noexcept(false)
{
throw UnknownDerivIDException();
}
bool
DataTree::isUnaryOpUsed(UnaryOpcode opcode) const
{

View File

@ -305,8 +305,21 @@ public:
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);
//! Returns the column of the Jacobian associated to a derivation ID
virtual int
getJacobianCol([[maybe_unused]] int deriv_id) const
{
throw UnknownDerivIDException();
}
//! Returns the number of columns of the Jacobian
virtual int
getJacobianColsNbr() const
{
throw UnknownDerivIDException();
}
//! Adds to the set all the deriv IDs corresponding to parameters
virtual void addAllParamDerivId(set<int> &deriv_id_set);

File diff suppressed because it is too large Load Diff

View File

@ -96,10 +96,6 @@ private:
//! Nonzero equations in the Hessian
set<int> nonzero_hessian_eqs;
//! Number of columns of dynamic jacobian
/*! Set by computeDerivID()s and computeDynJacobianCols() */
int dynJacobianColsNbr{0};
//! Creates mapping for variables and equations they are present in
map<int, set<int>> variableMapping;
@ -124,15 +120,10 @@ private:
//! Writes dynamic model file (Matlab version)
void writeDynamicMFile(const string &basename) const;
//! Writes dynamic model file (Julia version)
void writeDynamicJuliaFile(const string &dynamic_basename) const;
void writeDynamicJuliaFile(const string &basename) const;
//! Writes dynamic model file (C version)
/*! \todo add third derivatives handling */
void writeDynamicCFile(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 main dynamic function of block decomposed model (MATLAB version)
void writeDynamicBlockMFile(const string &basename) const;
//! Writes the main dynamic function of block decomposed model (C version)
@ -463,7 +454,22 @@ public:
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;
int
getJacobianCol(int deriv_id) const override
{
if (auto it = dyn_jacobian_cols_table.find(deriv_id);
it == dyn_jacobian_cols_table.end())
throw UnknownDerivIDException();
else
return it->second;
}
int
getJacobianColsNbr() const override
{
return dyn_jacobian_cols_table.size();
}
void addAllParamDerivId(set<int> &deriv_id_set) override;
//! Returns true indicating that this is a dynamic model

View File

@ -1074,7 +1074,7 @@ VariableNode::writeOutput(ostream &output, ExprNodeOutputType output_type,
case ExprNodeOutputType::juliaDynamicModel:
case ExprNodeOutputType::matlabDynamicModel:
case ExprNodeOutputType::CDynamicModel:
i = datatree.getDynJacobianCol(datatree.getDerivID(symb_id, lag)) + ARRAY_SUBSCRIPT_OFFSET(output_type);
i = datatree.getJacobianCol(datatree.getDerivID(symb_id, lag)) + ARRAY_SUBSCRIPT_OFFSET(output_type);
output << "y" << LEFT_ARRAY_SUBSCRIPT(output_type) << i << RIGHT_ARRAY_SUBSCRIPT(output_type);
break;
case ExprNodeOutputType::CStaticModel:

View File

@ -1326,14 +1326,6 @@ ModelTree::writeJsonModelLocalVariables(ostream &output, bool write_tef_terms, d
output << "]";
}
void
ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type) const
{
temporary_terms_t tt;
temporary_terms_idxs_t ttidxs;
writeModelEquations(output, output_type, tt);
}
void
ModelTree::writeModelEquations(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms) const
@ -1599,19 +1591,6 @@ ModelTree::set_cutoff_to_zero()
cutoff = 0;
}
void
ModelTree::jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const
{
if (isJuliaOutput(output_type))
output << " @inbounds ";
output << "g1" << LEFT_ARRAY_SUBSCRIPT(output_type);
if (isMatlabOutput(output_type) || isJuliaOutput(output_type))
output << eq_nb + 1 << "," << col_nb + 1;
else
output << eq_nb + col_nb *equations.size();
output << RIGHT_ARRAY_SUBSCRIPT(output_type);
}
void
ModelTree::computeParamsDerivatives(int paramsDerivsOrder)
{

View File

@ -28,6 +28,7 @@
#include <array>
#include <filesystem>
#include <optional>
#include <cassert>
#include "DataTree.hh"
#include "EquationTags.hh"
@ -254,9 +255,13 @@ protected:
ostream &output, ExprNodeOutputType output_type,
deriv_node_temp_terms_t &tef_terms) const;
//! Writes model equations
void writeModelEquations(ostream &output, ExprNodeOutputType output_type) const;
void writeModelEquations(ostream &output, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms) const;
// Returns outputs for derivatives and temporary terms at each derivation order
template<ExprNodeOutputType output_type>
pair<vector<ostringstream>, vector<ostringstream>> writeModelFileHelper() const;
//! Writes JSON model equations
//! if residuals = true, we are writing the dynamic/static model.
//! Otherwise, just the model equations (with line numbers, no tmp terms)
@ -448,9 +453,6 @@ public:
void reorderAuxiliaryEquations();
//! Find equations of the form “variable=constant”, excluding equations with “mcp” tag (see dynare#1697)
void findConstantEquationsWithoutMcpTag(map<VariableNode *, NumConstNode *> &subst_table) const;
//! Helper for writing the Jacobian elements in MATLAB and C
/*! Writes either (i+1,j+1) or [i+j*no_eq] */
void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
/* Given an expression, searches for the first equation that has exactly this
expression on the LHS, and returns the RHS of that equation.
If no such equation can be found, throws an ExprNode::MatchFailureExpression */
@ -511,4 +513,139 @@ public:
}
};
template<ExprNodeOutputType output_type>
pair<vector<ostringstream>, vector<ostringstream>>
ModelTree::writeModelFileHelper() const
{
vector<ostringstream> d_output(derivatives.size()); // Derivatives output (at all orders, including 0=residual)
vector<ostringstream> tt_output(derivatives.size()); // Temp terms output (at all orders)
deriv_node_temp_terms_t tef_terms;
temporary_terms_t temp_term_union;
writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs,
tt_output[0], output_type, tef_terms);
writeTemporaryTerms(temporary_terms_derivatives[0],
temp_term_union,
temporary_terms_idxs,
tt_output[0], output_type, tef_terms);
writeModelEquations(d_output[0], output_type, temp_term_union);
// Writing Jacobian
if (!derivatives[1].empty())
{
writeTemporaryTerms(temporary_terms_derivatives[1],
temp_term_union,
temporary_terms_idxs,
tt_output[1], output_type, tef_terms);
for (const auto &[indices, d1] : derivatives[1])
{
auto [eq, var] = vectorToTuple<2>(indices);
if constexpr(isJuliaOutput(output_type))
d_output[1] << " @inbounds ";
d_output[1] << "g1" << LEFT_ARRAY_SUBSCRIPT(output_type);
if constexpr(isMatlabOutput(output_type) || isJuliaOutput(output_type))
d_output[1] << eq + 1 << "," << getJacobianCol(var) + 1;
else
d_output[1] << eq + getJacobianCol(var)*equations.size();
d_output[1] << RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
d1->writeOutput(d_output[1], output_type,
temp_term_union, temporary_terms_idxs, tef_terms);
d_output[1] << ";" << endl;
}
}
// Write derivatives for order ≥ 2
for (size_t i = 2; i < derivatives.size(); i++)
if (!derivatives[i].empty())
{
writeTemporaryTerms(temporary_terms_derivatives[i],
temp_term_union,
temporary_terms_idxs,
tt_output[i], output_type, tef_terms);
/* When creating the sparse matrix (in MATLAB or C mode), since storage
is in column-major order, output the first column, then the second,
then the third. This gives a significant performance boost in use_dll
mode (at both compilation and runtime), because it facilitates memory
accesses and expression reusage. */
ostringstream i_output, j_output, v_output;
for (int k{0}; // Current line index in the 3-column matrix
const auto &[vidx, d] : derivatives[i])
{
int eq{vidx[0]};
int col_idx{0};
for (size_t j = 1; j < vidx.size(); j++)
{
col_idx *= getJacobianColsNbr();
col_idx += getJacobianCol(vidx[j]);
}
if constexpr(isJuliaOutput(output_type))
{
d_output[i] << " @inbounds " << "g" << i << "[" << eq + 1 << "," << col_idx + 1 << "] = ";
d->writeOutput(d_output[i], output_type, temp_term_union, temporary_terms_idxs, tef_terms);
d_output[i] << endl;
}
else
{
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << eq + 1 << ";" << endl;
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << col_idx + 1 << ";" << endl;
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
d->writeOutput(v_output, output_type, temp_term_union, temporary_terms_idxs, tef_terms);
v_output << ";" << endl;
k++;
}
// Output symetric elements at order 2
if (i == 2 && vidx[1] != vidx[2])
{
int col_idx_sym{getJacobianCol(vidx[2]) * getJacobianColsNbr() + getJacobianCol(vidx[1])};
if constexpr(isJuliaOutput(output_type))
d_output[2] << " @inbounds g2[" << eq + 1 << "," << col_idx_sym + 1 << "] = "
<< "g2[" << eq + 1 << "," << col_idx + 1 << "]" << endl;
else
{
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << eq + 1 << ";" << endl;
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << col_idx_sym + 1 << ";" << endl;
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "="
<< "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k-1 + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
k++;
}
}
}
if constexpr(!isJuliaOutput(output_type))
d_output[i] << i_output.str() << j_output.str() << v_output.str();
}
return { move(d_output), move(tt_output) };
}
#endif

View File

@ -939,7 +939,73 @@ StaticModel::computingPass(int derivsOrder, int paramsDerivsOrder, const eval_co
void
StaticModel::writeStaticMFile(const string &basename) const
{
writeStaticModel(basename, false, false);
auto [d_output, tt_output] = writeModelFileHelper<ExprNodeOutputType::matlabStaticModel>();
// Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
map<string, string> tmp_paren_vars;
bool message_printed{false};
for (auto &it : tt_output)
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
for (auto &it : d_output)
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
ostringstream init_output, end_output;
init_output << "residual = zeros(" << equations.size() << ", 1);";
end_output << "if ~isreal(residual)" << endl
<< " residual = real(residual)+imag(residual).^2;" << endl
<< "end";
writeStaticModelHelper(basename, "static_resid", "residual", "static_resid_tt",
temporary_terms_mlv.size() + temporary_terms_derivatives[0].size(),
"", init_output, end_output,
d_output[0], tt_output[0]);
init_output.str("");
end_output.str("");
init_output << "g1 = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ");";
end_output << "if ~isreal(g1)" << endl
<< " g1 = real(g1)+2*imag(g1);" << endl
<< "end";
writeStaticModelHelper(basename, "static_g1", "g1", "static_g1_tt",
temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
"static_resid_tt",
init_output, end_output,
d_output[1], tt_output[1]);
writeWrapperFunctions(basename, "g1");
// For order ≥ 2
int ncols{symbol_table.endo_nbr()};
int ntt{static_cast<int>(temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size())};
for (size_t i{2}; i < derivatives.size(); i++)
{
ncols *= symbol_table.endo_nbr();
ntt += temporary_terms_derivatives[i].size();
string gname{"g" + to_string(i)};
string gprevname{"g" + to_string(i-1)};
init_output.str("");
end_output.str("");
if (derivatives[i].size())
{
init_output << gname << "_i = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_j = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_v = zeros(" << NNZDerivatives[i] << ",1);" << endl;
end_output << gname << " = sparse("
<< gname << "_i," << gname << "_j," << gname << "_v,"
<< equations.size() << "," << ncols << ");";
}
else
init_output << gname << " = sparse([],[],[]," << equations.size() << "," << ncols << ");";
writeStaticModelHelper(basename, "static_" + gname, gname,
"static_" + gname + "_tt",
ntt,
"static_" + gprevname + "_tt",
init_output, end_output,
d_output[i], tt_output[i]);
if (i <= 3)
writeWrapperFunctions(basename, gname);
}
writeStaticMatlabCompatLayer(basename);
}
void
@ -1098,464 +1164,13 @@ StaticModel::writeStaticMatlabCompatLayer(const string &basename) const
output.close();
}
void
StaticModel::writeStaticModel(ostream &StaticOutput, bool use_dll, bool julia) const
{
writeStaticModel("", StaticOutput, use_dll, julia);
}
void
StaticModel::writeStaticModel(const string &basename, bool use_dll, bool julia) const
{
ofstream StaticOutput;
writeStaticModel(basename, StaticOutput, use_dll, julia);
}
void
StaticModel::writeStaticModel(const string &basename,
ostream &StaticOutput, bool use_dll, bool julia) const
{
vector<ostringstream> d_output(derivatives.size()); // Derivatives output (at all orders, including 0=residual)
vector<ostringstream> tt_output(derivatives.size()); // Temp terms output (at all orders)
ExprNodeOutputType output_type = (use_dll ? ExprNodeOutputType::CStaticModel :
julia ? ExprNodeOutputType::juliaStaticModel : ExprNodeOutputType::matlabStaticModel);
deriv_node_temp_terms_t tef_terms;
temporary_terms_t temp_term_union;
writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_idxs,
tt_output[0], output_type, tef_terms);
writeTemporaryTerms(temporary_terms_derivatives[0],
temp_term_union,
temporary_terms_idxs,
tt_output[0], output_type, tef_terms);
writeModelEquations(d_output[0], output_type, temp_term_union);
int nrows = equations.size();
int JacobianColsNbr = symbol_table.endo_nbr();
int hessianColsNbr = JacobianColsNbr*JacobianColsNbr;
auto getJacobCol = [this](int var) { return symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)); };
// Write Jacobian w.r. to endogenous only
if (!derivatives[1].empty())
{
writeTemporaryTerms(temporary_terms_derivatives[1],
temp_term_union,
temporary_terms_idxs,
tt_output[1], output_type, tef_terms);
for (const auto & [indices, d1] : derivatives[1])
{
auto [eq, var] = vectorToTuple<2>(indices);
jacobianHelper(d_output[1], eq, getJacobCol(var), output_type);
d_output[1] << "=";
d1->writeOutput(d_output[1], output_type,
temp_term_union, temporary_terms_idxs, tef_terms);
d_output[1] << ";" << endl;
}
}
// Write derivatives for order ≥ 2
for (size_t i = 2; i < derivatives.size(); i++)
if (!derivatives[i].empty())
{
writeTemporaryTerms(temporary_terms_derivatives[i],
temp_term_union,
temporary_terms_idxs,
tt_output[i], output_type, tef_terms);
/* When creating the sparse matrix (in MATLAB or C mode), since storage
is in column-major order, output the first column, then the second,
then the third. This gives a significant performance boost in use_dll
mode (at both compilation and runtime), because it facilitates memory
accesses and expression reusage. */
ostringstream i_output, j_output, v_output;
for (int k{0}; // Current line index in the 3-column matrix
const auto &[vidx, d] : derivatives[i])
{
int eq = vidx[0];
int col_idx = 0;
for (size_t j = 1; j < vidx.size(); j++)
{
col_idx *= JacobianColsNbr;
col_idx += getJacobCol(vidx[j]);
}
if (output_type == ExprNodeOutputType::juliaStaticModel)
{
d_output[i] << " @inbounds " << "g" << i << "[" << eq + 1 << "," << col_idx + 1 << "] = ";
d->writeOutput(d_output[i], output_type, temp_term_union, temporary_terms_idxs, tef_terms);
d_output[i] << endl;
}
else
{
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << eq + 1 << ";" << endl;
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << col_idx + 1 << ";" << endl;
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "=";
d->writeOutput(v_output, output_type, temp_term_union, temporary_terms_idxs, tef_terms);
v_output << ";" << endl;
k++;
}
// Output symetric elements at order 2
if (i == 2 && vidx[1] != vidx[2])
{
int col_idx_sym = getJacobCol(vidx[2]) * JacobianColsNbr + getJacobCol(vidx[1]);
if (output_type == ExprNodeOutputType::juliaStaticModel)
d_output[2] << " @inbounds g2[" << eq + 1 << "," << col_idx_sym + 1 << "] = "
<< "g2[" << eq + 1 << "," << col_idx + 1 << "]" << endl;
else
{
i_output << "g" << i << "_i" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << eq + 1 << ";" << endl;
j_output << "g" << i << "_j" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type)
<< "=" << col_idx_sym + 1 << ";" << endl;
v_output << "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << "="
<< "g" << i << "_v" << LEFT_ARRAY_SUBSCRIPT(output_type)
<< k-1 + ARRAY_SUBSCRIPT_OFFSET(output_type)
<< RIGHT_ARRAY_SUBSCRIPT(output_type) << ";" << endl;
k++;
}
}
}
if (output_type != ExprNodeOutputType::juliaStaticModel)
d_output[i] << i_output.str() << j_output.str() << v_output.str();
}
if (output_type == ExprNodeOutputType::matlabStaticModel)
{
// Check that we don't have more than 32 nested parenthesis because Matlab does not suppor this. See Issue #1201
map<string, string> tmp_paren_vars;
bool message_printed = false;
for (auto &it : tt_output)
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
for (auto &it : d_output)
fixNestedParenthesis(it, tmp_paren_vars, message_printed);
ostringstream init_output, end_output;
init_output << "residual = zeros(" << equations.size() << ", 1);";
end_output << "if ~isreal(residual)" << endl
<< " residual = real(residual)+imag(residual).^2;" << endl
<< "end";
writeStaticModelHelper(basename, "static_resid", "residual", "static_resid_tt",
temporary_terms_mlv.size() + temporary_terms_derivatives[0].size(),
"", init_output, end_output,
d_output[0], tt_output[0]);
init_output.str("");
end_output.str("");
init_output << "g1 = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ");";
end_output << "if ~isreal(g1)" << endl
<< " g1 = real(g1)+2*imag(g1);" << endl
<< "end";
writeStaticModelHelper(basename, "static_g1", "g1", "static_g1_tt",
temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
"static_resid_tt",
init_output, end_output,
d_output[1], tt_output[1]);
writeWrapperFunctions(basename, "g1");
// For order ≥ 2
int ncols = JacobianColsNbr;
int ntt = temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size();
for (size_t i = 2; i < derivatives.size(); i++)
{
ncols *= JacobianColsNbr;
ntt += temporary_terms_derivatives[i].size();
string gname = "g" + to_string(i);
string gprevname = "g" + to_string(i-1);
init_output.str("");
end_output.str("");
if (derivatives[i].size())
{
init_output << gname << "_i = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_j = zeros(" << NNZDerivatives[i] << ",1);" << endl
<< gname << "_v = zeros(" << NNZDerivatives[i] << ",1);" << endl;
end_output << gname << " = sparse("
<< gname << "_i," << gname << "_j," << gname << "_v,"
<< nrows << "," << ncols << ");";
}
else
init_output << gname << " = sparse([],[],[]," << nrows << "," << ncols << ");";
writeStaticModelHelper(basename, "static_" + gname, gname,
"static_" + gname + "_tt",
ntt,
"static_" + gprevname + "_tt",
init_output, end_output,
d_output[i], tt_output[i]);
if (i <= 3)
writeWrapperFunctions(basename, gname);
}
writeStaticMatlabCompatLayer(basename);
}
else if (output_type == ExprNodeOutputType::CStaticModel)
{
for (size_t i = 0; i < d_output.size(); i++)
{
string funcname = i == 0 ? "resid" : "g" + to_string(i);
StaticOutput << "void static_" << funcname << "_tt(const double *restrict y, const double *restrict x, const double *restrict params, double *restrict T)" << endl
<< "{" << endl
<< tt_output[i].str()
<< "}" << endl
<< endl
<< "void static_" << funcname << "(const double *restrict y, const double *restrict x, const double *restrict params, const double *restrict T, ";
if (i == 0)
StaticOutput << "double *restrict residual";
else if (i == 1)
StaticOutput << "double *restrict g1";
else
StaticOutput << "double *restrict " << funcname << "_i, double *restrict " << funcname << "_j, double *restrict " << funcname << "_v";
StaticOutput << ")" << endl
<< "{" << endl;
if (i == 0)
StaticOutput << " double lhs, rhs;" << endl;
StaticOutput << d_output[i].str()
<< "}" << endl
<< endl;
}
}
else
{
stringstream output;
output << "module " << basename << "Static" << endl
<< "#" << endl
<< "# NB: this file was automatically generated by Dynare" << endl
<< "# from " << basename << ".mod" << endl
<< "#" << endl
<< "using StatsFuns" << endl << endl
<< "export tmp_nbr, static!, staticResid!, staticG1!, staticG2!, staticG3!" << endl << endl
<< "#=" << endl
<< "# The comments below apply to all functions contained in this module #" << endl
<< " NB: The arguments contained on the first line of the function" << endl
<< " definition are those that are modified in place" << endl << endl
<< "## Exported Functions ##" << endl
<< " static! : Wrapper function; computes residuals, Jacobian, Hessian," << endl
<< " and third order derivatives matroces depending on the arguments provided" << endl
<< " staticResid! : Computes the static model residuals" << endl
<< " staticG1! : Computes the static model Jacobian" << endl
<< " staticG2! : Computes the static model Hessian" << endl
<< " staticG3! : Computes the static model third derivatives" << endl << endl
<< "## Exported Variables ##" << endl
<< " tmp_nbr : Vector{Int}(4) respectively the number of temporary variables" << endl
<< " for the residuals, g1, g2 and g3." << endl << endl
<< "## Local Functions ##" << endl
<< " staticResidTT! : Computes the static model temporary terms for the residuals" << endl
<< " staticG1TT! : Computes the static model temporary terms for the Jacobian" << endl
<< " staticG2TT! : Computes the static model temporary terms for the Hessian" << endl
<< " staticG3TT! : Computes the static model temporary terms for the third derivatives" << endl << endl
<< "## Function Arguments ##" << endl
<< " T : Vector{Float64}(num_temp_terms) temporary terms" << endl
<< " y : Vector{Float64}(model_.endo_nbr) endogenous variables in declaration order" << endl
<< " x : Vector{Float64}(model_.exo_nbr) exogenous variables in declaration order" << endl
<< " params : Vector{Float64}(model_.param) parameter values in declaration order" << endl
<< " residual : Vector{Float64}(model_.eq_nbr) residuals of the static model equations" << endl
<< " in order of declaration of the equations. Dynare may prepend auxiliary equations," << endl
<< " see model.aux_vars" << endl
<< " g1 : Matrix{Float64}(model.eq_nbr,model_.endo_nbr) Jacobian matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl
<< " g2 : spzeros(model.eq_nbr, model_.endo^2) Hessian matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl
<< " g3 : spzeros(model.eq_nbr, model_.endo^3) Third order derivatives matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl << endl
<< "## Remarks ##" << endl
<< " [1] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the static model called. The number of temporary variables" << endl
<< " used for the different returned objects (residuals, jacobian, hessian or third order derivatives) is given by the elements in `tmp_nbr`" << endl
<< " exported vector. The first element is the number of temporaries used for the computation of the residuals, the second element is the" << endl
<< " number of temporaries used for the evaluation of the jacobian matrix, etc. If one calls the version of the static model computing the" << endl
<< " residuals, and the jacobian and hessian matrices, then `T` must have at least `sum(tmp_nbr[1:3])` elements." << endl
<< "=#" << endl << endl;
// Write the number of temporary terms
output << "tmp_nbr = zeros(Int,4)" << endl
<< "tmp_nbr[1] = " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << "# Number of temporary terms for the residuals" << endl
<< "tmp_nbr[2] = " << temporary_terms_derivatives[1].size() << "# Number of temporary terms for g1 (jacobian)" << endl
<< "tmp_nbr[3] = " << temporary_terms_derivatives[2].size() << "# Number of temporary terms for g2 (hessian)" << endl
<< "tmp_nbr[4] = " << temporary_terms_derivatives[3].size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl;
// staticResidTT!
output << "function staticResidTT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << endl
<< tt_output[0].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// static!
output << "function staticResid!(T::Vector{Float64}, residual::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T0_flag::Bool)" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " @assert length(residual) == " << equations.size() << endl
<< " if T0_flag" << endl
<< " staticResidTT!(T, y, x, params)" << endl
<< " end" << endl
<< d_output[0].str()
<< " if ~isreal(residual)" << endl
<< " residual = real(residual)+imag(residual).^2;" << endl
<< " end" << endl
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG1TT!
output << "function staticG1TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T0_flag::Bool)" << endl
<< " if T0_flag" << endl
<< " staticResidTT!(T, y, x, params)" << endl
<< " end" << endl
<< tt_output[1].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG1!
output << "function staticG1!(T::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() << endl
<< " @assert size(g1) == (" << equations.size() << ", " << symbol_table.endo_nbr() << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T1_flag" << endl
<< " staticG1TT!(T, y, x, params, T0_flag)" << endl
<< " end" << endl
<< " fill!(g1, 0.0)" << endl
<< d_output[1].str()
<< " if ~isreal(g1)" << endl
<< " g1 = real(g1)+2*imag(g1);" << endl
<< " end" << endl
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG2TT!
output << "function staticG2TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T1_flag::Bool, T0_flag::Bool)" << endl
<< " if T1_flag" << endl
<< " staticG1TT!(T, y, x, params, TO_flag)" << endl
<< " end" << endl
<< tt_output[2].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG2!
output << "function staticG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() << endl
<< " @assert size(g2) == (" << equations.size() << ", " << hessianColsNbr << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T2_flag" << endl
<< " staticG2TT!(T, y, x, params, T1_flag, T0_flag)" << endl
<< " end" << endl
<< " fill!(g2, 0.0)" << endl
<< d_output[2].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG3TT!
output << "function staticG3TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " if T2_flag" << endl
<< " staticG2TT!(T, y, x, params, T1_flag, T0_flag)" << endl
<< " end" << endl
<< tt_output[3].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG3!
int ncols = hessianColsNbr * JacobianColsNbr;
output << "function staticG3!(T::Vector{Float64}, g3::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T3_flag::Bool, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size() << endl
<< " @assert size(g3) == (" << nrows << ", " << ncols << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T3_flag" << endl
<< " staticG3TT!(T, y, x, params, T2_flag, T1_flag, T0_flag)" << endl
<< " end" << endl
<< " fill!(g3, 0.0)" << endl
<< d_output[3].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// static!
output << "function static!(T::Vector{Float64}, residual::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticResid!(T, residual, y, x, params, true)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG1!(T, g1, y, x, params, true, true)" << endl
<< " staticResid!(T, residual, y, x, params, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG1!(T, g1, y, x, params, true, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG2!(T, g2, y, x, params, true, true, true)" << endl
<< " staticG1!(T, g1, y, x, params, false, false)" << endl
<< " staticResid!(T, residual, y, x, params, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl;
// Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivJulia(output);
output << "end" << endl;
writeToFileIfModified(output, basename + "Static.jl");
}
}
void
StaticModel::writeStaticCFile(const string &basename) const
{
// Writing comments and function definition command
string filename = basename + "/model/src/static.c";
string filename{basename + "/model/src/static.c"};
int ntt = temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size();
int ntt{static_cast<int>(temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size())};
ofstream output{filename, ios::out | ios::binary};
if (!output.is_open())
@ -1581,7 +1196,31 @@ StaticModel::writeStaticCFile(const string &basename) const
output << endl;
writeStaticModel(output, true, false);
auto [d_output, tt_output] = writeModelFileHelper<ExprNodeOutputType::CStaticModel>();
for (size_t i = 0; i < d_output.size(); i++)
{
string funcname{i == 0 ? "resid" : "g" + to_string(i)};
output << "void static_" << funcname << "_tt(const double *restrict y, const double *restrict x, const double *restrict params, double *restrict T)" << endl
<< "{" << endl
<< tt_output[i].str()
<< "}" << endl
<< endl
<< "void static_" << funcname << "(const double *restrict y, const double *restrict x, const double *restrict params, const double *restrict T, ";
if (i == 0)
output << "double *restrict residual";
else if (i == 1)
output << "double *restrict g1";
else
output << "double *restrict " << funcname << "_i, double *restrict " << funcname << "_j, double *restrict " << funcname << "_v";
output << ")" << endl
<< "{" << endl;
if (i == 0)
output << " double lhs, rhs;" << endl;
output << d_output[i].str()
<< "}" << endl
<< endl;
}
output << "void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])" << endl
<< "{" << endl
@ -1639,7 +1278,213 @@ StaticModel::writeStaticCFile(const string &basename) const
void
StaticModel::writeStaticJuliaFile(const string &basename) const
{
writeStaticModel(basename, false, true);
auto [d_output, tt_output] = writeModelFileHelper<ExprNodeOutputType::juliaStaticModel>();
stringstream output;
output << "module " << basename << "Static" << endl
<< "#" << endl
<< "# NB: this file was automatically generated by Dynare" << endl
<< "# from " << basename << ".mod" << endl
<< "#" << endl
<< "using StatsFuns" << endl << endl
<< "export tmp_nbr, static!, staticResid!, staticG1!, staticG2!, staticG3!" << endl << endl
<< "#=" << endl
<< "# The comments below apply to all functions contained in this module #" << endl
<< " NB: The arguments contained on the first line of the function" << endl
<< " definition are those that are modified in place" << endl << endl
<< "## Exported Functions ##" << endl
<< " static! : Wrapper function; computes residuals, Jacobian, Hessian," << endl
<< " and third order derivatives matroces depending on the arguments provided" << endl
<< " staticResid! : Computes the static model residuals" << endl
<< " staticG1! : Computes the static model Jacobian" << endl
<< " staticG2! : Computes the static model Hessian" << endl
<< " staticG3! : Computes the static model third derivatives" << endl << endl
<< "## Exported Variables ##" << endl
<< " tmp_nbr : Vector{Int}(4) respectively the number of temporary variables" << endl
<< " for the residuals, g1, g2 and g3." << endl << endl
<< "## Local Functions ##" << endl
<< " staticResidTT! : Computes the static model temporary terms for the residuals" << endl
<< " staticG1TT! : Computes the static model temporary terms for the Jacobian" << endl
<< " staticG2TT! : Computes the static model temporary terms for the Hessian" << endl
<< " staticG3TT! : Computes the static model temporary terms for the third derivatives" << endl << endl
<< "## Function Arguments ##" << endl
<< " T : Vector{Float64}(num_temp_terms) temporary terms" << endl
<< " y : Vector{Float64}(model_.endo_nbr) endogenous variables in declaration order" << endl
<< " x : Vector{Float64}(model_.exo_nbr) exogenous variables in declaration order" << endl
<< " params : Vector{Float64}(model_.param) parameter values in declaration order" << endl
<< " residual : Vector{Float64}(model_.eq_nbr) residuals of the static model equations" << endl
<< " in order of declaration of the equations. Dynare may prepend auxiliary equations," << endl
<< " see model.aux_vars" << endl
<< " g1 : Matrix{Float64}(model.eq_nbr,model_.endo_nbr) Jacobian matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl
<< " g2 : spzeros(model.eq_nbr, model_.endo^2) Hessian matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl
<< " g3 : spzeros(model.eq_nbr, model_.endo^3) Third order derivatives matrix of the static model equations" << endl
<< " The columns and rows respectively correspond to the variables in declaration order and the" << endl
<< " equations in order of declaration" << endl << endl
<< "## Remarks ##" << endl
<< " [1] The size of `T`, ie the value of `num_temp_terms`, depends on the version of the static model called. The number of temporary variables" << endl
<< " used for the different returned objects (residuals, jacobian, hessian or third order derivatives) is given by the elements in `tmp_nbr`" << endl
<< " exported vector. The first element is the number of temporaries used for the computation of the residuals, the second element is the" << endl
<< " number of temporaries used for the evaluation of the jacobian matrix, etc. If one calls the version of the static model computing the" << endl
<< " residuals, and the jacobian and hessian matrices, then `T` must have at least `sum(tmp_nbr[1:3])` elements." << endl
<< "=#" << endl << endl;
// Write the number of temporary terms
output << "tmp_nbr = zeros(Int,4)" << endl
<< "tmp_nbr[1] = " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << "# Number of temporary terms for the residuals" << endl
<< "tmp_nbr[2] = " << temporary_terms_derivatives[1].size() << "# Number of temporary terms for g1 (jacobian)" << endl
<< "tmp_nbr[3] = " << temporary_terms_derivatives[2].size() << "# Number of temporary terms for g2 (hessian)" << endl
<< "tmp_nbr[4] = " << temporary_terms_derivatives[3].size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl;
// staticResidTT!
output << "function staticResidTT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << endl
<< tt_output[0].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// static!
output << "function staticResid!(T::Vector{Float64}, residual::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T0_flag::Bool)" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " @assert length(residual) == " << equations.size() << endl
<< " if T0_flag" << endl
<< " staticResidTT!(T, y, x, params)" << endl
<< " end" << endl
<< d_output[0].str()
<< " if ~isreal(residual)" << endl
<< " residual = real(residual)+imag(residual).^2;" << endl
<< " end" << endl
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG1TT!
output << "function staticG1TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T0_flag::Bool)" << endl
<< " if T0_flag" << endl
<< " staticResidTT!(T, y, x, params)" << endl
<< " end" << endl
<< tt_output[1].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG1!
output << "function staticG1!(T::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() << endl
<< " @assert size(g1) == (" << equations.size() << ", " << symbol_table.endo_nbr() << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T1_flag" << endl
<< " staticG1TT!(T, y, x, params, T0_flag)" << endl
<< " end" << endl
<< " fill!(g1, 0.0)" << endl
<< d_output[1].str()
<< " if ~isreal(g1)" << endl
<< " g1 = real(g1)+2*imag(g1);" << endl
<< " end" << endl
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG2TT!
output << "function staticG2TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T1_flag::Bool, T0_flag::Bool)" << endl
<< " if T1_flag" << endl
<< " staticG1TT!(T, y, x, params, TO_flag)" << endl
<< " end" << endl
<< tt_output[2].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG2!
int hessianColsNbr{symbol_table.endo_nbr() * symbol_table.endo_nbr()};
output << "function staticG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() << endl
<< " @assert size(g2) == (" << equations.size() << ", " << hessianColsNbr << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T2_flag" << endl
<< " staticG2TT!(T, y, x, params, T1_flag, T0_flag)" << endl
<< " end" << endl
<< " fill!(g2, 0.0)" << endl
<< d_output[2].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG3TT!
output << "function staticG3TT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " if T2_flag" << endl
<< " staticG2TT!(T, y, x, params, T1_flag, T0_flag)" << endl
<< " end" << endl
<< tt_output[3].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// staticG3!
int ncols{hessianColsNbr * symbol_table.endo_nbr()};
output << "function staticG3!(T::Vector{Float64}, g3::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T3_flag::Bool, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size() << endl
<< " @assert size(g3) == (" << equations.size() << ", " << ncols << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl
<< " if T3_flag" << endl
<< " staticG3TT!(T, y, x, params, T2_flag, T1_flag, T0_flag)" << endl
<< " end" << endl
<< " fill!(g3, 0.0)" << endl
<< d_output[3].str()
<< " return nothing" << endl
<< "end" << endl << endl;
// static!
output << "function static!(T::Vector{Float64}, residual::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticResid!(T, residual, y, x, params, true)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG1!(T, g1, y, x, params, true, true)" << endl
<< " staticResid!(T, residual, y, x, params, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, g1::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG1!(T, g1, y, x, params, true, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl
<< "function static!(T::Vector{Float64}, residual::Vector{Float64}, g1::Matrix{Float64}, g2::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " staticG2!(T, g2, y, x, params, true, true, true)" << endl
<< " staticG1!(T, g1, y, x, params, false, false)" << endl
<< " staticResid!(T, residual, y, x, params, false)" << endl
<< " return nothing" << endl
<< "end" << endl
<< endl;
// Write function definition if BinaryOpcode::powerDeriv is used
writePowerDerivJulia(output);
output << "end" << endl;
writeToFileIfModified(output, basename + "Static.jl");
}
void

View File

@ -43,9 +43,6 @@ private:
//! Writes static model file (Julia version)
void writeStaticJuliaFile(const string &basename) const;
//! Writes the static model equations and its derivatives
void writeStaticModel(const string &basename, ostream &StaticOutput, bool use_dll, bool julia) const;
//! Writes the main static function of block decomposed model (MATLAB version)
void writeStaticBlockMFile(const string &basename) const;
@ -89,8 +86,18 @@ private:
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;
//! Compute the column indices of the static Jacobian
void computeStatJacobianCols();
int
getJacobianCol(int deriv_id) const override
{
return symbol_table.getTypeSpecificID(getSymbIDByDerivID(deriv_id));
}
int
getJacobianColsNbr() const override
{
return symbol_table.endo_nbr();
}
//! Computes chain rule derivatives of the Jacobian w.r. to endogenous variables
void computeChainRuleJacobian();
@ -106,9 +113,6 @@ private:
//! Create a legacy *_static.m file for Matlab/Octave not yet using the temporary terms array interface
void writeStaticMatlabCompatLayer(const string &name) const;
void writeStaticModel(ostream &DynamicOutput, bool use_dll, bool julia) const;
void writeStaticModel(const string &dynamic_basename, bool use_dll, bool julia) const;
public:
StaticModel(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants,