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
parent
c8b046ec86
commit
f38c8278ae
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
145
src/ModelTree.hh
145
src/ModelTree.hh
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue