k_order_welfare MEX: use the sparse representation of the static model
parent
0d9857e737
commit
6f2af6943f
|
@ -22,21 +22,19 @@
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
KordwDynare::KordwDynare(KordpDynare& m, ConstVector& NNZD_arg, Journal& jr, Vector& inParams,
|
KordwDynare::KordwDynare(KordpDynare& m, Journal& jr, Vector& inParams,
|
||||||
std::unique_ptr<ObjectiveMFile> objectiveFile_arg,
|
std::unique_ptr<ObjectiveMFile> objectiveFile_arg,
|
||||||
const std::vector<int>& dr_order) :
|
const std::vector<int>& dr_order) :
|
||||||
model {m},
|
model {m},
|
||||||
NNZD {NNZD_arg},
|
|
||||||
journal {jr},
|
journal {jr},
|
||||||
params {inParams},
|
params {inParams},
|
||||||
resid(1),
|
resid(1),
|
||||||
ud {1},
|
ud {1},
|
||||||
objectiveFile {std::move(objectiveFile_arg)}
|
objectiveFile {std::move(objectiveFile_arg)}
|
||||||
{
|
{
|
||||||
dynppToDyn = dr_order;
|
|
||||||
dynToDynpp.resize(model.ny());
|
dynToDynpp.resize(model.ny());
|
||||||
for (int i = 0; i < model.ny(); i++)
|
for (int i = 0; i < model.ny(); i++)
|
||||||
dynToDynpp[dynppToDyn[i]] = i;
|
dynToDynpp[dr_order[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -45,71 +43,10 @@ KordwDynare::calcDerivativesAtSteady()
|
||||||
|
|
||||||
assert(ud.begin() == ud.end());
|
assert(ud.begin() == ud.end());
|
||||||
|
|
||||||
std::vector<TwoDMatrix> dyn_ud; // Planner's objective derivatives, in Dynare form
|
|
||||||
dyn_ud.emplace_back(1, model.ny()); // Allocate Jacobian
|
|
||||||
dyn_ud.back().zeros();
|
|
||||||
|
|
||||||
for (int i = 2; i <= model.order(); i++)
|
|
||||||
{
|
|
||||||
// Higher order derivatives, as sparse (3-column) matrices
|
|
||||||
dyn_ud.emplace_back(static_cast<int>(NNZD[i - 1]), 3);
|
|
||||||
dyn_ud.back().zeros();
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector xx(model.nexog());
|
Vector xx(model.nexog());
|
||||||
xx.zeros();
|
xx.zeros();
|
||||||
resid.zeros();
|
resid.zeros();
|
||||||
objectiveFile->eval(model.getSteady(), xx, params, resid, dyn_ud);
|
objectiveFile->eval(model.getSteady(), xx, params, resid, dynToDynpp, ud);
|
||||||
|
|
||||||
for (int i = 1; i <= model.order(); i++)
|
|
||||||
populateDerivativesContainer(dyn_ud, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
KordwDynare::populateDerivativesContainer(const std::vector<TwoDMatrix>& dyn_ud, int ord)
|
|
||||||
{
|
|
||||||
const TwoDMatrix& u = dyn_ud[ord - 1];
|
|
||||||
|
|
||||||
// utility derivatives FSSparseTensor instance
|
|
||||||
auto udTi = std::make_unique<FSSparseTensor>(ord, model.ny(), 1);
|
|
||||||
|
|
||||||
IntSequence s(ord, 0);
|
|
||||||
|
|
||||||
if (ord == 1)
|
|
||||||
for (int i = 0; i < u.ncols(); i++)
|
|
||||||
{
|
|
||||||
for (int j = 0; j < u.nrows(); j++)
|
|
||||||
{
|
|
||||||
double x = u.get(j, dynppToDyn[s[0]]);
|
|
||||||
if (x != 0.0)
|
|
||||||
udTi->insert(s, j, x);
|
|
||||||
}
|
|
||||||
s[0]++;
|
|
||||||
}
|
|
||||||
else // ord ≥ 2
|
|
||||||
for (int i = 0; i < u.nrows(); i++)
|
|
||||||
{
|
|
||||||
int j = static_cast<int>(u.get(i, 0)) - 1;
|
|
||||||
int i1 = static_cast<int>(u.get(i, 1)) - 1;
|
|
||||||
if (j < 0 || i1 < 0)
|
|
||||||
continue; // Discard empty entries (see comment in DynamicModelAC::unpackSparseMatrix())
|
|
||||||
|
|
||||||
for (int k = 0; k < ord; k++)
|
|
||||||
{
|
|
||||||
s[k] = dynToDynpp[i1 % model.ny()];
|
|
||||||
i1 /= model.ny();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ord == 2 && !s.isSorted())
|
|
||||||
continue; // Skip symmetric elements (only needed at order 2)
|
|
||||||
else if (ord > 2)
|
|
||||||
s.sort(); // For higher order, canonicalize the multi-index
|
|
||||||
|
|
||||||
double x = u.get(i, 2);
|
|
||||||
udTi->insert(s, j, x);
|
|
||||||
}
|
|
||||||
|
|
||||||
ud.insert(std::move(udTi));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|
|
@ -29,22 +29,19 @@ class KordwDynare
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
KordpDynare& model;
|
KordpDynare& model;
|
||||||
const ConstVector& NNZD;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Journal& journal;
|
Journal& journal;
|
||||||
Vector& params;
|
Vector& params;
|
||||||
Vector resid;
|
Vector resid;
|
||||||
TensorContainer<FSSparseTensor> ud; // planner's objective derivatives, in Dynare++ form
|
TensorContainer<FSSparseTensor> ud; // planner's objective derivatives, in Dynare++ form
|
||||||
std::vector<int> dynppToDyn; // Maps Dynare++ jacobian variable indices to Dynare ones
|
|
||||||
std::vector<int> dynToDynpp; // Maps Dynare jacobian variable indices to Dynare++ ones
|
std::vector<int> dynToDynpp; // Maps Dynare jacobian variable indices to Dynare++ ones
|
||||||
std::unique_ptr<ObjectiveMFile> objectiveFile;
|
std::unique_ptr<ObjectiveMFile> objectiveFile;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KordwDynare(KordpDynare& m, ConstVector& NNZD_arg, Journal& jr, Vector& inParams,
|
KordwDynare(KordpDynare& m, Journal& jr, Vector& inParams,
|
||||||
std::unique_ptr<ObjectiveMFile> objectiveFile_arg, const std::vector<int>& varOrder);
|
std::unique_ptr<ObjectiveMFile> objectiveFile_arg, const std::vector<int>& varOrder);
|
||||||
void calcDerivativesAtSteady();
|
void calcDerivativesAtSteady();
|
||||||
void populateDerivativesContainer(const std::vector<TwoDMatrix>& dyn_ud, int ord);
|
|
||||||
[[nodiscard]] const TensorContainer<FSSparseTensor>&
|
[[nodiscard]] const TensorContainer<FSSparseTensor>&
|
||||||
getPlannerObjDerivatives() const
|
getPlannerObjDerivatives() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include "dynmex.h"
|
#include "dynmex.h"
|
||||||
|
|
||||||
|
@ -214,15 +215,6 @@ extern "C"
|
||||||
mexErrMsgTxt("The derivatives were not computed for the required order. Make sure that you "
|
mexErrMsgTxt("The derivatives were not computed for the required order. Make sure that you "
|
||||||
"used the right order option inside the `stoch_simul' command");
|
"used the right order option inside the `stoch_simul' command");
|
||||||
|
|
||||||
const mxArray* nnzderivatives_obj_mx = mxGetField(M_mx, 0, "NNZDerivatives_objective");
|
|
||||||
if (!(nnzderivatives_obj_mx && mxIsDouble(nnzderivatives_obj_mx)
|
|
||||||
&& !mxIsComplex(nnzderivatives_obj_mx) && !mxIsSparse(nnzderivatives_obj_mx)))
|
|
||||||
mexErrMsgTxt("M_.NNZDerivatives should be a real dense array");
|
|
||||||
ConstVector NNZD_obj {nnzderivatives_obj_mx};
|
|
||||||
if (NNZD.length() < kOrder || NNZD_obj[kOrder - 1] == -1)
|
|
||||||
mexErrMsgTxt("The derivatives were not computed for the required order. Make sure that you "
|
|
||||||
"used the right order option inside the `stoch_simul' command");
|
|
||||||
|
|
||||||
const mxArray* endo_names_mx = mxGetField(M_mx, 0, "endo_names");
|
const mxArray* endo_names_mx = mxGetField(M_mx, 0, "endo_names");
|
||||||
if (!(endo_names_mx && mxIsCell(endo_names_mx)
|
if (!(endo_names_mx && mxIsCell(endo_names_mx)
|
||||||
&& mxGetNumberOfElements(endo_names_mx) == static_cast<size_t>(nEndo)))
|
&& mxGetNumberOfElements(endo_names_mx) == static_cast<size_t>(nEndo)))
|
||||||
|
@ -261,6 +253,32 @@ extern "C"
|
||||||
std::transform(mxGetPr(order_var_mx), mxGetPr(order_var_mx) + nEndo, dr_order.begin(),
|
std::transform(mxGetPr(order_var_mx), mxGetPr(order_var_mx) + nEndo, dr_order.begin(),
|
||||||
[](double x) { return static_cast<int>(x) - 1; });
|
[](double x) { return static_cast<int>(x) - 1; });
|
||||||
|
|
||||||
|
const mxArray* objective_g1_sparse_rowval_mx
|
||||||
|
= mxGetField(M_mx, 0, "objective_g1_sparse_rowval");
|
||||||
|
if (!(objective_g1_sparse_rowval_mx && mxIsInt32(objective_g1_sparse_rowval_mx)))
|
||||||
|
mexErrMsgTxt("M_.objective_g1_sparse_rowval should be an int32 array");
|
||||||
|
|
||||||
|
const mxArray* objective_g1_sparse_colval_mx
|
||||||
|
= mxGetField(M_mx, 0, "objective_g1_sparse_colval");
|
||||||
|
if (!(objective_g1_sparse_colval_mx && mxIsInt32(objective_g1_sparse_colval_mx)))
|
||||||
|
mexErrMsgTxt("M_.objective_g1_sparse_colval should be an int32 array");
|
||||||
|
|
||||||
|
const mxArray* objective_g1_sparse_colptr_mx
|
||||||
|
= mxGetField(M_mx, 0, "objective_g1_sparse_colptr");
|
||||||
|
if (!(objective_g1_sparse_colptr_mx && mxIsInt32(objective_g1_sparse_colptr_mx)))
|
||||||
|
mexErrMsgTxt("M_.objective_g1_sparse_colptr should be an int32 array");
|
||||||
|
|
||||||
|
std::vector<const mxArray*> objective_gN_sparse_indices;
|
||||||
|
for (int o {2}; o <= kOrder; o++)
|
||||||
|
{
|
||||||
|
using namespace std::string_literals;
|
||||||
|
auto fieldname {"objective_g"s + std::to_string(o) + "_sparse_indices"};
|
||||||
|
const mxArray* indices = mxGetField(M_mx, 0, fieldname.c_str());
|
||||||
|
if (!(indices && mxIsInt32(indices)))
|
||||||
|
mexErrMsgTxt(("M_."s + fieldname + " should be an int32 array").c_str());
|
||||||
|
objective_gN_sparse_indices.push_back(indices);
|
||||||
|
}
|
||||||
|
|
||||||
const int nSteps
|
const int nSteps
|
||||||
= 0; // Dynare++ solving steps, for time being default to 0 = deterministic steady state
|
= 0; // Dynare++ solving steps, for time being default to 0 = deterministic steady state
|
||||||
|
|
||||||
|
@ -291,21 +309,14 @@ extern "C"
|
||||||
// run stochastic steady
|
// run stochastic steady
|
||||||
app.walkStochSteady();
|
app.walkStochSteady();
|
||||||
|
|
||||||
const mxArray* objective_tmp_nbr_mx = mxGetField(M_mx, 0, "objective_tmp_nbr");
|
|
||||||
if (!(objective_tmp_nbr_mx && mxIsDouble(objective_tmp_nbr_mx)
|
|
||||||
&& !mxIsComplex(objective_tmp_nbr_mx) && !mxIsSparse(objective_tmp_nbr_mx)
|
|
||||||
&& mxGetNumberOfElements(objective_tmp_nbr_mx) >= static_cast<size_t>(kOrder + 1)))
|
|
||||||
mexErrMsgTxt("M_.objective_tmp_nbr should be a real dense array with strictly more elements "
|
|
||||||
"than the order of derivation");
|
|
||||||
int ntt_objective = std::accumulate(mxGetPr(objective_tmp_nbr_mx),
|
|
||||||
mxGetPr(objective_tmp_nbr_mx) + kOrder + 1, 0);
|
|
||||||
|
|
||||||
// Getting derivatives of the planner's objective function
|
// Getting derivatives of the planner's objective function
|
||||||
std::unique_ptr<ObjectiveMFile> objectiveFile;
|
std::unique_ptr<ObjectiveMFile> objectiveFile;
|
||||||
objectiveFile = std::make_unique<ObjectiveMFile>(fname, ntt_objective);
|
objectiveFile = std::make_unique<ObjectiveMFile>(
|
||||||
|
fname, kOrder, objective_g1_sparse_rowval_mx, objective_g1_sparse_colval_mx,
|
||||||
|
objective_g1_sparse_colptr_mx, objective_gN_sparse_indices);
|
||||||
|
|
||||||
// make KordwDynare object
|
// make KordwDynare object
|
||||||
KordwDynare welfare(dynare, NNZD_obj, journal, modParams, std::move(objectiveFile), dr_order);
|
KordwDynare welfare(dynare, journal, modParams, std::move(objectiveFile), dr_order);
|
||||||
|
|
||||||
// construct main K-order approximation class of welfare
|
// construct main K-order approximation class of welfare
|
||||||
ApproximationWelfare appwel(welfare, discount_factor, app.get_rule_ders(),
|
ApproximationWelfare appwel(welfare, discount_factor, app.get_rule_ders(),
|
||||||
|
|
|
@ -26,88 +26,41 @@
|
||||||
|
|
||||||
#include "objective_m.hh"
|
#include "objective_m.hh"
|
||||||
|
|
||||||
ObjectiveMFile::ObjectiveMFile(const std::string& modName, int ntt_arg) :
|
ObjectiveMFile::ObjectiveMFile(const std::string& modName, int kOrder_arg,
|
||||||
ntt {ntt_arg}, ObjectiveMFilename {modName + ".objective.static"}
|
const mxArray* objective_g1_sparse_rowval_mx_arg,
|
||||||
|
const mxArray* objective_g1_sparse_colval_mx_arg,
|
||||||
|
const mxArray* objective_g1_sparse_colptr_mx_arg,
|
||||||
|
const std::vector<const mxArray*> objective_gN_sparse_indices_arg) :
|
||||||
|
ObjectiveMFilename {modName + ".objective.sparse.static"},
|
||||||
|
kOrder {kOrder_arg},
|
||||||
|
objective_g1_sparse_rowval_mx {objective_g1_sparse_rowval_mx_arg},
|
||||||
|
objective_g1_sparse_colval_mx {objective_g1_sparse_colval_mx_arg},
|
||||||
|
objective_g1_sparse_colptr_mx {objective_g1_sparse_colptr_mx_arg},
|
||||||
|
objective_gN_sparse_indices {objective_gN_sparse_indices_arg}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
ObjectiveMFile::unpackSparseMatrixAndCopyIntoTwoDMatData(mxArray* sparseMat, TwoDMatrix& tdm)
|
|
||||||
{
|
|
||||||
int totalCols = mxGetN(sparseMat);
|
|
||||||
mwIndex* rowIdxVector = mxGetIr(sparseMat);
|
|
||||||
mwIndex* colIdxVector = mxGetJc(sparseMat);
|
|
||||||
|
|
||||||
assert(tdm.ncols() == 3);
|
|
||||||
/* Under MATLAB, the following check always holds at equality; under Octave,
|
|
||||||
there may be an inequality, because Octave diminishes nzmax if one gives
|
|
||||||
zeros in the values vector when calling sparse(). */
|
|
||||||
assert(tdm.nrows() >= static_cast<int>(mxGetNzmax(sparseMat)));
|
|
||||||
|
|
||||||
double* ptr = mxGetPr(sparseMat);
|
|
||||||
|
|
||||||
int rind = 0;
|
|
||||||
int output_row = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < totalCols; i++)
|
|
||||||
for (int j = 0; j < static_cast<int>((colIdxVector[i + 1] - colIdxVector[i])); j++, rind++)
|
|
||||||
{
|
|
||||||
tdm.get(output_row, 0) = rowIdxVector[rind] + 1;
|
|
||||||
tdm.get(output_row, 1) = i + 1;
|
|
||||||
tdm.get(output_row, 2) = ptr[rind];
|
|
||||||
output_row++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there are less elements than expected (that might happen if some
|
|
||||||
derivative is symbolically not zero but numerically zero at the evaluation
|
|
||||||
point), then fill in the matrix with empty entries, that will be
|
|
||||||
recognized as such by KordpDynare::populateDerivativesContainer() */
|
|
||||||
while (output_row < tdm.nrows())
|
|
||||||
{
|
|
||||||
tdm.get(output_row, 0) = 0;
|
|
||||||
tdm.get(output_row, 1) = 0;
|
|
||||||
tdm.get(output_row, 2) = 0;
|
|
||||||
output_row++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
ObjectiveMFile::eval(const Vector& y, const Vector& x, const Vector& modParams, Vector& residual,
|
ObjectiveMFile::eval(const Vector& y, const Vector& x, const Vector& modParams, Vector& residual,
|
||||||
std::vector<TwoDMatrix>& md) noexcept(false)
|
const std::vector<int>& dynToDynpp,
|
||||||
|
TensorContainer<FSSparseTensor>& derivatives) const
|
||||||
{
|
{
|
||||||
mxArray* T_m = mxCreateDoubleMatrix(ntt, 1, mxREAL);
|
mxArray* y_mx = mxCreateDoubleMatrix(y.length(), 1, mxREAL);
|
||||||
|
std::copy_n(y.base(), y.length(), mxGetPr(y_mx));
|
||||||
|
|
||||||
mxArray* y_m = mxCreateDoubleMatrix(y.length(), 1, mxREAL);
|
mxArray* x_mx = mxCreateDoubleMatrix(1, x.length(), mxREAL);
|
||||||
std::copy_n(y.base(), y.length(), mxGetPr(y_m));
|
std::copy_n(x.base(), x.length(), mxGetPr(x_mx));
|
||||||
|
|
||||||
mxArray* x_m = mxCreateDoubleMatrix(1, x.length(), mxREAL);
|
mxArray* params_mx = mxCreateDoubleMatrix(modParams.length(), 1, mxREAL);
|
||||||
std::copy_n(x.base(), x.length(), mxGetPr(x_m));
|
std::copy_n(modParams.base(), modParams.length(), mxGetPr(params_mx));
|
||||||
|
|
||||||
mxArray* params_m = mxCreateDoubleMatrix(modParams.length(), 1, mxREAL);
|
mxArray *T_order_mx, *T_mx;
|
||||||
std::copy_n(modParams.base(), modParams.length(), mxGetPr(params_m));
|
|
||||||
|
|
||||||
mxArray* T_flag_m = mxCreateLogicalScalar(false);
|
|
||||||
|
|
||||||
{
|
|
||||||
// Compute temporary terms (for all orders)
|
|
||||||
std::string funcname = ObjectiveMFilename + "_g" + std::to_string(md.size()) + "_tt";
|
|
||||||
std::array<mxArray*, 1> plhs;
|
|
||||||
std::array prhs {T_m, y_m, x_m, params_m};
|
|
||||||
|
|
||||||
int retVal
|
|
||||||
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
|
||||||
if (retVal != 0)
|
|
||||||
throw DynareException(__FILE__, __LINE__, "Trouble calling " + funcname);
|
|
||||||
|
|
||||||
mxDestroyArray(T_m);
|
|
||||||
T_m = plhs[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{
|
||||||
// Compute residuals
|
// Compute residuals
|
||||||
std::string funcname = ObjectiveMFilename + "_resid";
|
std::string funcname = ObjectiveMFilename + "_resid";
|
||||||
std::array<mxArray*, 1> plhs;
|
std::array<mxArray*, 3> plhs;
|
||||||
std::array prhs {T_m, y_m, x_m, params_m, T_flag_m};
|
std::array prhs {y_mx, x_mx, params_mx};
|
||||||
|
|
||||||
int retVal
|
int retVal
|
||||||
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
||||||
|
@ -116,35 +69,103 @@ ObjectiveMFile::eval(const Vector& y, const Vector& x, const Vector& modParams,
|
||||||
|
|
||||||
residual = Vector {plhs[0]};
|
residual = Vector {plhs[0]};
|
||||||
mxDestroyArray(plhs[0]);
|
mxDestroyArray(plhs[0]);
|
||||||
|
|
||||||
|
T_order_mx = plhs[1];
|
||||||
|
T_mx = plhs[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
for (size_t i = 1; i <= md.size(); i++)
|
{
|
||||||
|
// Compute Jacobian
|
||||||
|
std::string funcname = ObjectiveMFilename + "_g1";
|
||||||
|
std::array<mxArray*, 3> plhs;
|
||||||
|
std::array prhs {y_mx,
|
||||||
|
x_mx,
|
||||||
|
params_mx,
|
||||||
|
const_cast<mxArray*>(objective_g1_sparse_rowval_mx),
|
||||||
|
const_cast<mxArray*>(objective_g1_sparse_colval_mx),
|
||||||
|
const_cast<mxArray*>(objective_g1_sparse_colptr_mx),
|
||||||
|
T_order_mx,
|
||||||
|
T_mx};
|
||||||
|
|
||||||
|
int retVal
|
||||||
|
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
||||||
|
if (retVal != 0)
|
||||||
|
throw DynareException(__FILE__, __LINE__, "Trouble calling " + funcname);
|
||||||
|
|
||||||
|
assert(static_cast<int>(mxGetN(plhs[0])) == y.length());
|
||||||
|
double* g1_v {mxGetPr(plhs[0])};
|
||||||
|
mwIndex* g1_ir {mxGetIr(plhs[0])};
|
||||||
|
mwIndex* g1_jc {mxGetJc(plhs[0])};
|
||||||
|
|
||||||
|
IntSequence s(1, 0);
|
||||||
|
auto tensor = std::make_unique<FSSparseTensor>(1, y.length(), 1);
|
||||||
|
|
||||||
|
for (int j {0}; j < y.length(); j++)
|
||||||
|
for (mwIndex k {g1_jc[j]}; k < g1_jc[j + 1]; k++)
|
||||||
|
{
|
||||||
|
s[0] = dynToDynpp[j];
|
||||||
|
tensor->insert(s, g1_ir[k], g1_v[k]);
|
||||||
|
}
|
||||||
|
|
||||||
|
mxDestroyArray(plhs[0]);
|
||||||
|
|
||||||
|
mxDestroyArray(T_order_mx);
|
||||||
|
T_order_mx = plhs[1];
|
||||||
|
|
||||||
|
mxDestroyArray(T_mx);
|
||||||
|
T_mx = plhs[2];
|
||||||
|
|
||||||
|
derivatives.insert(std::move(tensor));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int o {2}; o <= kOrder; o++)
|
||||||
{
|
{
|
||||||
// Compute model derivatives
|
// Compute higher derivatives
|
||||||
std::string funcname = ObjectiveMFilename + "_g" + std::to_string(i);
|
std::string funcname = ObjectiveMFilename + "_g" + std::to_string(o);
|
||||||
std::array<mxArray*, 1> plhs;
|
std::array<mxArray*, 3> plhs;
|
||||||
std::array prhs {T_m, y_m, x_m, params_m, T_flag_m};
|
std::array prhs {y_mx, x_mx, params_mx, T_order_mx, T_mx};
|
||||||
|
|
||||||
int retVal
|
int retVal
|
||||||
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
= mexCallMATLAB(plhs.size(), plhs.data(), prhs.size(), prhs.data(), funcname.c_str());
|
||||||
if (retVal != 0)
|
if (retVal != 0)
|
||||||
throw DynareException(__FILE__, __LINE__, "Trouble calling " + funcname);
|
throw DynareException(__FILE__, __LINE__, "Trouble calling " + funcname);
|
||||||
|
|
||||||
if (i == 1)
|
const mxArray* sparse_indices_mx {objective_gN_sparse_indices[o - 2]};
|
||||||
|
size_t nnz {mxGetM(sparse_indices_mx)};
|
||||||
|
#if MX_HAS_INTERLEAVED_COMPLEX
|
||||||
|
const int32_T* sparse_indices {mxGetInt32s(sparse_indices_mx)};
|
||||||
|
#else
|
||||||
|
const int32_T* sparse_indices {static_cast<const int32_T*>(mxGetData(sparse_indices_mx))};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
assert(mxGetNumberOfElements(plhs[0]) == nnz);
|
||||||
|
double* gN_v {mxGetPr(plhs[0])};
|
||||||
|
|
||||||
|
IntSequence s(o, 0);
|
||||||
|
auto tensor = std::make_unique<FSSparseTensor>(o, y.length(), 1);
|
||||||
|
|
||||||
|
for (size_t k {0}; k < nnz; k++)
|
||||||
{
|
{
|
||||||
assert(static_cast<int>(mxGetM(plhs[0])) == md[i - 1].nrows());
|
for (int i {0}; i < o; i++)
|
||||||
assert(static_cast<int>(mxGetN(plhs[0])) == md[i - 1].ncols());
|
s[i] = dynToDynpp[sparse_indices[k + (i + 1) * nnz] - 1];
|
||||||
std::copy_n(mxGetPr(plhs[0]), mxGetM(plhs[0]) * mxGetN(plhs[0]), md[i - 1].base());
|
assert(s.isSorted());
|
||||||
|
tensor->insert(s, sparse_indices[k] - 1, gN_v[k]);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
unpackSparseMatrixAndCopyIntoTwoDMatData(plhs[0], md[i - 1]);
|
|
||||||
|
|
||||||
mxDestroyArray(plhs[0]);
|
mxDestroyArray(plhs[0]);
|
||||||
|
|
||||||
|
mxDestroyArray(T_order_mx);
|
||||||
|
T_order_mx = plhs[1];
|
||||||
|
|
||||||
|
mxDestroyArray(T_mx);
|
||||||
|
T_mx = plhs[2];
|
||||||
|
|
||||||
|
derivatives.insert(std::move(tensor));
|
||||||
}
|
}
|
||||||
|
|
||||||
mxDestroyArray(T_m);
|
mxDestroyArray(y_mx);
|
||||||
mxDestroyArray(y_m);
|
mxDestroyArray(x_mx);
|
||||||
mxDestroyArray(x_m);
|
mxDestroyArray(params_mx);
|
||||||
mxDestroyArray(params_m);
|
mxDestroyArray(T_order_mx);
|
||||||
mxDestroyArray(T_flag_m);
|
mxDestroyArray(T_mx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,21 +22,32 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <dynmex.h>
|
#include "dynmex.h"
|
||||||
|
|
||||||
#include "twod_matrix.hh"
|
#include "Vector.hh"
|
||||||
|
#include "sparse_tensor.hh"
|
||||||
|
#include "t_container.hh"
|
||||||
|
|
||||||
// Handles calls to <model>/+objective/static.m
|
// Handles calls to <model>/+objective/+sparse/static*.m
|
||||||
class ObjectiveMFile
|
class ObjectiveMFile
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
int ntt; // Size of vector of temporary terms
|
|
||||||
const std::string ObjectiveMFilename;
|
const std::string ObjectiveMFilename;
|
||||||
static void unpackSparseMatrixAndCopyIntoTwoDMatData(mxArray* sparseMat, TwoDMatrix& tdm);
|
const int kOrder;
|
||||||
|
const mxArray *const objective_g1_sparse_rowval_mx, *const objective_g1_sparse_colval_mx,
|
||||||
|
*const objective_g1_sparse_colptr_mx;
|
||||||
|
// Stores M_.objective_gN_sparse_indices, starting from N=2
|
||||||
|
const std::vector<const mxArray*> objective_gN_sparse_indices;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ObjectiveMFile(const std::string& modName, int ntt_arg);
|
ObjectiveMFile(const std::string& modName, int kOrder_arg,
|
||||||
|
const mxArray* objective_g1_sparse_rowval_mx_arg,
|
||||||
|
const mxArray* objective_g1_sparse_colval_mx_arg,
|
||||||
|
const mxArray* objective_g1_sparse_colptr_mx_arg,
|
||||||
|
const std::vector<const mxArray*> objective_gN_sparse_indices_arg);
|
||||||
void eval(const Vector& y, const Vector& x, const Vector& params, Vector& residual,
|
void eval(const Vector& y, const Vector& x, const Vector& params, Vector& residual,
|
||||||
std::vector<TwoDMatrix>& md);
|
const std::vector<int>& dynToDynpp, TensorContainer<FSSparseTensor>& derivatives) const
|
||||||
|
noexcept(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue