Make storage of derivatives ready for k-order

This is the first step towards computing k-order derivatives.

Ref Dynare/dynare#217, #10
issue#70
Sébastien Villemot 2018-11-15 16:39:53 +01:00
parent 3eff2b91c2
commit e89dd9cb8b
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
4 changed files with 432 additions and 507 deletions

View File

@ -245,8 +245,8 @@ DynamicModel::operator=(const DynamicModel &m)
void void
DynamicModel::compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const DynamicModel::compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, int lag, const map_idx_t &map_idx) const
{ {
auto it = first_derivatives.find({ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, symb_id), lag) }); auto it = derivatives[1].find({ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, symb_id), lag) });
if (it != first_derivatives.end()) if (it != derivatives[1].end())
(it->second)->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false); (it->second)->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
else else
{ {
@ -274,7 +274,6 @@ DynamicModel::computeTemporaryTermsOrdered()
map<expr_t, pair<int, int>> first_occurence; map<expr_t, pair<int, int>> first_occurence;
map<expr_t, int> reference_count; map<expr_t, int> reference_count;
BinaryOpNode *eq_node; BinaryOpNode *eq_node;
first_derivatives_t::const_iterator it;
first_chain_rule_derivatives_t::const_iterator it_chr; first_chain_rule_derivatives_t::const_iterator it_chr;
ostringstream tmp_s; ostringstream tmp_s;
v_temporary_terms.clear(); v_temporary_terms.clear();
@ -1016,10 +1015,10 @@ DynamicModel::writeModelEquationsCode(const string &basename, const map_idx_t &m
map<pair< int, pair<int, int>>, expr_t> first_derivatives_reordered_endo; map<pair< int, pair<int, int>>, expr_t> first_derivatives_reordered_endo;
map<pair< pair<int, SymbolType>, pair<int, int>>, expr_t> first_derivatives_reordered_exo; map<pair< pair<int, SymbolType>, pair<int, int>>, expr_t> first_derivatives_reordered_exo;
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
unsigned int eq = first_derivative.first.first; unsigned int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
unsigned int var = symbol_table.getTypeSpecificID(symb); unsigned int var = symbol_table.getTypeSpecificID(symb);
int lag = getLagByDerivID(deriv_id); int lag = getLagByDerivID(deriv_id);
@ -1103,24 +1102,24 @@ DynamicModel::writeModelEquationsCode(const string &basename, const map_idx_t &m
fjmp_if_eval.write(code_file, instruction_number); fjmp_if_eval.write(code_file, instruction_number);
int prev_instruction_number = instruction_number; int prev_instruction_number = instruction_number;
vector<vector<pair<pair<int, int>, int >>> derivatives; vector<vector<pair<pair<int, int>, int >>> my_derivatives;
derivatives.resize(symbol_table.endo_nbr()); my_derivatives.resize(symbol_table.endo_nbr());
count_u = symbol_table.endo_nbr(); count_u = symbol_table.endo_nbr();
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
expr_t d1 = first_derivative.second; expr_t d1 = first_derivative.second;
unsigned int eq = first_derivative.first.first; unsigned int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
unsigned int var = symbol_table.getTypeSpecificID(symb); unsigned int var = symbol_table.getTypeSpecificID(symb);
int lag = getLagByDerivID(deriv_id); int lag = getLagByDerivID(deriv_id);
FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var, lag); FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var, lag);
fnumexpr.write(code_file, instruction_number); fnumexpr.write(code_file, instruction_number);
if (!derivatives[eq].size()) if (!my_derivatives[eq].size())
derivatives[eq].clear(); my_derivatives[eq].clear();
derivatives[eq].emplace_back(make_pair(var, lag), count_u); my_derivatives[eq].emplace_back(make_pair(var, lag), count_u);
d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false); d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, true, false);
FSTPU_ fstpu(count_u); FSTPU_ fstpu(count_u);
@ -1132,10 +1131,10 @@ DynamicModel::writeModelEquationsCode(const string &basename, const map_idx_t &m
{ {
FLDR_ fldr(i); FLDR_ fldr(i);
fldr.write(code_file, instruction_number); fldr.write(code_file, instruction_number);
if (derivatives[i].size()) if (my_derivatives[i].size())
{ {
for (vector<pair<pair<int, int>, int>>::const_iterator it = derivatives[i].begin(); for (vector<pair<pair<int, int>, int>>::const_iterator it = my_derivatives[i].begin();
it != derivatives[i].end(); it++) it != my_derivatives[i].end(); it++)
{ {
FLDU_ fldu(it->second); FLDU_ fldu(it->second);
fldu.write(code_file, instruction_number); fldu.write(code_file, instruction_number);
@ -1143,7 +1142,7 @@ DynamicModel::writeModelEquationsCode(const string &basename, const map_idx_t &m
fldv.write(code_file, instruction_number); fldv.write(code_file, instruction_number);
FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)}; FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)};
fbinary.write(code_file, instruction_number); fbinary.write(code_file, instruction_number);
if (it != derivatives[i].begin()) if (it != my_derivatives[i].begin())
{ {
FBINARY_ fbinary{static_cast<int>(BinaryOpcode::plus)}; FBINARY_ fbinary{static_cast<int>(BinaryOpcode::plus)};
fbinary.write(code_file, instruction_number); fbinary.write(code_file, instruction_number);
@ -1722,7 +1721,7 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
string filename_mex = basename + "/model/src/dynamic_mex.c"; string filename_mex = basename + "/model/src/dynamic_mex.c";
ofstream mDynamicModelFile, mDynamicMexFile; ofstream mDynamicModelFile, mDynamicMexFile;
int ntt = temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size(); 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();
mDynamicModelFile.open(filename, ios::out | ios::binary); mDynamicModelFile.open(filename, ios::out | ios::binary);
if (!mDynamicModelFile.is_open()) if (!mDynamicModelFile.is_open())
@ -1835,7 +1834,7 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
<< " if (nlhs >= 3)" << endl << " if (nlhs >= 3)" << endl
<< " {" << endl << " {" << endl
<< " /* Set the output pointer to the output matrix v2. */" << endl << " /* Set the output pointer to the output matrix v2. */" << endl
<< " plhs[2] = mxCreateDoubleMatrix(" << NNZDerivatives[1] << ", " << 3 << " plhs[2] = mxCreateDoubleMatrix(" << NNZDerivatives[2] << ", " << 3
<< ", mxREAL);" << endl << ", mxREAL);" << endl
<< " double *v2 = mxGetPr(plhs[2]);" << endl << " double *v2 = mxGetPr(plhs[2]);" << endl
<< " dynamic_g2_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl << " dynamic_g2_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
@ -1845,7 +1844,7 @@ DynamicModel::writeDynamicCFile(const string &basename, const int order) const
<< " if (nlhs >= 4)" << endl << " if (nlhs >= 4)" << endl
<< " {" << endl << " {" << endl
<< " /* Set the output pointer to the output matrix v3. */" << endl << " /* Set the output pointer to the output matrix v3. */" << endl
<< " plhs[3] = mxCreateDoubleMatrix(" << NNZDerivatives[2] << ", " << 3 << ", mxREAL);" << endl << " plhs[3] = mxCreateDoubleMatrix(" << NNZDerivatives[3] << ", " << 3 << ", mxREAL);" << endl
<< " double *v3 = mxGetPr(plhs[3]);" << endl << " double *v3 = mxGetPr(plhs[3]);" << endl
<< " dynamic_g3_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl << " dynamic_g3_tt(y, x, nb_row_x, params, steady_state, it_, T);" << endl
<< " dynamic_g3(y, x, nb_row_x, params, steady_state, it_, T, v3);" << endl << " dynamic_g3(y, x, nb_row_x, params, steady_state, it_, T, v3);" << endl
@ -1893,9 +1892,9 @@ DynamicModel::printNonZeroHessianEquations(ostream &output) const
void void
DynamicModel::setNonZeroHessianEquations(map<int, string> &eqs) DynamicModel::setNonZeroHessianEquations(map<int, string> &eqs)
{ {
for (const auto &it : second_derivatives) for (const auto &it : derivatives[2])
{ {
int eq = get<0>(it.first); int eq = it.first[0];
if (nonzero_hessian_eqs.find(eq) == nonzero_hessian_eqs.end()) if (nonzero_hessian_eqs.find(eq) == nonzero_hessian_eqs.end())
{ {
nonzero_hessian_eqs[eq] = ""; nonzero_hessian_eqs[eq] = "";
@ -2460,7 +2459,7 @@ DynamicModel::writeDynamicMatlabCompatLayer(const string &basename) const
cerr << "Error: Can't open file " << filename << " for writing" << endl; cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
int ntt = temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size(); 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();
output << "function [residual, g1, g2, g3] = dynamic(y, x, params, steady_state, it_)" << endl output << "function [residual, g1, g2, g3] = dynamic(y, x, params, steady_state, it_)" << endl
<< " T = NaN(" << ntt << ", 1);" << endl << " T = NaN(" << ntt << ", 1);" << endl
@ -2514,11 +2513,11 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_mlv, writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_mlv,
model_tt_output, output_type, tef_terms); model_tt_output, output_type, tef_terms);
writeTemporaryTerms(temporary_terms_res, writeTemporaryTerms(temporary_terms_derivatives[0],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
model_tt_output, output_type, tef_terms); model_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_res.begin(), temporary_terms_res.end()); temp_term_union.insert(temporary_terms_derivatives[0].begin(), temporary_terms_derivatives[0].end());
writeModelEquations(model_output, output_type, temp_term_union); writeModelEquations(model_output, output_type, temp_term_union);
@ -2526,18 +2525,18 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr; int hessianColsNbr = dynJacobianColsNbr * dynJacobianColsNbr;
// Writing Jacobian // Writing Jacobian
if (!first_derivatives.empty()) if (!derivatives[1].empty())
{ {
writeTemporaryTerms(temporary_terms_g1, writeTemporaryTerms(temporary_terms_derivatives[1],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
jacobian_tt_output, output_type, tef_terms); jacobian_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); temp_term_union.insert(temporary_terms_derivatives[1].begin(), temporary_terms_derivatives[1].end());
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int eq, var; int eq, var;
tie(eq, var) = first_derivative.first; tie(eq, var) = vectorToTuple<2>(first_derivative.first);
expr_t d1 = first_derivative.second; expr_t d1 = first_derivative.second;
jacobianHelper(jacobian_output, eq, getDynJacobianCol(var), output_type); jacobianHelper(jacobian_output, eq, getDynJacobianCol(var), output_type);
@ -2549,19 +2548,19 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
} }
// Writing Hessian // Writing Hessian
if (!second_derivatives.empty()) if (!derivatives[2].empty())
{ {
writeTemporaryTerms(temporary_terms_g2, writeTemporaryTerms(temporary_terms_derivatives[2],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
hessian_tt_output, output_type, tef_terms); hessian_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); temp_term_union.insert(temporary_terms_derivatives[2].begin(), temporary_terms_derivatives[2].end());
int k = 0; // Keep the line of a 2nd derivative in v2 int k = 0; // Keep the line of a 2nd derivative in v2
for (const auto & second_derivative : second_derivatives) for (const auto & second_derivative : derivatives[2])
{ {
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = second_derivative.first; tie(eq, var1, var2) = vectorToTuple<3>(second_derivative.first);
expr_t d2 = second_derivative.second; expr_t d2 = second_derivative.second;
int id1 = getDynJacobianCol(var1); int id1 = getDynJacobianCol(var1);
@ -2618,19 +2617,19 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
} }
// Writing third derivatives // Writing third derivatives
if (!third_derivatives.empty()) if (!derivatives[3].empty())
{ {
writeTemporaryTerms(temporary_terms_g3, writeTemporaryTerms(temporary_terms_derivatives[3],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
third_derivatives_tt_output, output_type, tef_terms); third_derivatives_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); temp_term_union.insert(temporary_terms_derivatives[3].begin(), temporary_terms_derivatives[3].end());
int k = 0; // Keep the line of a 3rd derivative in v3 int k = 0; // Keep the line of a 3rd derivative in v3
for (const auto & third_derivative : third_derivatives) for (const auto & third_derivative : derivatives[3])
{ {
int eq, var1, var2, var3; int eq, var1, var2, var3;
tie(eq, var1, var2, var3) = third_derivative.first; tie(eq, var1, var2, var3) = vectorToTuple<4>(third_derivative.first);
expr_t d3 = third_derivative.second; expr_t d3 = third_derivative.second;
int id1 = getDynJacobianCol(var1); int id1 = getDynJacobianCol(var1);
@ -2714,7 +2713,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
init_output << "residual = zeros(" << nrows << ", 1);"; init_output << "residual = zeros(" << nrows << ", 1);";
writeDynamicModelHelper(basename, "dynamic_resid", "residual", writeDynamicModelHelper(basename, "dynamic_resid", "residual",
"dynamic_resid_tt", "dynamic_resid_tt",
temporary_terms_mlv.size() + temporary_terms_res.size(), temporary_terms_mlv.size() + temporary_terms_derivatives[0].size(),
"", init_output, end_output, "", init_output, end_output,
model_output, model_tt_output); model_output, model_tt_output);
@ -2723,7 +2722,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
init_output << "g1 = zeros(" << nrows << ", " << dynJacobianColsNbr << ");"; init_output << "g1 = zeros(" << nrows << ", " << dynJacobianColsNbr << ");";
writeDynamicModelHelper(basename, "dynamic_g1", "g1", writeDynamicModelHelper(basename, "dynamic_g1", "g1",
"dynamic_g1_tt", "dynamic_g1_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size(), temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
"dynamic_resid_tt", "dynamic_resid_tt",
init_output, end_output, init_output, end_output,
jacobian_output, jacobian_tt_output); jacobian_output, jacobian_tt_output);
@ -2731,17 +2730,17 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
init_output.str(string()); init_output.str(string());
init_output.clear(); init_output.clear();
if (second_derivatives.size()) if (derivatives[2].size())
{ {
init_output << "v2 = zeros(" << NNZDerivatives[1] << ",3);"; init_output << "v2 = zeros(" << NNZDerivatives[2] << ",3);";
end_output << "g2 = sparse(v2(:,1),v2(:,2),v2(:,3)," << nrows << "," << hessianColsNbr << ");"; end_output << "g2 = sparse(v2(:,1),v2(:,2),v2(:,3)," << nrows << "," << hessianColsNbr << ");";
} }
else else
init_output << "g2 = sparse([],[],[]," << nrows << "," << hessianColsNbr << ");"; init_output << "g2 = sparse([],[],[]," << nrows << "," << hessianColsNbr << ");";
writeDynamicModelHelper(basename, "dynamic_g2", "g2", writeDynamicModelHelper(basename, "dynamic_g2", "g2",
"dynamic_g2_tt", "dynamic_g2_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size()
+ temporary_terms_g2.size(), + temporary_terms_derivatives[2].size(),
"dynamic_g1_tt", "dynamic_g1_tt",
init_output, end_output, init_output, end_output,
hessian_output, hessian_tt_output); hessian_output, hessian_tt_output);
@ -2752,17 +2751,17 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
end_output.str(string()); end_output.str(string());
end_output.clear(); end_output.clear();
int ncols = hessianColsNbr * dynJacobianColsNbr; int ncols = hessianColsNbr * dynJacobianColsNbr;
if (third_derivatives.size()) if (derivatives[3].size())
{ {
init_output << "v3 = zeros(" << NNZDerivatives[2] << ",3);"; init_output << "v3 = zeros(" << NNZDerivatives[3] << ",3);";
end_output << "g3 = sparse(v3(:,1),v3(:,2),v3(:,3)," << nrows << "," << ncols << ");"; end_output << "g3 = sparse(v3(:,1),v3(:,2),v3(:,3)," << nrows << "," << ncols << ");";
} }
else else
init_output << "g3 = sparse([],[],[]," << nrows << "," << ncols << ");"; init_output << "g3 = sparse([],[],[]," << nrows << "," << ncols << ");";
writeDynamicModelHelper(basename, "dynamic_g3", "g3", writeDynamicModelHelper(basename, "dynamic_g3", "g3",
"dynamic_g3_tt", "dynamic_g3_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size()
+ temporary_terms_g2.size() + temporary_terms_g3.size(), + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size(),
"dynamic_g2_tt", "dynamic_g2_tt",
init_output, end_output, init_output, end_output,
third_derivatives_output, third_derivatives_tt_output); third_derivatives_output, third_derivatives_tt_output);
@ -2878,10 +2877,10 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
// Write the number of temporary terms // Write the number of temporary terms
output << "tmp_nbr = zeros(Int,4)" << endl output << "tmp_nbr = zeros(Int,4)" << endl
<< "tmp_nbr[1] = " << temporary_terms_mlv.size() + temporary_terms_res.size() << "# Number of temporary terms for the residuals" << 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_g1.size() << "# Number of temporary terms for g1 (jacobian)" << endl << "tmp_nbr[2] = " << temporary_terms_derivatives[1].size() << "# Number of temporary terms for g1 (jacobian)" << endl
<< "tmp_nbr[3] = " << temporary_terms_g2.size() << "# Number of temporary terms for g2 (hessian)" << endl << "tmp_nbr[3] = " << temporary_terms_derivatives[2].size() << "# Number of temporary terms for g2 (hessian)" << endl
<< "tmp_nbr[4] = " << temporary_terms_g3.size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl; << "tmp_nbr[4] = " << temporary_terms_derivatives[3].size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl;
// dynamicResidTT! // dynamicResidTT!
output << "function dynamicResidTT!(T::Vector{Float64}," << endl output << "function dynamicResidTT!(T::Vector{Float64}," << endl
@ -2895,7 +2894,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
output << "function dynamicResid!(T::Vector{Float64}, residual::Vector{Float64}," << endl output << "function dynamicResid!(T::Vector{Float64}, residual::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Matrix{Float64}, " << " y::Vector{Float64}, x::Matrix{Float64}, "
<< "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
<< " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_res.size() << endl << " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << endl
<< " @assert length(residual) == " << nrows << endl << " @assert length(residual) == " << nrows << endl
<< " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl << " @assert length(params) == " << symbol_table.param_nbr() << endl
@ -2920,7 +2919,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
<< " y::Vector{Float64}, x::Matrix{Float64}, " << " y::Vector{Float64}, x::Matrix{Float64}, "
<< "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
<< " @assert length(T) >= " << " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() << endl << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size() << endl
<< " @assert size(g1) == (" << nrows << ", " << dynJacobianColsNbr << ")" << endl << " @assert size(g1) == (" << nrows << ", " << dynJacobianColsNbr << ")" << endl
<< " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl << " @assert length(params) == " << symbol_table.param_nbr() << endl
@ -2945,7 +2944,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
output << "function dynamicG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl output << "function dynamicG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl
<< " y::Vector{Float64}, x::Matrix{Float64}, " << " y::Vector{Float64}, x::Matrix{Float64}, "
<< "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
<< " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() << 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) == (" << nrows << ", " << hessianColsNbr << ")" << endl << " @assert size(g2) == (" << nrows << ", " << hessianColsNbr << ")" << endl
<< " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl << " @assert length(params) == " << symbol_table.param_nbr() << endl
@ -2972,7 +2971,7 @@ DynamicModel::writeDynamicModel(const string &basename, ostream &DynamicOutput,
<< " y::Vector{Float64}, x::Matrix{Float64}, " << " y::Vector{Float64}, x::Matrix{Float64}, "
<< "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl << "params::Vector{Float64}, steady_state::Vector{Float64}, it_::Int, T_flag::Bool)" << endl
<< " @assert length(T) >= " << " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size() << endl << 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 size(g3) == (" << nrows << ", " << ncols << ")" << endl
<< " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl << " @assert length(y)+size(x, 2) == " << dynJacobianColsNbr << endl
<< " @assert length(params) == " << symbol_table.param_nbr() << endl << " @assert length(params) == " << symbol_table.param_nbr() << endl
@ -3117,10 +3116,10 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de
<< modstruct << "ndynamic = " << npred+nboth+nfwrd << ";" << endl; << modstruct << "ndynamic = " << npred+nboth+nfwrd << ";" << endl;
if (!julia) if (!julia)
output << modstruct << "dynamic_tmp_nbr = zeros(4,1); % Number of temporaries used for the dynamic model" << endl output << modstruct << "dynamic_tmp_nbr = zeros(4,1); % Number of temporaries used for the dynamic model" << endl
<< modstruct << "dynamic_tmp_nbr(1) = " << temporary_terms_res.size() << "; % Number of temporaries used for the evaluation of the residuals" << endl << modstruct << "dynamic_tmp_nbr(1) = " << temporary_terms_derivatives[0].size() << "; % Number of temporaries used for the evaluation of the residuals" << endl
<< modstruct << "dynamic_tmp_nbr(2) = " << temporary_terms_g1.size() << "; % Number of temporaries used for the evaluation of g1 (jacobian)" << endl << modstruct << "dynamic_tmp_nbr(2) = " << temporary_terms_derivatives[1].size() << "; % Number of temporaries used for the evaluation of g1 (jacobian)" << endl
<< modstruct << "dynamic_tmp_nbr(3) = " << temporary_terms_g2.size() << "; % Number of temporaries used for the evaluation of g2 (hessian)" << endl << modstruct << "dynamic_tmp_nbr(3) = " << temporary_terms_derivatives[2].size() << "; % Number of temporaries used for the evaluation of g2 (hessian)" << endl
<< modstruct << "dynamic_tmp_nbr(4) = " << temporary_terms_g3.size() << "; % Number of temporaries used for the evaluation of g3 (third order derivatives)" << endl; << modstruct << "dynamic_tmp_nbr(4) = " << temporary_terms_derivatives[3].size() << "; % Number of temporaries used for the evaluation of g3 (third order derivatives)" << endl;
// Write equation tags // Write equation tags
if (julia) if (julia)
@ -3413,12 +3412,12 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de
state_equ.push_back(equation_reordered[variable_inv_reordered[*it - 1]]+1); state_equ.push_back(equation_reordered[variable_inv_reordered[*it - 1]]+1);
map<pair< int, pair<int, int>>, int> lag_row_incidence; map<pair< int, pair<int, int>>, int> lag_row_incidence;
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
int var = symbol_table.getTypeSpecificID(symb); int var = symbol_table.getTypeSpecificID(symb);
int lag = getLagByDerivID(deriv_id); int lag = getLagByDerivID(deriv_id);
@ -3625,14 +3624,14 @@ DynamicModel::writeOutput(ostream &output, const string &basename, bool block_de
// Write number of non-zero derivatives // Write number of non-zero derivatives
// Use -1 if the derivatives have not been computed // Use -1 if the derivatives have not been computed
output << modstruct << (julia ? "nnzderivatives" : "NNZDerivatives") output << modstruct << (julia ? "nnzderivatives" : "NNZDerivatives")
<< " = [" << NNZDerivatives[0] << "; "; << " = [" << NNZDerivatives[1] << "; ";
if (order > 1) if (order > 1)
output << NNZDerivatives[1] << "; "; output << NNZDerivatives[2] << "; ";
else else
output << "-1; "; output << "-1; ";
if (order > 2) if (order > 2)
output << NNZDerivatives[2]; output << NNZDerivatives[3];
else else
output << "-1"; output << "-1";
output << "];" << endl; output << "];" << endl;
@ -3646,13 +3645,13 @@ map<pair<int, pair<int, int >>, expr_t>
DynamicModel::collect_first_order_derivatives_endogenous() DynamicModel::collect_first_order_derivatives_endogenous()
{ {
map<pair<int, pair<int, int >>, expr_t> endo_derivatives; map<pair<int, pair<int, int >>, expr_t> endo_derivatives;
for (auto & first_derivative : first_derivatives) for (auto & first_derivative : derivatives[1])
{ {
if (getTypeByDerivID(first_derivative.first.second) == SymbolType::endogenous) if (getTypeByDerivID(first_derivative.first[1]) == SymbolType::endogenous)
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first.second)); int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first[1]));
int lag = getLagByDerivID(first_derivative.first.second); int lag = getLagByDerivID(first_derivative.first[1]);
endo_derivatives[{ eq, { var, lag } }] = first_derivative.second; endo_derivatives[{ eq, { var, lag } }] = first_derivative.second;
} }
} }
@ -4718,7 +4717,7 @@ DynamicModel::computeChainRuleJacobian(blocks_derivatives_t &blocks_endo_derivat
int eqr = it_l.second.first; int eqr = it_l.second.first;
int varr = it_l.second.second; int varr = it_l.second.second;
if (Deriv_type == 0) if (Deriv_type == 0)
first_chain_rule_derivatives[{ eqr, { varr, lag } }] = first_derivatives[{ eqr, getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag) }]; first_chain_rule_derivatives[{ eqr, { varr, lag } }] = derivatives[1][{ eqr, getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag) }];
else if (Deriv_type == 1) else if (Deriv_type == 1)
first_chain_rule_derivatives[{ eqr, { varr, lag } }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables); first_chain_rule_derivatives[{ eqr, { varr, lag } }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables);
else if (Deriv_type == 2) else if (Deriv_type == 2)
@ -4763,16 +4762,16 @@ DynamicModel::collect_block_first_order_derivatives()
exo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 }); exo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
exo_det_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 }); exo_det_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 }); max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
for (auto & first_derivative : first_derivatives) for (auto & first_derivative : derivatives[1])
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first.second)); int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first[1]));
int lag = getLagByDerivID(first_derivative.first.second); int lag = getLagByDerivID(first_derivative.first[1]);
int block_eq = equation_2_block[eq]; int block_eq = equation_2_block[eq];
int block_var = 0; int block_var = 0;
derivative_t tmp_derivative; derivative_t tmp_derivative;
lag_var_t lag_var; lag_var_t lag_var;
switch (getTypeByDerivID(first_derivative.first.second)) switch (getTypeByDerivID(first_derivative.first[1]))
{ {
case SymbolType::endogenous: case SymbolType::endogenous:
block_var = variable_2_block[var]; block_var = variable_2_block[var];
@ -4783,7 +4782,7 @@ DynamicModel::collect_block_first_order_derivatives()
if (lag > 0 && lag > endo_max_leadlag_block[block_eq].second) if (lag > 0 && lag > endo_max_leadlag_block[block_eq].second)
endo_max_leadlag_block[block_eq] = { endo_max_leadlag_block[block_eq].first, lag }; endo_max_leadlag_block[block_eq] = { endo_max_leadlag_block[block_eq].first, lag };
tmp_derivative = derivative_endo[block_eq]; tmp_derivative = derivative_endo[block_eq];
tmp_derivative[{ lag, { eq, var } }] = first_derivatives[{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }]; tmp_derivative[{ lag, { eq, var } }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }];
derivative_endo[block_eq] = tmp_derivative; derivative_endo[block_eq] = tmp_derivative;
} }
else else
@ -4807,7 +4806,7 @@ DynamicModel::collect_block_first_order_derivatives()
} }
} }
} }
tmp_derivative[{ lag, { eq, var } }] = first_derivatives[{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }]; tmp_derivative[{ lag, { eq, var } }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }];
derivative_other_endo[block_eq] = tmp_derivative; derivative_other_endo[block_eq] = tmp_derivative;
lag_var = other_endo_block[block_eq]; lag_var = other_endo_block[block_eq];
if (lag_var.find(lag) == lag_var.end()) if (lag_var.find(lag) == lag_var.end())
@ -4836,7 +4835,7 @@ DynamicModel::collect_block_first_order_derivatives()
} }
} }
} }
tmp_derivative[{ lag, { eq, var } }] = first_derivatives[{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }]; tmp_derivative[{ lag, { eq, var } }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }];
derivative_exo[block_eq] = tmp_derivative; derivative_exo[block_eq] = tmp_derivative;
lag_var = exo_block[block_eq]; lag_var = exo_block[block_eq];
if (lag_var.find(lag) == lag_var.end()) if (lag_var.find(lag) == lag_var.end())
@ -4864,7 +4863,7 @@ DynamicModel::collect_block_first_order_derivatives()
} }
} }
} }
tmp_derivative[{ lag, { eq, var } }] = first_derivatives[{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }]; tmp_derivative[{ lag, { eq, var } }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::exogenous, var), lag) }];
derivative_exo_det[block_eq] = tmp_derivative; derivative_exo_det[block_eq] = tmp_derivative;
lag_var = exo_det_block[block_eq]; lag_var = exo_det_block[block_eq];
if (lag_var.find(lag) == lag_var.end()) if (lag_var.find(lag) == lag_var.end())
@ -5378,11 +5377,7 @@ DynamicModel::testTrendDerivativesEqualToZero(const eval_context_t &eval_context
void void
DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) const DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) const
{ {
if (!residuals_params_derivatives.size() if (!params_derivatives.size())
&& !residuals_params_second_derivatives.size()
&& !jacobian_params_derivatives.size()
&& !jacobian_params_second_derivatives.size()
&& !hessian_params_derivatives.size())
return; return;
ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaDynamicModel : ExprNodeOutputType::matlabDynamicModel); ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaDynamicModel : ExprNodeOutputType::matlabDynamicModel);
@ -5398,10 +5393,10 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
writeTemporaryTerms(params_derivs_temporary_terms, {}, params_derivs_temporary_terms_idxs, model_output, output_type, tef_terms); writeTemporaryTerms(params_derivs_temporary_terms, {}, params_derivs_temporary_terms_idxs, model_output, output_type, tef_terms);
for (const auto & residuals_params_derivative : residuals_params_derivatives) for (const auto & residuals_params_derivative : params_derivatives.find({ 0, 1 })->second)
{ {
int eq, param; int eq, param;
tie(eq, param) = residuals_params_derivative.first; tie(eq, param) = vectorToTuple<2>(residuals_params_derivative.first);
expr_t d1 = residuals_params_derivative.second; expr_t d1 = residuals_params_derivative.second;
int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1; int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
@ -5412,10 +5407,10 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
jacobian_output << ";" << endl; jacobian_output << ";" << endl;
} }
for (const auto & jacobian_params_derivative : jacobian_params_derivatives) for (const auto & jacobian_params_derivative : params_derivatives.find({ 1, 1 })->second)
{ {
int eq, var, param; int eq, var, param;
tie(eq, var, param) = jacobian_params_derivative.first; tie(eq, var, param) = vectorToTuple<3>(jacobian_params_derivative.first);
expr_t d2 = jacobian_params_derivative.second; expr_t d2 = jacobian_params_derivative.second;
int var_col = getDynJacobianCol(var) + 1; int var_col = getDynJacobianCol(var) + 1;
@ -5428,10 +5423,10 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
} }
int i = 1; int i = 1;
for (const auto &it : residuals_params_second_derivatives) for (const auto &it : params_derivatives.find({ 0, 2 })->second)
{ {
int eq, param1, param2; int eq, param1, param2;
tie(eq, param1, param2) = it.first; tie(eq, param1, param2) = vectorToTuple<3>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1; int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
@ -5452,10 +5447,10 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
} }
i = 1; i = 1;
for (const auto &it : jacobian_params_second_derivatives) for (const auto &it : params_derivatives.find({ 1, 2 })->second)
{ {
int eq, var, param1, param2; int eq, var, param1, param2;
tie(eq, var, param1, param2) = it.first; tie(eq, var, param1, param2) = vectorToTuple<4>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int var_col = getDynJacobianCol(var) + 1; int var_col = getDynJacobianCol(var) + 1;
@ -5479,10 +5474,10 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
} }
i = 1; i = 1;
for (const auto &it : hessian_params_derivatives) for (const auto &it : params_derivatives.find({ 2, 1 })->second)
{ {
int eq, var1, var2, param; int eq, var1, var2, param;
tie(eq, var1, var2, param) = it.first; tie(eq, var1, var2, param) = vectorToTuple<4>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int var1_col = getDynJacobianCol(var1) + 1; int var1_col = getDynJacobianCol(var1) + 1;
@ -5579,13 +5574,13 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
<< "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl << "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl
<< hessian_output.str() << hessian_output.str()
<< "if nargout >= 3" << endl << "if nargout >= 3" << endl
<< "rpp = zeros(" << residuals_params_second_derivatives.size() << ",4);" << endl << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
<< hessian1_output.str() << hessian1_output.str()
<< "gpp = zeros(" << jacobian_params_second_derivatives.size() << ",5);" << endl << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
<< third_derivs_output.str() << third_derivs_output.str()
<< "end" << endl << "end" << endl
<< "if nargout >= 5" << endl << "if nargout >= 5" << endl
<< "hp = zeros(" << hessian_params_derivatives.size() << ",5);" << endl << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
<< third_derivs1_output.str() << third_derivs1_output.str()
<< "end" << endl << "end" << endl
<< "end" << endl; << "end" << endl;
@ -5606,11 +5601,11 @@ DynamicModel::writeParamsDerivativesFile(const string &basename, bool julia) con
<< jacobian_output.str() << jacobian_output.str()
<< "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl << "gp = zeros(" << equations.size() << ", " << dynJacobianColsNbr << ", " << symbol_table.param_nbr() << ");" << endl
<< hessian_output.str() << hessian_output.str()
<< "rpp = zeros(" << residuals_params_second_derivatives.size() << ",4);" << endl << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
<< hessian1_output.str() << hessian1_output.str()
<< "gpp = zeros(" << jacobian_params_second_derivatives.size() << ",5);" << endl << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
<< third_derivs_output.str() << third_derivs_output.str()
<< "hp = zeros(" << hessian_params_derivatives.size() << ",5);" << endl << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
<< third_derivs1_output.str() << third_derivs1_output.str()
<< "(rp, gp, rpp, gpp, hp)" << endl << "(rp, gp, rpp, gpp, hp)" << endl
<< "end" << endl << "end" << endl
@ -6371,7 +6366,7 @@ DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) c
deriv_node_temp_terms_t tef_terms; deriv_node_temp_terms_t tef_terms;
temporary_terms_t temp_term_empty; temporary_terms_t temp_term_empty;
temporary_terms_t temp_term_union = temporary_terms_res; temporary_terms_t temp_term_union = temporary_terms_derivatives[0];
temporary_terms_t temp_term_union_m_1; temporary_terms_t temp_term_union_m_1;
string concat = ""; string concat = "";
@ -6379,27 +6374,27 @@ DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) c
writeJsonModelLocalVariables(model_local_vars_output, tef_terms); writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat); writeJsonTemporaryTerms(temporary_terms_derivatives[0], temp_term_union_m_1, model_output, tef_terms, concat);
model_output << ", "; model_output << ", ";
writeJsonModelEquations(model_output, true); writeJsonModelEquations(model_output, true);
// Writing Jacobian // Writing Jacobian
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); temp_term_union.insert(temporary_terms_derivatives[1].begin(), temporary_terms_derivatives[1].end());
concat = "jacobian"; concat = "jacobian";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
jacobian_output << ", \"jacobian\": {" jacobian_output << ", \"jacobian\": {"
<< " \"nrows\": " << equations.size() << " \"nrows\": " << equations.size()
<< ", \"ncols\": " << dynJacobianColsNbr << ", \"ncols\": " << dynJacobianColsNbr
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = first_derivatives.begin(); for (auto it = derivatives[1].begin();
it != first_derivatives.end(); it++) it != derivatives[1].end(); it++)
{ {
if (it != first_derivatives.begin()) if (it != derivatives[1].begin())
jacobian_output << ", "; jacobian_output << ", ";
int eq, var; int eq, var;
tie(eq, var) = it->first; tie(eq, var) = vectorToTuple<2>(it->first);
int col = getDynJacobianCol(var); int col = getDynJacobianCol(var);
expr_t d1 = it->second; expr_t d1 = it->second;
@ -6422,21 +6417,21 @@ DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) c
// Writing Hessian // Writing Hessian
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); temp_term_union.insert(temporary_terms_derivatives[2].begin(), temporary_terms_derivatives[2].end());
concat = "hessian"; concat = "hessian";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
hessian_output << ", \"hessian\": {" hessian_output << ", \"hessian\": {"
<< " \"nrows\": " << equations.size() << " \"nrows\": " << equations.size()
<< ", \"ncols\": " << hessianColsNbr << ", \"ncols\": " << hessianColsNbr
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = second_derivatives.begin(); for (auto it = derivatives[2].begin();
it != second_derivatives.end(); it++) it != derivatives[2].end(); it++)
{ {
if (it != second_derivatives.begin()) if (it != derivatives[2].begin())
hessian_output << ", "; hessian_output << ", ";
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = it->first; tie(eq, var1, var2) = vectorToTuple<3>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int id1 = getDynJacobianCol(var1); int id1 = getDynJacobianCol(var1);
int id2 = getDynJacobianCol(var2); int id2 = getDynJacobianCol(var2);
@ -6467,21 +6462,21 @@ DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) c
// Writing third derivatives // Writing third derivatives
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); temp_term_union.insert(temporary_terms_derivatives[3].begin(), temporary_terms_derivatives[3].end());
concat = "third_derivatives"; concat = "third_derivatives";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
third_derivatives_output << ", \"third_derivative\": {" third_derivatives_output << ", \"third_derivative\": {"
<< " \"nrows\": " << equations.size() << " \"nrows\": " << equations.size()
<< ", \"ncols\": " << hessianColsNbr * dynJacobianColsNbr << ", \"ncols\": " << hessianColsNbr * dynJacobianColsNbr
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = third_derivatives.begin(); for (auto it = derivatives[3].begin();
it != third_derivatives.end(); it++) it != derivatives[3].end(); it++)
{ {
if (it != third_derivatives.begin()) if (it != derivatives[3].begin())
third_derivatives_output << ", "; third_derivatives_output << ", ";
int eq, var1, var2, var3; int eq, var1, var2, var3;
tie(eq, var1, var2, var3) = it->first; tie(eq, var1, var2, var3) = vectorToTuple<4>(it->first);
expr_t d3 = it->second; expr_t d3 = it->second;
if (writeDetails) if (writeDetails)
@ -6538,11 +6533,7 @@ DynamicModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) c
void void
DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const
{ {
if (!residuals_params_derivatives.size() if (!params_derivatives.size())
&& !residuals_params_second_derivatives.size()
&& !jacobian_params_derivatives.size()
&& !jacobian_params_second_derivatives.size()
&& !hessian_params_derivatives.size())
return; return;
ostringstream model_local_vars_output; // Used for storing model local vars ostringstream model_local_vars_output; // Used for storing model local vars
@ -6563,14 +6554,14 @@ DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = residuals_params_derivatives.begin(); auto &rp = params_derivatives.find({ 0, 1 })->second;
it != residuals_params_derivatives.end(); it++) for (auto it = rp.begin(); it != rp.end(); it++)
{ {
if (it != residuals_params_derivatives.begin()) if (it != rp.begin())
jacobian_output << ", "; jacobian_output << ", ";
int eq, param; int eq, param;
tie(eq, param) = it->first; tie(eq, param) = vectorToTuple<2>(it->first);
expr_t d1 = it->second; expr_t d1 = it->second;
int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1; int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
@ -6590,19 +6581,20 @@ DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
jacobian_output << "\"}" << endl; jacobian_output << "\"}" << endl;
} }
jacobian_output << "]}"; jacobian_output << "]}";
hessian_output << "\"deriv_jacobian_wrt_params\": {" hessian_output << "\"deriv_jacobian_wrt_params\": {"
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nvarcols\": " << dynJacobianColsNbr << ", \"nvarcols\": " << dynJacobianColsNbr
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = jacobian_params_derivatives.begin(); auto &gp = params_derivatives.find({ 1, 1 })->second;
it != jacobian_params_derivatives.end(); it++) for (auto it = gp.begin(); it != gp.end(); it++)
{ {
if (it != jacobian_params_derivatives.begin()) if (it != gp.begin())
hessian_output << ", "; hessian_output << ", ";
int eq, var, param; int eq, var, param;
tie(eq, var, param) = it->first; tie(eq, var, param) = vectorToTuple<3>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var_col = getDynJacobianCol(var) + 1; int var_col = getDynJacobianCol(var) + 1;
@ -6632,14 +6624,14 @@ DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< ", \"nparam1cols\": " << symbol_table.param_nbr() << ", \"nparam1cols\": " << symbol_table.param_nbr()
<< ", \"nparam2cols\": " << symbol_table.param_nbr() << ", \"nparam2cols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = residuals_params_second_derivatives.begin(); auto &rpp = params_derivatives.find({ 0, 2 })->second;
it != residuals_params_second_derivatives.end(); ++it) for (auto it = rpp.begin(); it != rpp.end(); ++it)
{ {
if (it != residuals_params_second_derivatives.begin()) if (it != rpp.begin())
hessian1_output << ", "; hessian1_output << ", ";
int eq, param1, param2; int eq, param1, param2;
tie(eq, param1, param2) = it->first; tie(eq, param1, param2) = vectorToTuple<3>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1; int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
@ -6661,20 +6653,21 @@ DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
hessian1_output << "\"}" << endl; hessian1_output << "\"}" << endl;
} }
hessian1_output << "]}"; hessian1_output << "]}";
third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {" third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nvarcols\": " << dynJacobianColsNbr << ", \"nvarcols\": " << dynJacobianColsNbr
<< ", \"nparam1cols\": " << symbol_table.param_nbr() << ", \"nparam1cols\": " << symbol_table.param_nbr()
<< ", \"nparam2cols\": " << symbol_table.param_nbr() << ", \"nparam2cols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = jacobian_params_second_derivatives.begin(); auto &gpp = params_derivatives.find({ 1, 2 })->second;
it != jacobian_params_second_derivatives.end(); ++it) for (auto it = gpp.begin(); it != gpp.end(); ++it)
{ {
if (it != jacobian_params_second_derivatives.begin()) if (it != gpp.begin())
third_derivs_output << ", "; third_derivs_output << ", ";
int eq, var, param1, param2; int eq, var, param1, param2;
tie(eq, var, param1, param2) = it->first; tie(eq, var, param1, param2) = vectorToTuple<4>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var_col = getDynJacobianCol(var) + 1; int var_col = getDynJacobianCol(var) + 1;
@ -6708,14 +6701,14 @@ DynamicModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< ", \"nvar2cols\": " << dynJacobianColsNbr << ", \"nvar2cols\": " << dynJacobianColsNbr
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = hessian_params_derivatives.begin(); auto &hp = params_derivatives.find({ 2, 1 })->second;
it != hessian_params_derivatives.end(); ++it) for (auto it = hp.begin(); it != hp.end(); ++it)
{ {
if (it != hessian_params_derivatives.begin()) if (it != hp.begin())
third_derivs1_output << ", "; third_derivs1_output << ", ";
int eq, var1, var2, param; int eq, var1, var2, param;
tie(eq, var1, var2, param) = it->first; tie(eq, var1, var2, param) = vectorToTuple<4>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var1_col = getDynJacobianCol(var1) + 1; int var1_col = getDynJacobianCol(var1) + 1;

View File

@ -43,51 +43,41 @@ ModelTree::copyHelper(const ModelTree &m)
for (const auto & it : m.aux_equations) for (const auto & it : m.aux_equations)
aux_equations.push_back(dynamic_cast<BinaryOpNode *>(f(it))); aux_equations.push_back(dynamic_cast<BinaryOpNode *>(f(it)));
auto convert_deriv_map = [f](map<vector<int>, expr_t> dm)
{
map<vector<int>, expr_t> dm2;
for (const auto &it : dm)
dm2.emplace(it.first, f(it.second));
return dm2;
};
// Derivatives // Derivatives
for (const auto & it : m.first_derivatives) for (const auto &it : m.derivatives)
first_derivatives[it.first] = f(it.second); derivatives.push_back(convert_deriv_map(it));
for (const auto & it : m.second_derivatives) for (const auto &it : m.params_derivatives)
second_derivatives[it.first] = f(it.second); params_derivatives[it.first] = convert_deriv_map(it.second);
for (const auto & it : m.third_derivatives)
third_derivatives[it.first] = f(it.second); auto convert_temporary_terms_t = [f](temporary_terms_t tt)
for (const auto & it : m.residuals_params_derivatives) {
residuals_params_derivatives[it.first] = f(it.second); temporary_terms_t tt2;
for (const auto & it : m.residuals_params_second_derivatives) for (const auto &it : tt)
residuals_params_second_derivatives[it.first] = f(it.second); tt2.insert(f(it));
for (const auto & it : m.jacobian_params_derivatives) return tt2;
jacobian_params_derivatives[it.first] = f(it.second); };
for (const auto & it : m.jacobian_params_second_derivatives)
jacobian_params_second_derivatives[it.first] = f(it.second);
for (const auto & it : m.hessian_params_derivatives)
hessian_params_derivatives[it.first] = f(it.second);
// Temporary terms // Temporary terms
for (const auto & it : m.temporary_terms) for (const auto & it : m.temporary_terms)
temporary_terms.insert(f(it)); temporary_terms.insert(f(it));
for (const auto & it : m.temporary_terms_mlv) for (const auto & it : m.temporary_terms_mlv)
temporary_terms_mlv[f(it.first)] = f(it.second); temporary_terms_mlv[f(it.first)] = f(it.second);
for (const auto & it : m.temporary_terms_res) for (const auto &it : m.temporary_terms_derivatives)
temporary_terms_res.insert(f(it)); temporary_terms_derivatives.push_back(convert_temporary_terms_t(it));
for (const auto & it : m.temporary_terms_g1)
temporary_terms_g1.insert(f(it));
for (const auto & it : m.temporary_terms_g2)
temporary_terms_g2.insert(f(it));
for (const auto & it : m.temporary_terms_g3)
temporary_terms_g3.insert(f(it));
for (const auto & it : m.temporary_terms_idxs) for (const auto & it : m.temporary_terms_idxs)
temporary_terms_idxs[f(it.first)] = it.second; temporary_terms_idxs[f(it.first)] = it.second;
for (const auto & it : m.params_derivs_temporary_terms) for (const auto & it : m.params_derivs_temporary_terms)
params_derivs_temporary_terms.insert(f(it)); params_derivs_temporary_terms.insert(f(it));
for (const auto & it : m.params_derivs_temporary_terms_res) for (const auto & it : m.params_derivs_temporary_terms_split)
params_derivs_temporary_terms_res.insert(f(it)); params_derivs_temporary_terms_split[it.first] = convert_temporary_terms_t(it.second);
for (const auto & it : m.params_derivs_temporary_terms_g1)
params_derivs_temporary_terms_g1.insert(f(it));
for (const auto & it : m.params_derivs_temporary_terms_res2)
params_derivs_temporary_terms_res2.insert(f(it));
for (const auto & it : m.params_derivs_temporary_terms_g12)
params_derivs_temporary_terms_g12.insert(f(it));
for (const auto & it : m.params_derivs_temporary_terms_g2)
params_derivs_temporary_terms_g2.insert(f(it));
for (const auto & it : m.params_derivs_temporary_terms_idxs) for (const auto & it : m.params_derivs_temporary_terms_idxs)
params_derivs_temporary_terms_idxs[f(it.first)] = it.second; params_derivs_temporary_terms_idxs[f(it.first)] = it.second;
@ -129,28 +119,14 @@ ModelTree::operator=(const ModelTree &m)
equation_tags = m.equation_tags; equation_tags = m.equation_tags;
NNZDerivatives = m.NNZDerivatives; NNZDerivatives = m.NNZDerivatives;
first_derivatives.clear(); derivatives.clear();
second_derivatives.clear(); params_derivatives.clear();
third_derivatives.clear();
residuals_params_derivatives.clear();
residuals_params_second_derivatives.clear();
jacobian_params_derivatives.clear();
jacobian_params_second_derivatives.clear();
hessian_params_derivatives.clear();
temporary_terms.clear(); temporary_terms.clear();
temporary_terms_mlv.clear(); temporary_terms_mlv.clear();
temporary_terms_res.clear(); temporary_terms_derivatives.clear();
temporary_terms_g1.clear();
temporary_terms_g2.clear();
temporary_terms_g3.clear();
temporary_terms_idxs.clear();
params_derivs_temporary_terms.clear(); params_derivs_temporary_terms.clear();
params_derivs_temporary_terms_res.clear(); params_derivs_temporary_terms_split.clear();
params_derivs_temporary_terms_g1.clear();
params_derivs_temporary_terms_res2.clear();
params_derivs_temporary_terms_g12.clear();
params_derivs_temporary_terms_g2.clear();
params_derivs_temporary_terms_idxs.clear(); params_derivs_temporary_terms_idxs.clear();
trend_symbols_map.clear(); trend_symbols_map.clear();
@ -350,8 +326,8 @@ ModelTree::computeNonSingularNormalization(jacob_map_t &contemporaneous_jacobian
contemporaneous_jacobian[{ it->first.first, it->first.second }] = 0; contemporaneous_jacobian[{ it->first.first, it->first.second }] = 0;
try try
{ {
if (first_derivatives.find({ it->first.first, getDerivID(symbol_table.getID(SymbolType::endogenous, it->first.second), 0) }) == first_derivatives.end()) if (derivatives[1].find({ it->first.first, getDerivID(symbol_table.getID(SymbolType::endogenous, it->first.second), 0) }) == derivatives[1].end())
first_derivatives[{ it->first.first, getDerivID(symbol_table.getID(SymbolType::endogenous, it->first.second), 0) }] = Zero; derivatives[1][{ it->first.first, getDerivID(symbol_table.getID(SymbolType::endogenous, it->first.second), 0) }] = Zero;
} }
catch (DataTree::UnknownDerivIDException &e) catch (DataTree::UnknownDerivIDException &e)
{ {
@ -397,15 +373,15 @@ void
ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_map_t &contemporaneous_jacobian, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian, double cutoff, bool verbose) ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_map_t &contemporaneous_jacobian, jacob_map_t &static_jacobian, dynamic_jacob_map_t &dynamic_jacobian, double cutoff, bool verbose)
{ {
int nb_elements_contemparenous_Jacobian = 0; int nb_elements_contemparenous_Jacobian = 0;
set<pair<int, int>> jacobian_elements_to_delete; set<vector<int>> jacobian_elements_to_delete;
for (first_derivatives_t::const_iterator it = first_derivatives.begin(); for (auto it = derivatives[1].begin();
it != first_derivatives.end(); it++) it != derivatives[1].end(); it++)
{ {
int deriv_id = it->first.second; int deriv_id = it->first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
expr_t Id = it->second; expr_t Id = it->second;
int eq = it->first.first; int eq = it->first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
int var = symbol_table.getTypeSpecificID(symb); int var = symbol_table.getTypeSpecificID(symb);
int lag = getLagByDerivID(deriv_id); int lag = getLagByDerivID(deriv_id);
@ -429,7 +405,7 @@ ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_m
{ {
if (verbose) if (verbose)
cout << "the coefficient related to variable " << var << " with lag " << lag << " in equation " << eq << " is equal to " << val << " and is set to 0 in the incidence matrix (size=" << symbol_table.endo_nbr() << ")" << endl; cout << "the coefficient related to variable " << var << " with lag " << lag << " in equation " << eq << " is equal to " << val << " and is set to 0 in the incidence matrix (size=" << symbol_table.endo_nbr() << ")" << endl;
jacobian_elements_to_delete.emplace(eq, deriv_id); jacobian_elements_to_delete.insert({ eq, deriv_id });
} }
else else
{ {
@ -449,11 +425,11 @@ ModelTree::evaluateAndReduceJacobian(const eval_context_t &eval_context, jacob_m
// Get rid of the elements of the Jacobian matrix below the cutoff // Get rid of the elements of the Jacobian matrix below the cutoff
for (const auto & it : jacobian_elements_to_delete) for (const auto & it : jacobian_elements_to_delete)
first_derivatives.erase(it); derivatives[1].erase(it);
if (jacobian_elements_to_delete.size() > 0) if (jacobian_elements_to_delete.size() > 0)
{ {
cout << jacobian_elements_to_delete.size() << " elements among " << first_derivatives.size() << " in the incidence matrices are below the cutoff (" << cutoff << ") and are discarded" << endl cout << jacobian_elements_to_delete.size() << " elements among " << derivatives[1].size() << " in the incidence matrices are below the cutoff (" << cutoff << ") and are discarded" << endl
<< "The contemporaneous incidence matrix has " << nb_elements_contemparenous_Jacobian << " elements" << endl; << "The contemporaneous incidence matrix has " << nb_elements_contemparenous_Jacobian << " elements" << endl;
} }
} }
@ -1277,10 +1253,11 @@ ModelTree::ModelTree(SymbolTable &symbol_table_arg,
NumericalConstants &num_constants_arg, NumericalConstants &num_constants_arg,
ExternalFunctionsTable &external_functions_table_arg, ExternalFunctionsTable &external_functions_table_arg,
bool is_dynamic_arg) : bool is_dynamic_arg) :
DataTree {symbol_table_arg, num_constants_arg, external_functions_table_arg, is_dynamic_arg} DataTree {symbol_table_arg, num_constants_arg, external_functions_table_arg, is_dynamic_arg},
derivatives(4),
NNZDerivatives(4, 0),
temporary_terms_derivatives(4)
{ {
for (int & NNZDerivative : NNZDerivatives)
NNZDerivative = 0;
} }
int int
@ -1294,8 +1271,8 @@ ModelTree::writeDerivative(ostream &output, int eq, int symb_id, int lag,
ExprNodeOutputType output_type, ExprNodeOutputType output_type,
const temporary_terms_t &temporary_terms) const const temporary_terms_t &temporary_terms) const
{ {
auto it = first_derivatives.find({ eq, getDerivID(symb_id, lag) }); auto it = derivatives[1].find({ eq, getDerivID(symb_id, lag) });
if (it != first_derivatives.end()) if (it != derivatives[1].end())
(it->second)->writeOutput(output, output_type, temporary_terms, {}); (it->second)->writeOutput(output, output_type, temporary_terms, {});
else else
output << 0; output << 0;
@ -1311,8 +1288,8 @@ ModelTree::computeJacobian(const set<int> &vars)
expr_t d1 = equations[eq]->getDerivative(var); expr_t d1 = equations[eq]->getDerivative(var);
if (d1 == Zero) if (d1 == Zero)
continue; continue;
first_derivatives[{ eq, var }] = d1; derivatives[1][{ eq, var }] = d1;
++NNZDerivatives[0]; ++NNZDerivatives[1];
} }
} }
} }
@ -1320,10 +1297,10 @@ ModelTree::computeJacobian(const set<int> &vars)
void void
ModelTree::computeHessian(const set<int> &vars) ModelTree::computeHessian(const set<int> &vars)
{ {
for (const auto &it : first_derivatives) for (const auto &it : derivatives[1])
{ {
int eq, var1; int eq, var1;
tie(eq, var1) = it.first; tie(eq, var1) = vectorToTuple<2>(it.first);
expr_t d1 = it.second; expr_t d1 = it.second;
// Store only second derivatives with var2 <= var1 // Store only second derivatives with var2 <= var1
@ -1335,11 +1312,11 @@ ModelTree::computeHessian(const set<int> &vars)
expr_t d2 = d1->getDerivative(var2); expr_t d2 = d1->getDerivative(var2);
if (d2 == Zero) if (d2 == Zero)
continue; continue;
second_derivatives[{ eq, var1, var2 }] = d2; derivatives[2][{ eq, var1, var2 }] = d2;
if (var2 == var1) if (var2 == var1)
++NNZDerivatives[1]; ++NNZDerivatives[2];
else else
NNZDerivatives[1] += 2; NNZDerivatives[2] += 2;
} }
} }
} }
@ -1347,10 +1324,10 @@ ModelTree::computeHessian(const set<int> &vars)
void void
ModelTree::computeThirdDerivatives(const set<int> &vars) ModelTree::computeThirdDerivatives(const set<int> &vars)
{ {
for (const auto &it : second_derivatives) for (const auto &it : derivatives[2])
{ {
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = it.first; tie(eq, var1, var2) = vectorToTuple<3>(it.first);
// By construction, var2 <= var1 // By construction, var2 <= var1
expr_t d2 = it.second; expr_t d2 = it.second;
@ -1364,13 +1341,13 @@ ModelTree::computeThirdDerivatives(const set<int> &vars)
expr_t d3 = d2->getDerivative(var3); expr_t d3 = d2->getDerivative(var3);
if (d3 == Zero) if (d3 == Zero)
continue; continue;
third_derivatives[{ eq, var1, var2, var3 }] = d3; derivatives[3][{ eq, var1, var2, var3 }] = d3;
if (var3 == var2 && var2 == var1) if (var3 == var2 && var2 == var1)
++NNZDerivatives[2]; ++NNZDerivatives[3];
else if (var3 == var2 || var2 == var1) else if (var3 == var2 || var2 == var1)
NNZDerivatives[2] += 3; NNZDerivatives[3] += 3;
else else
NNZDerivatives[2] += 6; NNZDerivatives[3] += 6;
} }
} }
} }
@ -1381,10 +1358,8 @@ ModelTree::computeTemporaryTerms(bool is_matlab, bool no_tmp_terms)
map<expr_t, pair<int, NodeTreeReference>> reference_count; map<expr_t, pair<int, NodeTreeReference>> reference_count;
temporary_terms.clear(); temporary_terms.clear();
temporary_terms_mlv.clear(); temporary_terms_mlv.clear();
temporary_terms_res.clear(); temporary_terms_derivatives.clear();
temporary_terms_g1.clear(); temporary_terms_derivatives.resize(4);
temporary_terms_g2.clear();
temporary_terms_g3.clear();
// Collect all model local variables appearing in equations. See #101 // Collect all model local variables appearing in equations. See #101
// All used model local variables are automatically set as temporary variables // All used model local variables are automatically set as temporary variables
@ -1400,10 +1375,10 @@ ModelTree::computeTemporaryTerms(bool is_matlab, bool no_tmp_terms)
} }
map<NodeTreeReference, temporary_terms_t> temp_terms_map; map<NodeTreeReference, temporary_terms_t> temp_terms_map;
temp_terms_map[NodeTreeReference::residuals] = temporary_terms_res; temp_terms_map[NodeTreeReference::residuals] = temporary_terms_derivatives[0];
temp_terms_map[NodeTreeReference::firstDeriv] = temporary_terms_g1; temp_terms_map[NodeTreeReference::firstDeriv] = temporary_terms_derivatives[1];
temp_terms_map[NodeTreeReference::secondDeriv] = temporary_terms_g2; temp_terms_map[NodeTreeReference::secondDeriv] = temporary_terms_derivatives[2];
temp_terms_map[NodeTreeReference::thirdDeriv] = temporary_terms_g3; temp_terms_map[NodeTreeReference::thirdDeriv] = temporary_terms_derivatives[3];
if (!no_tmp_terms) if (!no_tmp_terms)
{ {
@ -1412,17 +1387,17 @@ ModelTree::computeTemporaryTerms(bool is_matlab, bool no_tmp_terms)
temp_terms_map, temp_terms_map,
is_matlab, NodeTreeReference::residuals); is_matlab, NodeTreeReference::residuals);
for (auto & first_derivative : first_derivatives) for (auto & first_derivative : derivatives[1])
first_derivative.second->computeTemporaryTerms(reference_count, first_derivative.second->computeTemporaryTerms(reference_count,
temp_terms_map, temp_terms_map,
is_matlab, NodeTreeReference::firstDeriv); is_matlab, NodeTreeReference::firstDeriv);
for (auto & second_derivative : second_derivatives) for (auto & second_derivative : derivatives[2])
second_derivative.second->computeTemporaryTerms(reference_count, second_derivative.second->computeTemporaryTerms(reference_count,
temp_terms_map, temp_terms_map,
is_matlab, NodeTreeReference::secondDeriv); is_matlab, NodeTreeReference::secondDeriv);
for (auto & third_derivative : third_derivatives) for (auto & third_derivative : derivatives[3])
third_derivative.second->computeTemporaryTerms(reference_count, third_derivative.second->computeTemporaryTerms(reference_count,
temp_terms_map, temp_terms_map,
is_matlab, NodeTreeReference::thirdDeriv); is_matlab, NodeTreeReference::thirdDeriv);
@ -1432,26 +1407,26 @@ ModelTree::computeTemporaryTerms(bool is_matlab, bool no_tmp_terms)
it != temp_terms_map.end(); it++) it != temp_terms_map.end(); it++)
temporary_terms.insert(it->second.begin(), it->second.end()); temporary_terms.insert(it->second.begin(), it->second.end());
temporary_terms_res = temp_terms_map[NodeTreeReference::residuals]; temporary_terms_derivatives[0] = temp_terms_map[NodeTreeReference::residuals];
temporary_terms_g1 = temp_terms_map[NodeTreeReference::firstDeriv]; temporary_terms_derivatives[1] = temp_terms_map[NodeTreeReference::firstDeriv];
temporary_terms_g2 = temp_terms_map[NodeTreeReference::secondDeriv]; temporary_terms_derivatives[2] = temp_terms_map[NodeTreeReference::secondDeriv];
temporary_terms_g3 = temp_terms_map[NodeTreeReference::thirdDeriv]; temporary_terms_derivatives[3] = temp_terms_map[NodeTreeReference::thirdDeriv];
int idx = 0; int idx = 0;
for (map<expr_t, expr_t, ExprNodeLess>::const_iterator it = temporary_terms_mlv.begin(); for (map<expr_t, expr_t, ExprNodeLess>::const_iterator it = temporary_terms_mlv.begin();
it != temporary_terms_mlv.end(); it++) it != temporary_terms_mlv.end(); it++)
temporary_terms_idxs[it->first] = idx++; temporary_terms_idxs[it->first] = idx++;
for (auto it : temporary_terms_res) for (auto it : temporary_terms_derivatives[0])
temporary_terms_idxs[it] = idx++; temporary_terms_idxs[it] = idx++;
for (auto it : temporary_terms_g1) for (auto it : temporary_terms_derivatives[1])
temporary_terms_idxs[it] = idx++; temporary_terms_idxs[it] = idx++;
for (auto it : temporary_terms_g2) for (auto it : temporary_terms_derivatives[2])
temporary_terms_idxs[it] = idx++; temporary_terms_idxs[it] = idx++;
for (auto it : temporary_terms_g3) for (auto it : temporary_terms_derivatives[3])
temporary_terms_idxs[it] = idx++; temporary_terms_idxs[it] = idx++;
} }
@ -1887,12 +1862,12 @@ ModelTree::Write_Inf_To_Bin_File(const string &filename,
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
u_count_int = 0; u_count_int = 0;
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
int var = symbol_table.getTypeSpecificID(symb); int var = symbol_table.getTypeSpecificID(symb);
int lag = getLagByDerivID(deriv_id); int lag = getLagByDerivID(deriv_id);
@ -2084,7 +2059,7 @@ ModelTree::sparseHelper(int order, ostream &output, int row_nb, int col_nb, Expr
if (isMatlabOutput(output_type) || isJuliaOutput(output_type)) if (isMatlabOutput(output_type) || isJuliaOutput(output_type))
output << row_nb + 1 << "," << col_nb + 1; output << row_nb + 1 << "," << col_nb + 1;
else else
output << row_nb + col_nb * NNZDerivatives[order-1]; output << row_nb + col_nb * NNZDerivatives[order];
output << RIGHT_ARRAY_SUBSCRIPT(output_type); output << RIGHT_ARRAY_SUBSCRIPT(output_type);
} }
@ -2103,58 +2078,58 @@ ModelTree::computeParamsDerivatives(int paramsDerivsOrder)
expr_t d1 = equations[eq]->getDerivative(param); expr_t d1 = equations[eq]->getDerivative(param);
if (d1 == Zero) if (d1 == Zero)
continue; continue;
residuals_params_derivatives[{ eq, param }] = d1; params_derivatives[{ 0, 1 }][{ eq, param }] = d1;
} }
if (paramsDerivsOrder == 2) if (paramsDerivsOrder == 2)
for (const auto &it : residuals_params_derivatives) for (const auto &it : params_derivatives[{ 0, 1 }])
{ {
int eq, param1; int eq, param1;
tie(eq, param1) = it.first; tie(eq, param1) = vectorToTuple<2>(it.first);
expr_t d1 = it.second; expr_t d1 = it.second;
expr_t d2 = d1->getDerivative(param); expr_t d2 = d1->getDerivative(param);
if (d2 == Zero) if (d2 == Zero)
continue; continue;
residuals_params_second_derivatives[{ eq, param1, param }] = d2; params_derivatives[{ 0, 2 }][{ eq, param1, param }] = d2;
} }
for (const auto &it : first_derivatives) for (const auto &it : derivatives[1])
{ {
int eq, var; int eq, var;
tie(eq, var) = it.first; tie(eq, var) = vectorToTuple<2>(it.first);
expr_t d1 = it.second; expr_t d1 = it.second;
expr_t d2 = d1->getDerivative(param); expr_t d2 = d1->getDerivative(param);
if (d2 == Zero) if (d2 == Zero)
continue; continue;
jacobian_params_derivatives[{ eq, var, param }] = d2; params_derivatives[{ 1, 1 }][{ eq, var, param }] = d2;
} }
if (paramsDerivsOrder == 2) if (paramsDerivsOrder == 2)
{ {
for (const auto &it : jacobian_params_derivatives) for (const auto &it : params_derivatives[{ 1, 1 }])
{ {
int eq, var, param1; int eq, var, param1;
tie(eq, var, param1) = it.first; tie(eq, var, param1) = vectorToTuple<3>(it.first);
expr_t d1 = it.second; expr_t d1 = it.second;
expr_t d2 = d1->getDerivative(param); expr_t d2 = d1->getDerivative(param);
if (d2 == Zero) if (d2 == Zero)
continue; continue;
jacobian_params_second_derivatives[{ eq, var, param1, param }] = d2; params_derivatives[{ 1, 2 }][{ eq, var, param1, param }] = d2;
} }
for (const auto &it : second_derivatives) for (const auto &it : derivatives[2])
{ {
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = it.first; tie(eq, var1, var2) = vectorToTuple<3>(it.first);
expr_t d1 = it.second; expr_t d1 = it.second;
expr_t d2 = d1->getDerivative(param); expr_t d2 = d1->getDerivative(param);
if (d2 == Zero) if (d2 == Zero)
continue; continue;
hessian_params_derivatives[{ eq, var1, var2, param }] = d2; params_derivatives[{ 2, 1 }][{ eq, var1, var2, param }] = d2;
} }
} }
} }
@ -2166,64 +2141,61 @@ ModelTree::computeParamsDerivativesTemporaryTerms()
map<expr_t, pair<int, NodeTreeReference >> reference_count; map<expr_t, pair<int, NodeTreeReference >> reference_count;
params_derivs_temporary_terms.clear(); params_derivs_temporary_terms.clear();
map<NodeTreeReference, temporary_terms_t> temp_terms_map; map<NodeTreeReference, temporary_terms_t> temp_terms_map;
temp_terms_map[NodeTreeReference::residualsParamsDeriv] = params_derivs_temporary_terms_res; temp_terms_map[NodeTreeReference::residualsParamsDeriv] = params_derivs_temporary_terms_split[{ 0, 1 }];
temp_terms_map[NodeTreeReference::jacobianParamsDeriv] = params_derivs_temporary_terms_g1; temp_terms_map[NodeTreeReference::jacobianParamsDeriv] = params_derivs_temporary_terms_split[{ 1, 1 }];
temp_terms_map[NodeTreeReference::residualsParamsSecondDeriv] = params_derivs_temporary_terms_res2; temp_terms_map[NodeTreeReference::residualsParamsSecondDeriv] = params_derivs_temporary_terms_split[{ 0, 2 }];
temp_terms_map[NodeTreeReference::jacobianParamsSecondDeriv] = params_derivs_temporary_terms_g12; temp_terms_map[NodeTreeReference::jacobianParamsSecondDeriv] = params_derivs_temporary_terms_split[{ 1, 2 }];
temp_terms_map[NodeTreeReference::hessianParamsDeriv] = params_derivs_temporary_terms_g2; temp_terms_map[NodeTreeReference::hessianParamsDeriv] = params_derivs_temporary_terms_split[{ 2, 1}];
for (auto & residuals_params_derivative : residuals_params_derivatives) for (const auto &residuals_params_derivative : params_derivatives[{ 0, 1 }])
residuals_params_derivative.second->computeTemporaryTerms(reference_count, residuals_params_derivative.second->computeTemporaryTerms(reference_count,
temp_terms_map, temp_terms_map,
true, NodeTreeReference::residualsParamsDeriv); true, NodeTreeReference::residualsParamsDeriv);
for (auto & jacobian_params_derivative : jacobian_params_derivatives) for (const auto &jacobian_params_derivative : params_derivatives[{ 1, 1 }])
jacobian_params_derivative.second->computeTemporaryTerms(reference_count, jacobian_params_derivative.second->computeTemporaryTerms(reference_count,
temp_terms_map, temp_terms_map,
true, NodeTreeReference::jacobianParamsDeriv); true, NodeTreeReference::jacobianParamsDeriv);
for (second_derivatives_t::const_iterator it = residuals_params_second_derivatives.begin(); for (const auto &it : params_derivatives[{ 0, 2 }])
it != residuals_params_second_derivatives.end(); ++it) it.second->computeTemporaryTerms(reference_count,
it->second->computeTemporaryTerms(reference_count, temp_terms_map,
temp_terms_map, true, NodeTreeReference::residualsParamsSecondDeriv);
true, NodeTreeReference::residualsParamsSecondDeriv);
for (third_derivatives_t::const_iterator it = jacobian_params_second_derivatives.begin(); for (const auto &it : params_derivatives[{ 1, 2 }])
it != jacobian_params_second_derivatives.end(); ++it) it.second->computeTemporaryTerms(reference_count,
it->second->computeTemporaryTerms(reference_count, temp_terms_map,
temp_terms_map, true, NodeTreeReference::jacobianParamsSecondDeriv);
true, NodeTreeReference::jacobianParamsSecondDeriv);
for (third_derivatives_t::const_iterator it = hessian_params_derivatives.begin(); for (const auto &it : params_derivatives[{ 2, 1 }])
it != hessian_params_derivatives.end(); ++it) it.second->computeTemporaryTerms(reference_count,
it->second->computeTemporaryTerms(reference_count, temp_terms_map,
temp_terms_map, true, NodeTreeReference::hessianParamsDeriv);
true, NodeTreeReference::hessianParamsDeriv);
for (map<NodeTreeReference, temporary_terms_t>::const_iterator it = temp_terms_map.begin(); for (map<NodeTreeReference, temporary_terms_t>::const_iterator it = temp_terms_map.begin();
it != temp_terms_map.end(); it++) it != temp_terms_map.end(); it++)
params_derivs_temporary_terms.insert(it->second.begin(), it->second.end()); params_derivs_temporary_terms.insert(it->second.begin(), it->second.end());
params_derivs_temporary_terms_res = temp_terms_map[NodeTreeReference::residualsParamsDeriv]; params_derivs_temporary_terms_split[{ 0, 1 }] = temp_terms_map[NodeTreeReference::residualsParamsDeriv];
params_derivs_temporary_terms_g1 = temp_terms_map[NodeTreeReference::jacobianParamsDeriv]; params_derivs_temporary_terms_split[{ 1, 1 }] = temp_terms_map[NodeTreeReference::jacobianParamsDeriv];
params_derivs_temporary_terms_res2 = temp_terms_map[NodeTreeReference::residualsParamsSecondDeriv]; params_derivs_temporary_terms_split[{ 0, 2 }] = temp_terms_map[NodeTreeReference::residualsParamsSecondDeriv];
params_derivs_temporary_terms_g12 = temp_terms_map[NodeTreeReference::jacobianParamsSecondDeriv]; params_derivs_temporary_terms_split[{ 1, 2 }] = temp_terms_map[NodeTreeReference::jacobianParamsSecondDeriv];
params_derivs_temporary_terms_g2 = temp_terms_map[NodeTreeReference::hessianParamsDeriv]; params_derivs_temporary_terms_split[{ 2, 1 }] = temp_terms_map[NodeTreeReference::hessianParamsDeriv];
int idx = 0; int idx = 0;
for (auto tt : params_derivs_temporary_terms_res) for (auto tt : params_derivs_temporary_terms_split[{ 0, 1 }])
params_derivs_temporary_terms_idxs[tt] = idx++; params_derivs_temporary_terms_idxs[tt] = idx++;
for (auto tt : params_derivs_temporary_terms_g1) for (auto tt : params_derivs_temporary_terms_split[{ 1, 1 }])
params_derivs_temporary_terms_idxs[tt] = idx++; params_derivs_temporary_terms_idxs[tt] = idx++;
for (auto tt : params_derivs_temporary_terms_res2) for (auto tt : params_derivs_temporary_terms_split[{ 0, 2 }])
params_derivs_temporary_terms_idxs[tt] = idx++; params_derivs_temporary_terms_idxs[tt] = idx++;
for (auto tt : params_derivs_temporary_terms_g12) for (auto tt : params_derivs_temporary_terms_split[{ 1, 2 }])
params_derivs_temporary_terms_idxs[tt] = idx++; params_derivs_temporary_terms_idxs[tt] = idx++;
for (auto tt : params_derivs_temporary_terms_g2) for (auto tt : params_derivs_temporary_terms_split[{ 2, 1 }])
params_derivs_temporary_terms_idxs[tt] = idx++; params_derivs_temporary_terms_idxs[tt] = idx++;
} }

