2009-05-06 12:10:27 +02:00
|
|
|
|
/*
|
2023-12-07 18:34:38 +01:00
|
|
|
|
* Copyright © 2008-2023 Dynare Team
|
2009-05-19 10:57:07 +02:00
|
|
|
|
*
|
|
|
|
|
* This file is part of Dynare.
|
|
|
|
|
*
|
|
|
|
|
* Dynare is free software: you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* Dynare is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License
|
2021-06-09 17:33:48 +02:00
|
|
|
|
* along with Dynare. If not, see <https://www.gnu.org/licenses/>.
|
2009-05-19 10:57:07 +02:00
|
|
|
|
*/
|
2009-05-06 12:10:27 +02:00
|
|
|
|
|
|
|
|
|
// GP, based on work by O.Kamenik
|
|
|
|
|
|
2019-04-02 16:33:15 +02:00
|
|
|
|
#include "k_ord_dynare.hh"
|
2010-12-17 18:34:23 +01:00
|
|
|
|
#include "dynamic_abstract_class.hh"
|
2019-04-02 16:33:15 +02:00
|
|
|
|
#include "dynare_exception.hh"
|
2009-05-06 12:10:27 +02:00
|
|
|
|
|
2021-01-22 11:13:31 +01:00
|
|
|
|
#include <cassert>
|
2023-11-29 19:00:21 +01:00
|
|
|
|
#include <utility>
|
2009-05-06 12:10:27 +02:00
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::KordpDynare(const std::vector<std::string>& endo, const std::vector<std::string>& exo,
|
|
|
|
|
int nexog, int npar, Vector& ysteady, TwoDMatrix& vcov, Vector& inParams,
|
|
|
|
|
int nstat, int npred, int nforw, int nboth, const ConstVector& nnzd,
|
|
|
|
|
int nsteps, int norder, Journal& jr,
|
|
|
|
|
std::unique_ptr<DynamicModelAC> dynamicModelFile_arg,
|
|
|
|
|
const std::vector<int>& dr_order, const ConstTwoDMatrix& llincidence) :
|
|
|
|
|
nStat {nstat},
|
2023-11-30 14:37:05 +01:00
|
|
|
|
nBoth {nboth},
|
|
|
|
|
nPred {npred},
|
|
|
|
|
nForw {nforw},
|
|
|
|
|
nExog {nexog},
|
|
|
|
|
nPar {npar},
|
|
|
|
|
nYs {npred + nboth},
|
|
|
|
|
nYss {nboth + nforw},
|
|
|
|
|
nY {nstat + npred + nboth + nforw},
|
|
|
|
|
nJcols {nExog + nY + nYs + nYss},
|
|
|
|
|
NNZD {nnzd},
|
|
|
|
|
nSteps {nsteps},
|
|
|
|
|
nOrder {norder},
|
|
|
|
|
journal {jr},
|
|
|
|
|
ySteady {ysteady},
|
|
|
|
|
params {inParams},
|
|
|
|
|
vCov {vcov},
|
|
|
|
|
md {1},
|
|
|
|
|
dnl {endo},
|
|
|
|
|
denl {exo},
|
|
|
|
|
dsnl {*this, dnl, denl},
|
|
|
|
|
ll_Incidence {llincidence},
|
|
|
|
|
dynamicModelFile {std::move(dynamicModelFile_arg)}
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2019-04-10 09:23:32 +02:00
|
|
|
|
computeJacobianPermutation(dr_order);
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
void
|
2009-11-30 17:31:27 +01:00
|
|
|
|
KordpDynare::solveDeterministicSteady()
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
|
|
|
|
JournalRecordPair pa(journal);
|
2019-04-02 16:33:15 +02:00
|
|
|
|
pa << "Non-linear solver for deterministic steady state skipped" << endrec;
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::evaluateSystem(Vector& out, [[maybe_unused]] const ConstVector& yy,
|
|
|
|
|
[[maybe_unused]] const Vector& xx)
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
// This method is only called when checking the residuals at steady state (Approximation::check),
|
|
|
|
|
// so return zero residuals
|
2010-02-09 14:32:40 +01:00
|
|
|
|
out.zeros();
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::evaluateSystem(Vector& out, [[maybe_unused]] const ConstVector& yym,
|
|
|
|
|
[[maybe_unused]] const ConstVector& yy,
|
|
|
|
|
[[maybe_unused]] const ConstVector& yyp,
|
|
|
|
|
[[maybe_unused]] const Vector& xx)
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
// This method is only called when checking the residuals at steady state (Approximation::check),
|
|
|
|
|
// so return zero residuals
|
2010-02-09 14:32:40 +01:00
|
|
|
|
out.zeros();
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
2009-11-30 17:31:27 +01:00
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
void
|
2016-07-16 00:13:47 +02:00
|
|
|
|
KordpDynare::calcDerivativesAtSteady()
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2021-01-22 11:13:31 +01:00
|
|
|
|
assert(md.begin() == md.end());
|
|
|
|
|
|
|
|
|
|
std::vector<TwoDMatrix> dyn_md; // Model derivatives, in Dynare form
|
|
|
|
|
|
|
|
|
|
dyn_md.emplace_back(nY, nJcols); // Allocate Jacobian
|
|
|
|
|
dyn_md.back().zeros();
|
|
|
|
|
|
|
|
|
|
for (int i = 2; i <= nOrder; i++)
|
2009-11-29 21:50:39 +01:00
|
|
|
|
{
|
2021-01-22 11:13:31 +01:00
|
|
|
|
// Higher order derivatives, as sparse (3-column) matrices
|
2023-11-29 19:00:21 +01:00
|
|
|
|
dyn_md.emplace_back(static_cast<int>(NNZD[i - 1]), 3);
|
2019-04-10 18:56:14 +02:00
|
|
|
|
dyn_md.back().zeros();
|
2021-01-22 11:13:31 +01:00
|
|
|
|
}
|
2017-05-16 16:30:27 +02:00
|
|
|
|
|
2021-01-22 11:13:31 +01:00
|
|
|
|
Vector xx(nexog());
|
|
|
|
|
xx.zeros();
|
2012-07-07 21:21:28 +02:00
|
|
|
|
|
2021-01-22 11:13:31 +01:00
|
|
|
|
Vector out(nY);
|
|
|
|
|
out.zeros();
|
2023-11-29 19:00:21 +01:00
|
|
|
|
Vector llxSteady(nJcols - nExog);
|
2021-01-22 11:13:31 +01:00
|
|
|
|
LLxSteady(ySteady, llxSteady);
|
2017-05-16 16:30:27 +02:00
|
|
|
|
|
2021-01-22 11:13:31 +01:00
|
|
|
|
dynamicModelFile->eval(llxSteady, xx, params, ySteady, out, dyn_md);
|
2010-03-09 17:09:18 +01:00
|
|
|
|
|
2019-04-10 18:56:14 +02:00
|
|
|
|
for (int i = 1; i <= nOrder; i++)
|
2021-01-22 11:13:31 +01:00
|
|
|
|
populateDerivativesContainer(dyn_md, i);
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::populateDerivativesContainer(const std::vector<TwoDMatrix>& dyn_md, int ord)
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
const TwoDMatrix& g = dyn_md[ord - 1];
|
2019-04-10 18:56:14 +02:00
|
|
|
|
|
2009-05-27 16:28:23 +02:00
|
|
|
|
// model derivatives FSSparseTensor instance
|
2019-02-20 16:50:33 +01:00
|
|
|
|
auto mdTi = std::make_unique<FSSparseTensor>(ord, nJcols, nY);
|
2009-05-27 16:28:23 +02:00
|
|
|
|
|
2019-02-12 19:09:28 +01:00
|
|
|
|
IntSequence s(ord, 0);
|
2009-05-27 16:28:23 +02:00
|
|
|
|
|
2009-06-25 16:35:28 +02:00
|
|
|
|
if (ord == 1)
|
2019-03-07 18:17:43 +01:00
|
|
|
|
for (int i = 0; i < g.ncols(); i++)
|
|
|
|
|
{
|
|
|
|
|
for (int j = 0; j < g.nrows(); j++)
|
|
|
|
|
{
|
2019-04-02 16:33:15 +02:00
|
|
|
|
double x = g.get(j, dynppToDyn[s[0]]);
|
2019-03-07 18:17:43 +01:00
|
|
|
|
if (x != 0.0)
|
|
|
|
|
mdTi->insert(s, j, x);
|
|
|
|
|
}
|
|
|
|
|
s[0]++;
|
|
|
|
|
}
|
2019-04-12 18:12:21 +02:00
|
|
|
|
else // ord ≥ 2
|
|
|
|
|
for (int i = 0; i < g.nrows(); i++)
|
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
int j = static_cast<int>(g.get(i, 0)) - 1;
|
|
|
|
|
int i1 = static_cast<int>(g.get(i, 1)) - 1;
|
2019-04-12 18:12:21 +02:00
|
|
|
|
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 % nJcols];
|
|
|
|
|
i1 /= nJcols;
|
|
|
|
|
}
|
|
|
|
|
|
2019-06-17 16:17:49 +02:00
|
|
|
|
if (ord == 2 && !s.isSorted())
|
|
|
|
|
continue; // Skip symmetric elements (only needed at order 2)
|
|
|
|
|
else if (ord > 2)
|
2019-04-12 18:12:21 +02:00
|
|
|
|
s.sort(); // For higher order, canonicalize the multi-index
|
|
|
|
|
|
|
|
|
|
double x = g.get(i, 2);
|
|
|
|
|
mdTi->insert(s, j, x);
|
|
|
|
|
}
|
2009-11-30 17:31:27 +01:00
|
|
|
|
|
2019-02-20 16:50:33 +01:00
|
|
|
|
md.insert(std::move(mdTi));
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-02 16:33:15 +02:00
|
|
|
|
/* Returns ySteady extended with leads and lags suitable for passing to
|
|
|
|
|
<model>_dynamic */
|
2010-03-09 17:09:18 +01:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::LLxSteady(const Vector& yS, Vector& llxSteady)
|
2009-05-27 16:28:23 +02:00
|
|
|
|
{
|
2023-11-29 19:00:21 +01:00
|
|
|
|
if (yS.length() == nJcols - nExog)
|
2009-11-30 17:31:27 +01:00
|
|
|
|
throw DynareException(__FILE__, __LINE__, "ySteady already of right size");
|
|
|
|
|
|
2019-04-02 16:33:15 +02:00
|
|
|
|
/* Create temporary square 2D matrix size nEndo×nEndo (sparse)
|
|
|
|
|
for the lag, current and lead blocks of the jacobian */
|
2023-11-29 19:00:21 +01:00
|
|
|
|
if (llxSteady.length() != nJcols - nExog)
|
2010-03-09 17:09:18 +01:00
|
|
|
|
throw DynareException(__FILE__, __LINE__, "llxSteady has wrong size");
|
|
|
|
|
|
|
|
|
|
for (int ll_row = 0; ll_row < ll_Incidence.nrows(); ll_row++)
|
2019-03-07 18:17:43 +01:00
|
|
|
|
// populate (non-sparse) vector with ysteady values
|
|
|
|
|
for (int i = 0; i < nY; i++)
|
2019-04-02 16:33:15 +02:00
|
|
|
|
if (ll_Incidence.get(ll_row, i))
|
2023-11-29 19:00:21 +01:00
|
|
|
|
llxSteady[static_cast<int>(ll_Incidence.get(ll_row, i)) - 1] = yS[i];
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2019-04-10 09:23:32 +02:00
|
|
|
|
/*
|
|
|
|
|
Computes mapping between Dynare and Dynare++ orderings of the (dynamic)
|
|
|
|
|
variable indices in derivatives.
|
|
|
|
|
|
|
|
|
|
If one defines:
|
|
|
|
|
– y (resp. x) as the vector of all endogenous (size nY), in DR-order (resp.
|
|
|
|
|
declaration order)
|
|
|
|
|
– y⁻ (resp. x⁻) as the vector of endogenous that appear at previous period (size nYs),
|
|
|
|
|
in DR-order (resp. declaration order)
|
|
|
|
|
– y⁺ (resp. x⁺) as the vector of endogenous that appear at future period (size nYss) in
|
|
|
|
|
DR-order (resp. declaration order)
|
|
|
|
|
– u as the vector of exogenous (size nExog)
|
|
|
|
|
|
|
|
|
|
In Dynare, the ordering is (x⁻, x, x⁺, u).
|
|
|
|
|
In Dynare++, the ordering is (y⁺, y, y⁻, u).
|
|
|
|
|
|
2019-06-28 15:24:30 +02:00
|
|
|
|
dr_order is typically equal to oo_.dr.order_var.
|
2019-04-10 09:23:32 +02:00
|
|
|
|
*/
|
2010-03-09 17:09:18 +01:00
|
|
|
|
void
|
2023-11-29 19:00:21 +01:00
|
|
|
|
KordpDynare::computeJacobianPermutation(const std::vector<int>& dr_order)
|
2009-05-27 16:28:23 +02:00
|
|
|
|
{
|
2019-04-10 09:23:32 +02:00
|
|
|
|
// Compute restricted inverse DR-orderings: x⁻→y⁻ and x⁺→y⁺
|
2023-11-29 19:00:21 +01:00
|
|
|
|
std::vector<int> dr_inv_order_forw(nBoth + nForw), dr_inv_order_pred(nBoth + nPred);
|
2019-04-10 09:23:32 +02:00
|
|
|
|
std::iota(dr_inv_order_forw.begin(), dr_inv_order_forw.end(), 0);
|
2023-11-29 19:00:21 +01:00
|
|
|
|
std::sort(dr_inv_order_forw.begin(), dr_inv_order_forw.end(), [&](int i, int j) {
|
|
|
|
|
return dr_order[nStat + nPred + i] < dr_order[nStat + nPred + j];
|
|
|
|
|
});
|
2019-04-10 09:23:32 +02:00
|
|
|
|
std::iota(dr_inv_order_pred.begin(), dr_inv_order_pred.end(), 0);
|
|
|
|
|
std::sort(dr_inv_order_pred.begin(), dr_inv_order_pred.end(),
|
2023-11-29 19:00:21 +01:00
|
|
|
|
[&](int i, int j) { return dr_order[nStat + i] < dr_order[nStat + j]; });
|
2019-04-10 09:23:32 +02:00
|
|
|
|
|
|
|
|
|
// Compute restricted DR-orderings: y⁻→x⁻ and y⁺→x⁺
|
2023-11-29 19:00:21 +01:00
|
|
|
|
std::vector<int> dr_order_forw(nBoth + nForw), dr_order_pred(nBoth + nPred);
|
|
|
|
|
for (int i = 0; i < nBoth + nForw; i++)
|
2019-04-10 09:23:32 +02:00
|
|
|
|
dr_order_forw[dr_inv_order_forw[i]] = i;
|
2023-11-29 19:00:21 +01:00
|
|
|
|
for (int i = 0; i < nBoth + nPred; i++)
|
2019-04-10 09:23:32 +02:00
|
|
|
|
dr_order_pred[dr_inv_order_pred[i]] = i;
|
|
|
|
|
|
|
|
|
|
// Compute Dynare++ → Dynare ordering
|
2019-04-02 16:33:15 +02:00
|
|
|
|
dynppToDyn.resize(nJcols);
|
2019-04-10 09:23:32 +02:00
|
|
|
|
int j = 0;
|
|
|
|
|
for (; j < nYss; j++)
|
2023-11-29 19:00:21 +01:00
|
|
|
|
dynppToDyn[j] = dr_order_forw[j] + nYs + nY; // Forward variables
|
|
|
|
|
for (; j < nYss + nY; j++)
|
|
|
|
|
dynppToDyn[j] = dr_order[j - nYss] + nYs; // Variables in current period
|
|
|
|
|
for (; j < nYss + nY + nYs; j++)
|
|
|
|
|
dynppToDyn[j] = dr_order_pred[j - nY - nYss]; // Predetermined variables
|
2019-04-10 09:23:32 +02:00
|
|
|
|
for (; j < nJcols; j++)
|
|
|
|
|
dynppToDyn[j] = j; // Exogenous
|
|
|
|
|
|
|
|
|
|
// Compute Dynare → Dynare++ ordering
|
2019-04-02 16:33:15 +02:00
|
|
|
|
dynToDynpp.resize(nJcols);
|
|
|
|
|
for (int i = 0; i < nJcols; i++)
|
|
|
|
|
dynToDynpp[dynppToDyn[i]] = i;
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
DynareNameList::DynareNameList(std::vector<std::string> names_arg) : names(std::move(names_arg))
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-29 19:00:21 +01:00
|
|
|
|
DynareStateNameList::DynareStateNameList(const KordpDynare& dynare, const DynareNameList& dnl,
|
|
|
|
|
const DynareNameList& denl)
|
2009-05-06 12:10:27 +02:00
|
|
|
|
{
|
2019-04-02 16:33:15 +02:00
|
|
|
|
for (int i = 0; i < dynare.nYs; i++)
|
2023-12-07 18:34:38 +01:00
|
|
|
|
names.emplace_back(dnl.getName(i + dynare.nStat));
|
|
|
|
|
for (int i = 0; i < dynare.nExog; i++)
|
2019-03-06 18:40:19 +01:00
|
|
|
|
names.emplace_back(denl.getName(i));
|
2009-05-06 12:10:27 +02:00
|
|
|
|
}
|