View File

@ -34,6 +34,17 @@ using namespace std;
#include "DataTree.hh" #include "DataTree.hh"
#include "ExtendedPreprocessorTypes.hh" #include "ExtendedPreprocessorTypes.hh"
// Helper to convert a vector into a tuple
template <typename T, size_t... Indices>
auto vectorToTupleHelper(const vector<T>& v, index_sequence<Indices...>) {
return make_tuple(v[Indices]...);
}
template <size_t N, typename T>
auto vectorToTuple(const vector<T>& v) {
assert(v.size() >= N);
return vectorToTupleHelper(v, make_index_sequence<N>());
}
//! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation //! Vector describing equations: BlockSimulationType, if BlockSimulationType == EVALUATE_s then a expr_t on the new normalized equation
using equation_type_and_normalized_equation_t = vector<pair<EquationType, expr_t >>; using equation_type_and_normalized_equation_t = vector<pair<EquationType, expr_t >>;
@ -76,87 +87,44 @@ protected:
//! Stores equation tags //! Stores equation tags
vector<pair<int, pair<string, string>>> equation_tags; vector<pair<int, pair<string, string>>> equation_tags;
//! Stores derivatives
/*! Index 0 is not used, index 1 contains first derivatives, ...
For each derivation order, stores a map whose key is a vector of integer: the
first integer is the equation index, the remaining ones are the derivation
IDs of variables */
vector<map<vector<int>, expr_t>> derivatives;
//! Number of non-zero derivatives //! Number of non-zero derivatives
array<int, 3> NNZDerivatives; /*! Index 0 is not used, index 1 contains number of non-zero first
derivatives, ... */
vector<int> NNZDerivatives;
using first_derivatives_t = map<pair<int, int>, expr_t>; //! Derivatives with respect to parameters
//! First order derivatives /*! The key of the outer map is a pair (derivation order w.r.t. endogenous,
/*! First index is equation number, second is variable w.r. to which is computed the derivative. derivation order w.r.t. parameters). For e.g., { 1, 2 } corresponds to the jacobian
Only non-null derivatives are stored in the map. differentiated twice w.r.t. to parameters.
Variable indices are those of the getDerivID() method. In inner maps, the vector of integers consists of: the equation index, then
*/ the derivation IDs of endogenous, then the IDs of parameters */
first_derivatives_t first_derivatives; map<pair<int,int>, map<vector<int>, expr_t>> params_derivatives;
using second_derivatives_t = map<tuple<int, int, int>, expr_t>;
//! Second order derivatives
/*! First index is equation number, second and third are variables w.r. to which is computed the derivative.
Only non-null derivatives are stored in the map.
Contains only second order derivatives where var1 >= var2 (for obvious symmetry reasons).
Variable indices are those of the getDerivID() method.
*/
second_derivatives_t second_derivatives;
using third_derivatives_t = map<tuple<int, int, int, int>, expr_t>;
//! Third order derivatives
/*! First index is equation number, second, third and fourth are variables w.r. to which is computed the derivative.
Only non-null derivatives are stored in the map.
Contains only third order derivatives where var1 >= var2 >= var3 (for obvious symmetry reasons).
Variable indices are those of the getDerivID() method.
*/
third_derivatives_t third_derivatives;
//! Derivatives of the residuals w.r. to parameters
/*! First index is equation number, second is parameter.
Only non-null derivatives are stored in the map.
Parameter indices are those of the getDerivID() method.
*/
first_derivatives_t residuals_params_derivatives;
//! Second derivatives of the residuals w.r. to parameters
/*! First index is equation number, second and third indeces are parameters.
Only non-null derivatives are stored in the map.
Parameter indices are those of the getDerivID() method.
*/
second_derivatives_t residuals_params_second_derivatives;
//! Derivatives of the jacobian w.r. to parameters
/*! First index is equation number, second is endo/exo/exo_det variable, and third is parameter.
Only non-null derivatives are stored in the map.
Variable and parameter indices are those of the getDerivID() method.
*/
second_derivatives_t jacobian_params_derivatives;
//! Second derivatives of the jacobian w.r. to parameters
/*! First index is equation number, second is endo/exo/exo_det variable, and third and fourth are parameters.
Only non-null derivatives are stored in the map.
Variable and parameter indices are those of the getDerivID() method.
*/
third_derivatives_t jacobian_params_second_derivatives;
//! Derivatives of the hessian w.r. to parameters
/*! First index is equation number, first and second are endo/exo/exo_det variable, and third is parameter.
Only non-null derivatives are stored in the map.
Variable and parameter indices are those of the getDerivID() method.
*/
third_derivatives_t hessian_params_derivatives;
//! Temporary terms for the static/dynamic file (those which will be noted T[x]) //! Temporary terms for the static/dynamic file (those which will be noted T[x])
temporary_terms_t temporary_terms; temporary_terms_t temporary_terms;
//! Temporary terms for model local variables
map<expr_t, expr_t, ExprNodeLess> temporary_terms_mlv; map<expr_t, expr_t, ExprNodeLess> temporary_terms_mlv;
temporary_terms_t temporary_terms_res;
temporary_terms_t temporary_terms_g1; //! Temporary terms for residuals and derivatives
temporary_terms_t temporary_terms_g2; /*! Index 0 is temp. terms of residuals, index 1 for first derivatives, ... */
temporary_terms_t temporary_terms_g3; vector<temporary_terms_t> temporary_terms_derivatives;
temporary_terms_idxs_t temporary_terms_idxs; temporary_terms_idxs_t temporary_terms_idxs;
//! Temporary terms for the file containing parameters derivatives //! Temporary terms for the file containing parameters derivatives
temporary_terms_t params_derivs_temporary_terms; temporary_terms_t params_derivs_temporary_terms;
temporary_terms_t params_derivs_temporary_terms_res;
temporary_terms_t params_derivs_temporary_terms_g1; //! Temporary terms for parameter derivatives, under a disaggregated form
temporary_terms_t params_derivs_temporary_terms_res2; /*! The pair of integers is to be interpreted as in param_derivatives */
temporary_terms_t params_derivs_temporary_terms_g12; map<pair<int,int>, temporary_terms_t> params_derivs_temporary_terms_split;
temporary_terms_t params_derivs_temporary_terms_g2;
temporary_terms_idxs_t params_derivs_temporary_terms_idxs; temporary_terms_idxs_t params_derivs_temporary_terms_idxs;
@ -384,8 +352,8 @@ public:
/*! Writes either (i+1,j+1) or [i+j*no_eq] */ /*! 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; void jacobianHelper(ostream &output, int eq_nb, int col_nb, ExprNodeOutputType output_type) const;
//! Helper for writing the sparse Hessian or third derivatives in MATLAB and C //! Helper for writing the sparse Hessian or third derivatives in MATLAB and C
/*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[1]] /*! If order=2, writes either v2(i+1,j+1) or v2[i+j*NNZDerivatives[2]]
If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[2]] */ If order=3, writes either v3(i+1,j+1) or v3[i+j*NNZDerivatives[3]] */
void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const; void sparseHelper(int order, ostream &output, int row_nb, int col_nb, ExprNodeOutputType output_type) const;
inline static std::string inline static std::string
c_Equation_Type(int type) c_Equation_Type(int type)

View File

@ -218,8 +218,8 @@ StaticModel::StaticModel(const DynamicModel &m) :
void void
StaticModel::compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, map_idx_t &map_idx, temporary_terms_t temporary_terms) const StaticModel::compileDerivative(ofstream &code_file, unsigned int &instruction_number, int eq, int symb_id, map_idx_t &map_idx, temporary_terms_t temporary_terms) const
{ {
auto it = first_derivatives.find({ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, symb_id), 0) }); auto it = derivatives[1].find({ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, symb_id), 0) });
if (it != first_derivatives.end()) if (it != derivatives[1].end())
(it->second)->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false); (it->second)->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false);
else else
{ {
@ -247,7 +247,6 @@ StaticModel::computeTemporaryTermsOrdered()
map<expr_t, pair<int, int>> first_occurence; map<expr_t, pair<int, int>> first_occurence;
map<expr_t, int> reference_count; map<expr_t, int> reference_count;
BinaryOpNode *eq_node; BinaryOpNode *eq_node;
first_derivatives_t::const_iterator it;
first_chain_rule_derivatives_t::const_iterator it_chr; first_chain_rule_derivatives_t::const_iterator it_chr;
ostringstream tmp_s; ostringstream tmp_s;
v_temporary_terms.clear(); v_temporary_terms.clear();
@ -627,23 +626,23 @@ StaticModel::writeModelEquationsCode(const string &basename, map_idx_t map_idx)
fjmp_if_eval.write(code_file, instruction_number); fjmp_if_eval.write(code_file, instruction_number);
int prev_instruction_number = instruction_number; int prev_instruction_number = instruction_number;
vector<vector<pair<int, int>>> derivatives; vector<vector<pair<int, int>>> my_derivatives;
derivatives.resize(symbol_table.endo_nbr()); my_derivatives.resize(symbol_table.endo_nbr());
count_u = symbol_table.endo_nbr(); count_u = symbol_table.endo_nbr();
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
expr_t d1 = first_derivative.second; expr_t d1 = first_derivative.second;
unsigned int eq = first_derivative.first.first; unsigned int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
unsigned int var = symbol_table.getTypeSpecificID(symb); unsigned int var = symbol_table.getTypeSpecificID(symb);
FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var); FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var);
fnumexpr.write(code_file, instruction_number); fnumexpr.write(code_file, instruction_number);
if (!derivatives[eq].size()) if (!my_derivatives[eq].size())
derivatives[eq].clear(); my_derivatives[eq].clear();
derivatives[eq].emplace_back(var, count_u); my_derivatives[eq].emplace_back(var, count_u);
d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false); d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false);
@ -656,10 +655,10 @@ StaticModel::writeModelEquationsCode(const string &basename, map_idx_t map_idx)
{ {
FLDR_ fldr(i); FLDR_ fldr(i);
fldr.write(code_file, instruction_number); fldr.write(code_file, instruction_number);
if (derivatives[i].size()) if (my_derivatives[i].size())
{ {
for (vector<pair<int, int>>::const_iterator it = derivatives[i].begin(); for (vector<pair<int, int>>::const_iterator it = my_derivatives[i].begin();
it != derivatives[i].end(); it++) it != my_derivatives[i].end(); it++)
{ {
FLDSU_ fldsu(it->second); FLDSU_ fldsu(it->second);
fldsu.write(code_file, instruction_number); fldsu.write(code_file, instruction_number);
@ -667,7 +666,7 @@ StaticModel::writeModelEquationsCode(const string &basename, map_idx_t map_idx)
fldsv.write(code_file, instruction_number); fldsv.write(code_file, instruction_number);
FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)}; FBINARY_ fbinary{static_cast<int>(BinaryOpcode::times)};
fbinary.write(code_file, instruction_number); fbinary.write(code_file, instruction_number);
if (it != derivatives[i].begin()) if (it != my_derivatives[i].begin())
{ {
FBINARY_ fbinary{static_cast<int>(BinaryOpcode::plus)}; FBINARY_ fbinary{static_cast<int>(BinaryOpcode::plus)};
fbinary.write(code_file, instruction_number); fbinary.write(code_file, instruction_number);
@ -697,20 +696,20 @@ StaticModel::writeModelEquationsCode(const string &basename, map_idx_t map_idx)
tt3.clear(); tt3.clear();
// The Jacobian if we have to solve the block determinsitic bloc // The Jacobian if we have to solve the block determinsitic bloc
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
expr_t d1 = first_derivative.second; expr_t d1 = first_derivative.second;
unsigned int eq = first_derivative.first.first; unsigned int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
unsigned int var = symbol_table.getTypeSpecificID(symb); unsigned int var = symbol_table.getTypeSpecificID(symb);
FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var); FNUMEXPR_ fnumexpr(FirstEndoDerivative, eq, var);
fnumexpr.write(code_file, instruction_number); fnumexpr.write(code_file, instruction_number);
if (!derivatives[eq].size()) if (!my_derivatives[eq].size())
derivatives[eq].clear(); my_derivatives[eq].clear();
derivatives[eq].emplace_back(var, count_u); my_derivatives[eq].emplace_back(var, count_u);
d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false); d1->compile(code_file, instruction_number, false, temporary_terms, map_idx, false, false);
FSTPG2_ fstpg2(eq, var); FSTPG2_ fstpg2(eq, var);
@ -1201,12 +1200,12 @@ map<pair<int, pair<int, int >>, expr_t>
StaticModel::collect_first_order_derivatives_endogenous() StaticModel::collect_first_order_derivatives_endogenous()
{ {
map<pair<int, pair<int, int >>, expr_t> endo_derivatives; map<pair<int, pair<int, int >>, expr_t> endo_derivatives;
for (auto & first_derivative : first_derivatives) for (auto & first_derivative : derivatives[1])
{ {
if (getTypeByDerivID(first_derivative.first.second) == SymbolType::endogenous) if (getTypeByDerivID(first_derivative.first[1]) == SymbolType::endogenous)
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first.second)); int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first[1]));
int lag = 0; int lag = 0;
endo_derivatives[{ eq, { var, lag } }] = first_derivative.second; endo_derivatives[{ eq, { var, lag } }] = first_derivative.second;
} }
@ -1248,7 +1247,6 @@ StaticModel::computingPass(const eval_context_t &eval_context, bool no_tmp_terms
if (!nopreprocessoroutput) if (!nopreprocessoroutput)
cout << "Computing static model derivatives:" << endl cout << "Computing static model derivatives:" << endl
<< " - order 1" << endl; << " - order 1" << endl;
first_derivatives.clear();
computeJacobian(vars); computeJacobian(vars);
@ -1470,7 +1468,7 @@ StaticModel::writeStaticMatlabCompatLayer(const string &basename) const
cerr << "Error: Can't open file " << filename << " for writing" << endl; cerr << "Error: Can't open file " << filename << " for writing" << endl;
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
int ntt = temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size(); 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();
output << "function [residual, g1, g2, g3] = static(y, x, params)" << endl output << "function [residual, g1, g2, g3] = static(y, x, params)" << endl
<< " T = NaN(" << ntt << ", 1);" << endl << " T = NaN(" << ntt << ", 1);" << endl
@ -1526,11 +1524,11 @@ StaticModel::writeStaticModel(const string &basename,
writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_mlv, writeModelLocalVariableTemporaryTerms(temp_term_union, temporary_terms_mlv,
model_tt_output, output_type, tef_terms); model_tt_output, output_type, tef_terms);
writeTemporaryTerms(temporary_terms_res, writeTemporaryTerms(temporary_terms_derivatives[0],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
model_tt_output, output_type, tef_terms); model_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_res.begin(), temporary_terms_res.end()); temp_term_union.insert(temporary_terms_derivatives[0].begin(), temporary_terms_derivatives[0].end());
writeModelEquations(model_output, output_type, temp_term_union); writeModelEquations(model_output, output_type, temp_term_union);
@ -1539,18 +1537,18 @@ StaticModel::writeStaticModel(const string &basename,
int hessianColsNbr = JacobianColsNbr*JacobianColsNbr; int hessianColsNbr = JacobianColsNbr*JacobianColsNbr;
// Write Jacobian w.r. to endogenous only // Write Jacobian w.r. to endogenous only
if (!first_derivatives.empty()) if (!derivatives[1].empty())
{ {
writeTemporaryTerms(temporary_terms_g1, writeTemporaryTerms(temporary_terms_derivatives[1],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
jacobian_tt_output, output_type, tef_terms); jacobian_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); temp_term_union.insert(temporary_terms_derivatives[1].begin(), temporary_terms_derivatives[1].end());
} }
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int eq, var; int eq, var;
tie(eq, var) = first_derivative.first; tie(eq, var) = vectorToTuple<2>(first_derivative.first);
expr_t d1 = first_derivative.second; expr_t d1 = first_derivative.second;
int symb_id = getSymbIDByDerivID(var); int symb_id = getSymbIDByDerivID(var);
@ -1563,19 +1561,19 @@ StaticModel::writeStaticModel(const string &basename,
int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr(); int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr();
// Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed) // Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed)
if (!second_derivatives.empty()) if (!derivatives[2].empty())
{ {
writeTemporaryTerms(temporary_terms_g2, writeTemporaryTerms(temporary_terms_derivatives[2],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
hessian_tt_output, output_type, tef_terms); hessian_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); temp_term_union.insert(temporary_terms_derivatives[2].begin(), temporary_terms_derivatives[2].end());
int k = 0; // Keep the line of a 2nd derivative in v2 int k = 0; // Keep the line of a 2nd derivative in v2
for (const auto & second_derivative : second_derivatives) for (const auto & second_derivative : derivatives[2])
{ {
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = second_derivative.first; tie(eq, var1, var2) = vectorToTuple<3>(second_derivative.first);
expr_t d2 = second_derivative.second; expr_t d2 = second_derivative.second;
int symb_id1 = getSymbIDByDerivID(var1); int symb_id1 = getSymbIDByDerivID(var1);
@ -1634,19 +1632,19 @@ StaticModel::writeStaticModel(const string &basename,
} }
// Writing third derivatives // Writing third derivatives
if (!third_derivatives.empty()) if (!derivatives[3].empty())
{ {
writeTemporaryTerms(temporary_terms_g3, writeTemporaryTerms(temporary_terms_derivatives[3],
temp_term_union, temp_term_union,
temporary_terms_idxs, temporary_terms_idxs,
third_derivatives_tt_output, output_type, tef_terms); third_derivatives_tt_output, output_type, tef_terms);
temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); temp_term_union.insert(temporary_terms_derivatives[3].begin(), temporary_terms_derivatives[3].end());
int k = 0; // Keep the line of a 3rd derivative in v3 int k = 0; // Keep the line of a 3rd derivative in v3
for (const auto & third_derivative : third_derivatives) for (const auto & third_derivative : derivatives[3])
{ {
int eq, var1, var2, var3; int eq, var1, var2, var3;
tie(eq, var1, var2, var3) = third_derivative.first; tie(eq, var1, var2, var3) = vectorToTuple<4>(third_derivative.first);
expr_t d3 = third_derivative.second; expr_t d3 = third_derivative.second;
int id1 = getSymbIDByDerivID(var1); int id1 = getSymbIDByDerivID(var1);
@ -1731,7 +1729,7 @@ StaticModel::writeStaticModel(const string &basename,
<< " residual = real(residual)+imag(residual).^2;" << endl << " residual = real(residual)+imag(residual).^2;" << endl
<< "end"; << "end";
writeStaticModelHelper(basename, "static_resid", "residual", "static_resid_tt", writeStaticModelHelper(basename, "static_resid", "residual", "static_resid_tt",
temporary_terms_mlv.size() + temporary_terms_res.size(), temporary_terms_mlv.size() + temporary_terms_derivatives[0].size(),
"", init_output, end_output, "", init_output, end_output,
model_output, model_tt_output); model_output, model_tt_output);
@ -1744,7 +1742,7 @@ StaticModel::writeStaticModel(const string &basename,
<< " g1 = real(g1)+2*imag(g1);" << endl << " g1 = real(g1)+2*imag(g1);" << endl
<< "end"; << "end";
writeStaticModelHelper(basename, "static_g1", "g1", "static_g1_tt", writeStaticModelHelper(basename, "static_g1", "g1", "static_g1_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size(), temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size(),
"static_resid_tt", "static_resid_tt",
init_output, end_output, init_output, end_output,
jacobian_output, jacobian_tt_output); jacobian_output, jacobian_tt_output);
@ -1754,16 +1752,16 @@ StaticModel::writeStaticModel(const string &basename,
init_output.clear(); init_output.clear();
end_output.str(string()); end_output.str(string());
end_output.clear(); end_output.clear();
if (second_derivatives.size()) if (derivatives[2].size())
{ {
init_output << "v2 = zeros(" << NNZDerivatives[1] << ",3);"; init_output << "v2 = zeros(" << NNZDerivatives[2] << ",3);";
end_output << "g2 = sparse(v2(:,1),v2(:,2),v2(:,3)," << equations.size() << "," << g2ncols << ");"; end_output << "g2 = sparse(v2(:,1),v2(:,2),v2(:,3)," << equations.size() << "," << g2ncols << ");";
} }
else else
init_output << "g2 = sparse([],[],[]," << equations.size() << "," << g2ncols << ");"; init_output << "g2 = sparse([],[],[]," << equations.size() << "," << g2ncols << ");";
writeStaticModelHelper(basename, "static_g2", "g2", "static_g2_tt", writeStaticModelHelper(basename, "static_g2", "g2", "static_g2_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size()
+ temporary_terms_g2.size(), + temporary_terms_derivatives[2].size(),
"static_g1_tt", "static_g1_tt",
init_output, end_output, init_output, end_output,
hessian_output, hessian_tt_output); hessian_output, hessian_tt_output);
@ -1774,16 +1772,16 @@ StaticModel::writeStaticModel(const string &basename,
end_output.str(string()); end_output.str(string());
end_output.clear(); end_output.clear();
int ncols = hessianColsNbr * JacobianColsNbr; int ncols = hessianColsNbr * JacobianColsNbr;
if (third_derivatives.size()) if (derivatives[3].size())
{ {
init_output << "v3 = zeros(" << NNZDerivatives[2] << ",3);"; init_output << "v3 = zeros(" << NNZDerivatives[3] << ",3);";
end_output << "g3 = sparse(v3(:,1),v3(:,2),v3(:,3)," << nrows << "," << ncols << ");"; end_output << "g3 = sparse(v3(:,1),v3(:,2),v3(:,3)," << nrows << "," << ncols << ");";
} }
else else
init_output << "g3 = sparse([],[],[]," << nrows << "," << ncols << ");"; init_output << "g3 = sparse([],[],[]," << nrows << "," << ncols << ");";
writeStaticModelHelper(basename, "static_g3", "g3", "static_g3_tt", writeStaticModelHelper(basename, "static_g3", "g3", "static_g3_tt",
temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() + temporary_terms_derivatives[1].size()
+ temporary_terms_g2.size() + temporary_terms_g3.size(), + temporary_terms_derivatives[2].size() + temporary_terms_derivatives[3].size(),
"static_g2_tt", "static_g2_tt",
init_output, end_output, init_output, end_output,
third_derivatives_output, third_derivatives_tt_output); third_derivatives_output, third_derivatives_tt_output);
@ -1888,15 +1886,15 @@ StaticModel::writeStaticModel(const string &basename,
// Write the number of temporary terms // Write the number of temporary terms
output << "tmp_nbr = zeros(Int,4)" << endl output << "tmp_nbr = zeros(Int,4)" << endl
<< "tmp_nbr[1] = " << temporary_terms_mlv.size() + temporary_terms_res.size() << "# Number of temporary terms for the residuals" << 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_g1.size() << "# Number of temporary terms for g1 (jacobian)" << endl << "tmp_nbr[2] = " << temporary_terms_derivatives[1].size() << "# Number of temporary terms for g1 (jacobian)" << endl
<< "tmp_nbr[3] = " << temporary_terms_g2.size() << "# Number of temporary terms for g2 (hessian)" << endl << "tmp_nbr[3] = " << temporary_terms_derivatives[2].size() << "# Number of temporary terms for g2 (hessian)" << endl
<< "tmp_nbr[4] = " << temporary_terms_g3.size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl; << "tmp_nbr[4] = " << temporary_terms_derivatives[3].size() << "# Number of temporary terms for g3 (third order derivates)" << endl << endl;
// staticResidTT! // staticResidTT!
output << "function staticResidTT!(T::Vector{Float64}," << endl output << "function staticResidTT!(T::Vector{Float64}," << endl
<< " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl << " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64})" << endl
<< " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_res.size() << endl << " @assert length(T) >= " << temporary_terms_mlv.size() + temporary_terms_derivatives[0].size() << endl
<< model_tt_output.str() << model_tt_output.str()
<< " return nothing" << endl << " return nothing" << endl
<< "end" << endl << endl; << "end" << endl << endl;
@ -1932,7 +1930,7 @@ StaticModel::writeStaticModel(const string &basename,
output << "function staticG1!(T::Vector{Float64}, g1::Matrix{Float64}," << endl 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 << " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= " << " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() << endl << 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 size(g1) == (" << equations.size() << ", " << symbol_table.endo_nbr() << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl << " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl << " @assert length(x) == " << symbol_table.exo_nbr() << endl
@ -1962,7 +1960,7 @@ StaticModel::writeStaticModel(const string &basename,
output << "function staticG2!(T::Vector{Float64}, g2::Matrix{Float64}," << endl 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 << " y::Vector{Float64}, x::Vector{Float64}, params::Vector{Float64}, T2_flag::Bool, T1_flag::Bool, T0_flag::Bool)" << endl
<< " @assert length(T) >= " << " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() << endl << 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() << ", " << g2ncols << ")" << endl << " @assert size(g2) == (" << equations.size() << ", " << g2ncols << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl << " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl << " @assert length(x) == " << symbol_table.exo_nbr() << endl
@ -1990,7 +1988,7 @@ StaticModel::writeStaticModel(const string &basename,
output << "function staticG3!(T::Vector{Float64}, g3::Matrix{Float64}," << endl 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 << " 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) >= " << " @assert length(T) >= "
<< temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size() << endl << 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 size(g3) == (" << nrows << ", " << ncols << ")" << endl
<< " @assert length(y) == " << symbol_table.endo_nbr() << endl << " @assert length(y) == " << symbol_table.endo_nbr() << endl
<< " @assert length(x) == " << symbol_table.exo_nbr() << endl << " @assert length(x) == " << symbol_table.exo_nbr() << endl
@ -2043,7 +2041,7 @@ StaticModel::writeStaticCFile(const string &basename) const
string filename = basename + "/model/src/static.c"; string filename = basename + "/model/src/static.c";
string filename_mex = basename + "/model/src/static_mex.c"; string filename_mex = basename + "/model/src/static_mex.c";
int ntt = temporary_terms_mlv.size() + temporary_terms_res.size() + temporary_terms_g1.size() + temporary_terms_g2.size() + temporary_terms_g3.size(); 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();
ofstream output; ofstream output;
output.open(filename, ios::out | ios::binary); output.open(filename, ios::out | ios::binary);
@ -2146,7 +2144,7 @@ StaticModel::writeStaticCFile(const string &basename) const
<< " if (nlhs >= 3)" << endl << " if (nlhs >= 3)" << endl
<< " {" << endl << " {" << endl
<< " /* Set the output pointer to the output matrix v2. */" << endl << " /* Set the output pointer to the output matrix v2. */" << endl
<< " plhs[2] = mxCreateDoubleMatrix(" << NNZDerivatives[1] << ", " << 3 << " plhs[2] = mxCreateDoubleMatrix(" << NNZDerivatives[2] << ", " << 3
<< ", mxREAL);" << endl << ", mxREAL);" << endl
<< " double *v2 = mxGetPr(plhs[2]);" << endl << " double *v2 = mxGetPr(plhs[2]);" << endl
<< " static_g2_tt(y, x, nb_row_x, params, T);" << endl << " static_g2_tt(y, x, nb_row_x, params, T);" << endl
@ -2250,10 +2248,10 @@ void
StaticModel::writeOutput(ostream &output, bool block) const StaticModel::writeOutput(ostream &output, bool block) const
{ {
output << "M_.static_tmp_nbr = zeros(4,1); % Number of temporaries used for the static model" <<endl output << "M_.static_tmp_nbr = zeros(4,1); % Number of temporaries used for the static model" <<endl
<< "M_.static_tmp_nbr(1) = " << temporary_terms_res.size() << "; % Number of temporaries used for the evaluation of the residuals" << endl << "M_.static_tmp_nbr(1) = " << temporary_terms_derivatives[0].size() << "; % Number of temporaries used for the evaluation of the residuals" << endl
<< "M_.static_tmp_nbr(2) = " << temporary_terms_g1.size() << "; % Number of temporaries used for the evaluation of g1 (jacobian)" << endl << "M_.static_tmp_nbr(2) = " << temporary_terms_derivatives[1].size() << "; % Number of temporaries used for the evaluation of g1 (jacobian)" << endl
<< "M_.static_tmp_nbr(3) = " << temporary_terms_g2.size() << "; % Number of temporaries used for the evaluation of g2 (hessian)" << endl << "M_.static_tmp_nbr(3) = " << temporary_terms_derivatives[2].size() << "; % Number of temporaries used for the evaluation of g2 (hessian)" << endl
<< "M_.static_tmp_nbr(4) = " << temporary_terms_g3.size() << "; % Number of temporaries used for the evaluation of g3 (third order derivatives)" << endl; << "M_.static_tmp_nbr(4) = " << temporary_terms_derivatives[3].size() << "; % Number of temporaries used for the evaluation of g3 (third order derivatives)" << endl;
if (!block) if (!block)
return; return;
@ -2290,12 +2288,12 @@ StaticModel::writeOutput(ostream &output, bool block) const
output << "];\n"; output << "];\n";
map<pair<int, int>, int> row_incidence; map<pair<int, int>, int> row_incidence;
for (const auto & first_derivative : first_derivatives) for (const auto & first_derivative : derivatives[1])
{ {
int deriv_id = first_derivative.first.second; int deriv_id = first_derivative.first[1];
if (getTypeByDerivID(deriv_id) == SymbolType::endogenous) if (getTypeByDerivID(deriv_id) == SymbolType::endogenous)
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int symb = getSymbIDByDerivID(deriv_id); int symb = getSymbIDByDerivID(deriv_id);
int var = symbol_table.getTypeSpecificID(symb); int var = symbol_table.getTypeSpecificID(symb);
//int lag = getLagByDerivID(deriv_id); //int lag = getLagByDerivID(deriv_id);
@ -2444,7 +2442,7 @@ StaticModel::computeChainRuleJacobian(blocks_derivatives_t &blocks_derivatives)
int eqr = it_l.second.first; int eqr = it_l.second.first;
int varr = it_l.second.second; int varr = it_l.second.second;
if (Deriv_type == 0) if (Deriv_type == 0)
first_chain_rule_derivatives[{ eqr, { varr, lag } }] = first_derivatives[{ eqr, getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag) }]; first_chain_rule_derivatives[{ eqr, { varr, lag } }] = derivatives[1][{ eqr, getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag) }];
else if (Deriv_type == 1) else if (Deriv_type == 1)
first_chain_rule_derivatives[{ eqr, { varr, lag } }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables); first_chain_rule_derivatives[{ eqr, { varr, lag } }] = (equation_type_and_normalized_equation[eqr].second)->getChainRuleDerivative(getDerivID(symbol_table.getID(SymbolType::endogenous, varr), lag), recursive_variables);
else if (Deriv_type == 2) else if (Deriv_type == 2)
@ -2505,10 +2503,10 @@ StaticModel::collect_block_first_order_derivatives()
derivative_endo = vector<derivative_t>(nb_blocks); derivative_endo = vector<derivative_t>(nb_blocks);
endo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 }); endo_max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 }); max_leadlag_block = vector<pair<int, int>>(nb_blocks, { 0, 0 });
for (auto & first_derivative : first_derivatives) for (auto & first_derivative : derivatives[1])
{ {
int eq = first_derivative.first.first; int eq = first_derivative.first[0];
int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first.second)); int var = symbol_table.getTypeSpecificID(getSymbIDByDerivID(first_derivative.first[1]));
int lag = 0; int lag = 0;
int block_eq = equation_2_block[eq]; int block_eq = equation_2_block[eq];
int block_var = variable_2_block[var]; int block_var = variable_2_block[var];
@ -2518,10 +2516,10 @@ StaticModel::collect_block_first_order_derivatives()
endo_max_leadlag_block[block_eq] = { 0, 0 }; endo_max_leadlag_block[block_eq] = { 0, 0 };
derivative_t tmp_derivative; derivative_t tmp_derivative;
lag_var_t lag_var; lag_var_t lag_var;
if (getTypeByDerivID(first_derivative.first.second) == SymbolType::endogenous && block_eq == block_var) if (getTypeByDerivID(first_derivative.first[1]) == SymbolType::endogenous && block_eq == block_var)
{ {
tmp_derivative = derivative_endo[block_eq]; tmp_derivative = derivative_endo[block_eq];
tmp_derivative[{ lag, { eq, var } }] = first_derivatives[{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }]; tmp_derivative[{ lag, { eq, var } }] = derivatives[1][{ eq, getDerivID(symbol_table.getID(SymbolType::endogenous, var), lag) }];
derivative_endo[block_eq] = tmp_derivative; derivative_endo[block_eq] = tmp_derivative;
} }
} }
@ -2642,11 +2640,7 @@ StaticModel::writeJsonAuxVarRecursiveDefinitions(ostream &output) const
void void
StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) const StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) const
{ {
if (!residuals_params_derivatives.size() if (!params_derivatives.size())
&& !residuals_params_second_derivatives.size()
&& !jacobian_params_derivatives.size()
&& !jacobian_params_second_derivatives.size()
&& !hessian_params_derivatives.size())
return; return;
ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaStaticModel : ExprNodeOutputType::matlabStaticModel); ExprNodeOutputType output_type = (julia ? ExprNodeOutputType::juliaStaticModel : ExprNodeOutputType::matlabStaticModel);
@ -2663,10 +2657,10 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
writeTemporaryTerms(params_derivs_temporary_terms, {}, params_derivs_temporary_terms_idxs, model_output, output_type, tef_terms); writeTemporaryTerms(params_derivs_temporary_terms, {}, params_derivs_temporary_terms_idxs, model_output, output_type, tef_terms);
for (const auto & residuals_params_derivative : residuals_params_derivatives) for (const auto & residuals_params_derivative : params_derivatives.find({ 0, 1 })->second)
{ {
int eq, param; int eq, param;
tie(eq, param) = residuals_params_derivative.first; tie(eq, param) = vectorToTuple<2>(residuals_params_derivative.first);
expr_t d1 = residuals_params_derivative.second; expr_t d1 = residuals_params_derivative.second;
int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1; int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
@ -2678,10 +2672,10 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
jacobian_output << ";" << endl; jacobian_output << ";" << endl;
} }
for (const auto & jacobian_params_derivative : jacobian_params_derivatives) for (const auto & jacobian_params_derivative : params_derivatives.find({ 1, 1 })->second)
{ {
int eq, var, param; int eq, var, param;
tie(eq, var, param) = jacobian_params_derivative.first; tie(eq, var, param) = vectorToTuple<3>(jacobian_params_derivative.first);
expr_t d2 = jacobian_params_derivative.second; expr_t d2 = jacobian_params_derivative.second;
int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1; int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
@ -2695,10 +2689,10 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
} }
int i = 1; int i = 1;
for (const auto &it : residuals_params_second_derivatives) for (const auto &it : params_derivatives.find({ 0, 2 })->second)
{ {
int eq, param1, param2; int eq, param1, param2;
tie(eq, param1, param2) = it.first; tie(eq, param1, param2) = vectorToTuple<3>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1; int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
@ -2719,10 +2713,10 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
} }
i = 1; i = 1;
for (const auto &it : jacobian_params_second_derivatives) for (const auto &it : params_derivatives.find({ 1, 2 })->second)
{ {
int eq, var, param1, param2; int eq, var, param1, param2;
tie(eq, var, param1, param2) = it.first; tie(eq, var, param1, param2) = vectorToTuple<4>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1; int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
@ -2746,10 +2740,10 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
} }
i = 1; i = 1;
for (const auto &it : hessian_params_derivatives) for (const auto &it : params_derivatives.find({ 2, 1 })->second)
{ {
int eq, var1, var2, param; int eq, var1, var2, param;
tie(eq, var1, var2, param) = it.first; tie(eq, var1, var2, param) = vectorToTuple<4>(it.first);
expr_t d2 = it.second; expr_t d2 = it.second;
int var1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var1)) + 1; int var1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var1)) + 1;
@ -2836,13 +2830,13 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
<< symbol_table.param_nbr() << ");" << endl << symbol_table.param_nbr() << ");" << endl
<< hessian_output.str() << hessian_output.str()
<< "if nargout >= 3" << endl << "if nargout >= 3" << endl
<< "rpp = zeros(" << residuals_params_second_derivatives.size() << ",4);" << endl << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
<< hessian1_output.str() << hessian1_output.str()
<< "gpp = zeros(" << jacobian_params_second_derivatives.size() << ",5);" << endl << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
<< third_derivs_output.str() << third_derivs_output.str()
<< "end" << endl << "end" << endl
<< "if nargout >= 5" << endl << "if nargout >= 5" << endl
<< "hp = zeros(" << hessian_params_derivatives.size() << ",5);" << endl << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
<< third_derivs1_output.str() << third_derivs1_output.str()
<< "end" << endl << "end" << endl
<< "end" << endl; << "end" << endl;
@ -2863,11 +2857,11 @@ StaticModel::writeParamsDerivativesFile(const string &basename, bool julia) cons
<< "gp = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ", " << "gp = zeros(" << equations.size() << ", " << symbol_table.endo_nbr() << ", "
<< symbol_table.param_nbr() << ");" << endl << symbol_table.param_nbr() << ");" << endl
<< hessian_output.str() << hessian_output.str()
<< "rpp = zeros(" << residuals_params_second_derivatives.size() << ",4);" << endl << "rpp = zeros(" << params_derivatives.find({ 0, 2 })->second.size() << ",4);" << endl
<< hessian1_output.str() << hessian1_output.str()
<< "gpp = zeros(" << jacobian_params_second_derivatives.size() << ",5);" << endl << "gpp = zeros(" << params_derivatives.find({ 1, 2 })->second.size() << ",5);" << endl
<< third_derivs_output.str() << third_derivs_output.str()
<< "hp = zeros(" << hessian_params_derivatives.size() << ",5);" << endl << "hp = zeros(" << params_derivatives.find({ 2, 1 })->second.size() << ",5);" << endl
<< third_derivs1_output.str() << third_derivs1_output.str()
<< "(rp, gp, rpp, gpp, hp)" << endl << "(rp, gp, rpp, gpp, hp)" << endl
<< "end" << endl << "end" << endl
@ -2892,14 +2886,14 @@ StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) co
ostringstream third_derivatives_output; // Used for storing third order derivatives equations ostringstream third_derivatives_output; // Used for storing third order derivatives equations
deriv_node_temp_terms_t tef_terms; deriv_node_temp_terms_t tef_terms;
temporary_terms_t temp_term_union = temporary_terms_res; temporary_terms_t temp_term_union = temporary_terms_derivatives[0];
temporary_terms_t temp_term_union_m_1; temporary_terms_t temp_term_union_m_1;
string concat = ""; string concat = "";
writeJsonModelLocalVariables(model_local_vars_output, tef_terms); writeJsonModelLocalVariables(model_local_vars_output, tef_terms);
writeJsonTemporaryTerms(temporary_terms_res, temp_term_union_m_1, model_output, tef_terms, concat); writeJsonTemporaryTerms(temporary_terms_derivatives[0], temp_term_union_m_1, model_output, tef_terms, concat);
model_output << ", "; model_output << ", ";
writeJsonModelEquations(model_output, true); writeJsonModelEquations(model_output, true);
@ -2909,21 +2903,21 @@ StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) co
// Write Jacobian w.r. to endogenous only // Write Jacobian w.r. to endogenous only
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g1.begin(), temporary_terms_g1.end()); temp_term_union.insert(temporary_terms_derivatives[1].begin(), temporary_terms_derivatives[1].end());
concat = "jacobian"; concat = "jacobian";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, jacobian_output, tef_terms, concat);
jacobian_output << ", \"jacobian\": {" jacobian_output << ", \"jacobian\": {"
<< " \"nrows\": " << nrows << " \"nrows\": " << nrows
<< ", \"ncols\": " << JacobianColsNbr << ", \"ncols\": " << JacobianColsNbr
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = first_derivatives.begin(); for (auto it = derivatives[1].begin();
it != first_derivatives.end(); it++) it != derivatives[1].end(); it++)
{ {
if (it != first_derivatives.begin()) if (it != derivatives[1].begin())
jacobian_output << ", "; jacobian_output << ", ";
int eq, var; int eq, var;
tie(eq, var) = it->first; tie(eq, var) = vectorToTuple<2>(it->first);
int symb_id = getSymbIDByDerivID(var); int symb_id = getSymbIDByDerivID(var);
int col = symbol_table.getTypeSpecificID(symb_id); int col = symbol_table.getTypeSpecificID(symb_id);
expr_t d1 = it->second; expr_t d1 = it->second;
@ -2947,21 +2941,21 @@ StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) co
int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr(); int g2ncols = symbol_table.endo_nbr() * symbol_table.endo_nbr();
// Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed) // Write Hessian w.r. to endogenous only (only if 2nd order derivatives have been computed)
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g2.begin(), temporary_terms_g2.end()); temp_term_union.insert(temporary_terms_derivatives[2].begin(), temporary_terms_derivatives[2].end());
concat = "hessian"; concat = "hessian";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, hessian_output, tef_terms, concat);
hessian_output << ", \"hessian\": {" hessian_output << ", \"hessian\": {"
<< " \"nrows\": " << equations.size() << " \"nrows\": " << equations.size()
<< ", \"ncols\": " << g2ncols << ", \"ncols\": " << g2ncols
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = second_derivatives.begin(); for (auto it = derivatives[2].begin();
it != second_derivatives.end(); it++) it != derivatives[2].end(); it++)
{ {
if (it != second_derivatives.begin()) if (it != derivatives[2].begin())
hessian_output << ", "; hessian_output << ", ";
int eq, var1, var2; int eq, var1, var2;
tie(eq, var1, var2) = it->first; tie(eq, var1, var2) = vectorToTuple<3>(it->first);
int symb_id1 = getSymbIDByDerivID(var1); int symb_id1 = getSymbIDByDerivID(var1);
int symb_id2 = getSymbIDByDerivID(var2); int symb_id2 = getSymbIDByDerivID(var2);
expr_t d2 = it->second; expr_t d2 = it->second;
@ -2994,21 +2988,21 @@ StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) co
// Writing third derivatives // Writing third derivatives
temp_term_union_m_1 = temp_term_union; temp_term_union_m_1 = temp_term_union;
temp_term_union.insert(temporary_terms_g3.begin(), temporary_terms_g3.end()); temp_term_union.insert(temporary_terms_derivatives[3].begin(), temporary_terms_derivatives[3].end());
concat = "third_derivatives"; concat = "third_derivatives";
writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat); writeJsonTemporaryTerms(temp_term_union, temp_term_union_m_1, third_derivatives_output, tef_terms, concat);
third_derivatives_output << ", \"third_derivative\": {" third_derivatives_output << ", \"third_derivative\": {"
<< " \"nrows\": " << equations.size() << " \"nrows\": " << equations.size()
<< ", \"ncols\": " << hessianColsNbr * JacobianColsNbr << ", \"ncols\": " << hessianColsNbr * JacobianColsNbr
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = third_derivatives.begin(); for (auto it = derivatives[3].begin();
it != third_derivatives.end(); it++) it != derivatives[3].end(); it++)
{ {
if (it != third_derivatives.begin()) if (it != derivatives[3].begin())
third_derivatives_output << ", "; third_derivatives_output << ", ";
int eq, var1, var2, var3; int eq, var1, var2, var3;
tie(eq, var1, var2, var3) = it->first; tie(eq, var1, var2, var3) = vectorToTuple<4>(it->first);
expr_t d3 = it->second; expr_t d3 = it->second;
if (writeDetails) if (writeDetails)
@ -3062,11 +3056,7 @@ StaticModel::writeJsonComputingPassOutput(ostream &output, bool writeDetails) co
void void
StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails) const
{ {
if (!residuals_params_derivatives.size() if (!params_derivatives.size())
&& !residuals_params_second_derivatives.size()
&& !jacobian_params_derivatives.size()
&& !jacobian_params_second_derivatives.size()
&& !hessian_params_derivatives.size())
return; return;
ostringstream model_local_vars_output; // Used for storing model local vars ostringstream model_local_vars_output; // Used for storing model local vars
@ -3087,14 +3077,14 @@ StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = residuals_params_derivatives.begin(); auto &rp = params_derivatives.find({ 0, 1 })->second;
it != residuals_params_derivatives.end(); it++) for (auto it = rp.begin(); it != rp.end(); it++)
{ {
if (it != residuals_params_derivatives.begin()) if (it != rp.begin())
jacobian_output << ", "; jacobian_output << ", ";
int eq, param; int eq, param;
tie(eq, param) = it->first; tie(eq, param) = vectorToTuple<2>(it->first);
expr_t d1 = it->second; expr_t d1 = it->second;
int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1; int param_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param)) + 1;
@ -3114,19 +3104,20 @@ StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
jacobian_output << "\"}" << endl; jacobian_output << "\"}" << endl;
} }
jacobian_output << "]}"; jacobian_output << "]}";
hessian_output << "\"deriv_jacobian_wrt_params\": {" hessian_output << "\"deriv_jacobian_wrt_params\": {"
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nvarcols\": " << symbol_table.endo_nbr() << ", \"nvarcols\": " << symbol_table.endo_nbr()
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = jacobian_params_derivatives.begin(); auto &gp = params_derivatives.find({ 1, 1 })->second;
it != jacobian_params_derivatives.end(); it++) for (auto it = gp.begin(); it != gp.end(); it++)
{ {
if (it != jacobian_params_derivatives.begin()) if (it != gp.begin())
hessian_output << ", "; hessian_output << ", ";
int eq, var, param; int eq, var, param;
tie(eq, var, param) = it->first; tie(eq, var, param) = vectorToTuple<3>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1; int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
@ -3154,14 +3145,14 @@ StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< ", \"nparam1cols\": " << symbol_table.param_nbr() << ", \"nparam1cols\": " << symbol_table.param_nbr()
<< ", \"nparam2cols\": " << symbol_table.param_nbr() << ", \"nparam2cols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = residuals_params_second_derivatives.begin(); auto &rpp = params_derivatives.find({ 0, 2 })->second;
it != residuals_params_second_derivatives.end(); ++it) for (auto it = rpp.begin(); it != rpp.end(); ++it)
{ {
if (it != residuals_params_second_derivatives.begin()) if (it != rpp.begin())
hessian1_output << ", "; hessian1_output << ", ";
int eq, param1, param2; int eq, param1, param2;
tie(eq, param1, param2) = it->first; tie(eq, param1, param2) = vectorToTuple<3>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1; int param1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(param1)) + 1;
@ -3184,20 +3175,21 @@ StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
hessian1_output << "\"}" << endl; hessian1_output << "\"}" << endl;
} }
hessian1_output << "]}"; hessian1_output << "]}";
third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {" third_derivs_output << "\"second_deriv_jacobian_wrt_params\": {"
<< " \"neqs\": " << equations.size() << " \"neqs\": " << equations.size()
<< ", \"nvarcols\": " << symbol_table.endo_nbr() << ", \"nvarcols\": " << symbol_table.endo_nbr()
<< ", \"nparam1cols\": " << symbol_table.param_nbr() << ", \"nparam1cols\": " << symbol_table.param_nbr()
<< ", \"nparam2cols\": " << symbol_table.param_nbr() << ", \"nparam2cols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = jacobian_params_second_derivatives.begin(); auto &gpp = params_derivatives.find({ 1, 2 })->second;
it != jacobian_params_second_derivatives.end(); ++it) for (auto it = gpp.begin(); it != gpp.end(); ++it)
{ {
if (it != jacobian_params_second_derivatives.begin()) if (it != gpp.begin())
third_derivs_output << ", "; third_derivs_output << ", ";
int eq, var, param1, param2; int eq, var, param1, param2;
tie(eq, var, param1, param2) = it->first; tie(eq, var, param1, param2) = vectorToTuple<4>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1; int var_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var)) + 1;
@ -3229,14 +3221,14 @@ StaticModel::writeJsonParamsDerivativesFile(ostream &output, bool writeDetails)
<< ", \"nvar2cols\": " << symbol_table.endo_nbr() << ", \"nvar2cols\": " << symbol_table.endo_nbr()
<< ", \"nparamcols\": " << symbol_table.param_nbr() << ", \"nparamcols\": " << symbol_table.param_nbr()
<< ", \"entries\": ["; << ", \"entries\": [";
for (auto it = hessian_params_derivatives.begin(); auto &hp = params_derivatives.find({ 2, 1 })->second;
it != hessian_params_derivatives.end(); ++it) for (auto it = hp.begin(); it != hp.end(); ++it)
{ {
if (it != hessian_params_derivatives.begin()) if (it != hp.begin())
third_derivs1_output << ", "; third_derivs1_output << ", ";
int eq, var1, var2, param; int eq, var1, var2, param;
tie(eq, var1, var2, param) = it->first; tie(eq, var1, var2, param) = vectorToTuple<4>(it->first);
expr_t d2 = it->second; expr_t d2 = it->second;
int var1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var1)) + 1; int var1_col = symbol_table.getTypeSpecificID(getSymbIDByDerivID(var1)) + 1;