2019-06-19 14:34:30 +02:00
|
|
|
/*
|
|
|
|
* Copyright © 2004 Ondra Kamenik
|
|
|
|
* Copyright © 2019 Dynare Team
|
|
|
|
*
|
|
|
|
* 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
|
|
|
|
* along with Dynare. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2019-01-04 16:29:57 +01:00
|
|
|
|
|
|
|
#include "kord_exception.hh"
|
|
|
|
#include "decision_rule.hh"
|
|
|
|
#include "dynamic_model.hh"
|
2019-03-05 12:29:17 +01:00
|
|
|
#include "seed_generator.hh"
|
2019-01-04 16:29:57 +01:00
|
|
|
|
2019-01-08 17:12:05 +01:00
|
|
|
#include "SymSchurDecomp.hh"
|
2019-01-04 16:29:57 +01:00
|
|
|
|
|
|
|
#include <dynlapack.h>
|
|
|
|
|
|
|
|
#include <limits>
|
2019-01-09 15:46:04 +01:00
|
|
|
#include <utility>
|
2019-01-14 12:19:00 +01:00
|
|
|
#include <memory>
|
2019-01-04 16:29:57 +01:00
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
// FoldDecisionRule conversion from UnfoldDecisionRule
|
2019-01-04 16:29:57 +01:00
|
|
|
FoldDecisionRule::FoldDecisionRule(const UnfoldDecisionRule &udr)
|
2019-03-06 18:40:19 +01:00
|
|
|
: DecisionRuleImpl<Storage::fold>(ctraits<Storage::fold>::Tpol(udr.nrows(), udr.nvars()),
|
2019-12-20 14:36:20 +01:00
|
|
|
udr.ypart, udr.nu, udr.ysteady)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &it : udr)
|
2019-03-06 18:40:19 +01:00
|
|
|
insert(std::make_unique<ctraits<Storage::fold>::Ttensym>(*(it.second)));
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
// UnfoldDecisionRule conversion from FoldDecisionRule
|
2019-01-04 16:29:57 +01:00
|
|
|
UnfoldDecisionRule::UnfoldDecisionRule(const FoldDecisionRule &fdr)
|
2019-03-06 18:40:19 +01:00
|
|
|
: DecisionRuleImpl<Storage::unfold>(ctraits<Storage::unfold>::Tpol(fdr.nrows(), fdr.nvars()),
|
2019-12-20 14:36:20 +01:00
|
|
|
fdr.ypart, fdr.nu, fdr.ysteady)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &it : fdr)
|
2019-03-06 18:40:19 +01:00
|
|
|
insert(std::make_unique<ctraits<Storage::unfold>::Ttensym>(*(it.second)));
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* This runs simulations with an output to journal file. Note that we
|
|
|
|
report how many simulations had to be thrown out due to Nan or Inf. */
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResults::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
|
|
|
|
const TwoDMatrix &vcov, Journal &journal)
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Performing " << num_sim << " stochastic simulations for "
|
|
|
|
<< num_per << " periods burning " << num_burn << " initial periods" << endrec;
|
|
|
|
simulate(num_sim, dr, start, vcov);
|
|
|
|
int thrown = num_sim - data.size();
|
|
|
|
if (thrown > 0)
|
|
|
|
{
|
|
|
|
JournalRecord rec(journal);
|
|
|
|
rec << "I had to throw " << thrown << " simulations away due to Nan or Inf" << endrec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This runs a given number of simulations by creating
|
2019-05-10 18:41:23 +02:00
|
|
|
SimulationWorker for each simulation and inserting them to the
|
2019-01-04 16:29:57 +01:00
|
|
|
thread group. */
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResults::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
|
|
|
|
const TwoDMatrix &vcov)
|
|
|
|
{
|
|
|
|
std::vector<RandomShockRealization> rsrs;
|
|
|
|
rsrs.reserve(num_sim);
|
|
|
|
|
2019-01-28 18:39:42 +01:00
|
|
|
sthread::detach_thread_group gr;
|
2019-01-04 16:29:57 +01:00
|
|
|
for (int i = 0; i < num_sim; i++)
|
|
|
|
{
|
2019-03-05 12:29:17 +01:00
|
|
|
RandomShockRealization sr(vcov, seed_generator::get_new_seed());
|
2019-01-04 16:29:57 +01:00
|
|
|
rsrs.push_back(sr);
|
2019-03-05 18:35:35 +01:00
|
|
|
gr.insert(std::make_unique<SimulationWorker>(*this, dr, DecisionRule::emethod::horner,
|
2019-01-14 12:19:00 +01:00
|
|
|
num_per+num_burn, start, rsrs.back()));
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
gr.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This adds the data with the realized shocks. It takes only periods
|
|
|
|
which are not to be burnt. If the data is not finite, the both data
|
|
|
|
and shocks are thrown away. */
|
|
|
|
|
|
|
|
bool
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResults::addDataSet(const TwoDMatrix &d, const ExplicitShockRealization &sr, const ConstVector &st)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
KORD_RAISE_IF(d.nrows() != num_y,
|
2019-01-04 16:29:57 +01:00
|
|
|
"Incompatible number of rows for SimResults::addDataSets");
|
2019-03-05 18:35:35 +01:00
|
|
|
KORD_RAISE_IF(d.ncols() != num_per+num_burn,
|
2019-01-04 16:29:57 +01:00
|
|
|
"Incompatible number of cols for SimResults::addDataSets");
|
|
|
|
bool ret = false;
|
2019-03-05 18:35:35 +01:00
|
|
|
if (d.isFinite())
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
data.emplace_back(d, num_burn, num_per);
|
|
|
|
shocks.emplace_back(ConstTwoDMatrix(sr.getShocks(), num_burn, num_per));
|
2019-02-05 17:14:59 +01:00
|
|
|
if (num_burn == 0)
|
|
|
|
start.emplace_back(st);
|
|
|
|
else
|
2019-03-05 18:35:35 +01:00
|
|
|
start.emplace_back(d.getCol(num_burn-1));
|
2019-01-04 16:29:57 +01:00
|
|
|
ret = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResults::writeMat(const std::string &base, const std::string &lname) const
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
std::string matfile_name = base + ".mat";
|
|
|
|
mat_t *matfd = Mat_Create(matfile_name.c_str(), nullptr);
|
|
|
|
if (matfd)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-04-24 14:52:30 +02:00
|
|
|
writeMat(matfd, lname);
|
2019-01-04 16:29:57 +01:00
|
|
|
Mat_Close(matfd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This save the results as matrices with given prefix and with index
|
|
|
|
appended. If there is only one matrix, the index is not appended. */
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResults::writeMat(mat_t *fd, const std::string &lname) const
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
for (int i = 0; i < getNumSets(); i++)
|
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
std::string tmp = lname + "_data";
|
2019-01-04 16:29:57 +01:00
|
|
|
if (getNumSets() > 1)
|
2019-03-05 18:35:35 +01:00
|
|
|
tmp += std::to_string(i+1);
|
|
|
|
data[i].writeMat(fd, tmp);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsStats::simulate(int num_sim, const DecisionRule &dr,
|
|
|
|
const Vector &start,
|
|
|
|
const TwoDMatrix &vcov, Journal &journal)
|
|
|
|
{
|
|
|
|
SimResults::simulate(num_sim, dr, start, vcov, journal);
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Calculating means from the simulations." << endrec;
|
|
|
|
calcMean();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Calculating covariances from the simulations." << endrec;
|
|
|
|
calcVcov();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Here we do not save the data itself, we save only mean and vcov. */
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResultsStats::writeMat(mat_t *fd, const std::string &lname) const
|
|
|
|
{
|
|
|
|
ConstTwoDMatrix(num_y, 1, mean).writeMat(fd, lname + "_mean");;
|
|
|
|
vcov.writeMat(fd, lname + "_vcov");
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsStats::calcMean()
|
|
|
|
{
|
|
|
|
mean.zeros();
|
|
|
|
if (data.size()*num_per > 0)
|
|
|
|
{
|
|
|
|
double mult = 1.0/data.size()/num_per;
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &i : data)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
for (int j = 0; j < num_per; j++)
|
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
ConstVector col{i.getCol(j)};
|
2019-01-04 16:29:57 +01:00
|
|
|
mean.add(mult, col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsStats::calcVcov()
|
|
|
|
{
|
|
|
|
if (data.size()*num_per > 1)
|
|
|
|
{
|
|
|
|
vcov.zeros();
|
|
|
|
double mult = 1.0/(data.size()*num_per - 1);
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &d : data)
|
|
|
|
for (int j = 0; j < num_per; j++)
|
|
|
|
for (int m = 0; m < num_y; m++)
|
|
|
|
for (int n = m; n < num_y; n++)
|
|
|
|
{
|
|
|
|
double s = (d.get(m, j)-mean[m])*(d.get(n, j)-mean[n]);
|
|
|
|
vcov.get(m, n) += mult*s;
|
|
|
|
if (m != n)
|
|
|
|
vcov.get(n, m) += mult*s;
|
|
|
|
}
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
else
|
2019-03-05 18:35:35 +01:00
|
|
|
vcov.infs();
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsDynamicStats::simulate(int num_sim, const DecisionRule &dr,
|
|
|
|
const Vector &start,
|
|
|
|
const TwoDMatrix &vcov, Journal &journal)
|
|
|
|
{
|
|
|
|
SimResults::simulate(num_sim, dr, start, vcov, journal);
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Calculating means of the conditional simulations." << endrec;
|
|
|
|
calcMean();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Calculating variances of the conditional simulations." << endrec;
|
|
|
|
calcVariance();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResultsDynamicStats::writeMat(mat_t *fd, const std::string &lname) const
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
mean.writeMat(fd, lname + "_cond_mean");
|
|
|
|
variance.writeMat(fd, lname + "_cond_variance");
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsDynamicStats::calcMean()
|
|
|
|
{
|
|
|
|
mean.zeros();
|
|
|
|
if (data.size() > 0)
|
|
|
|
{
|
|
|
|
double mult = 1.0/data.size();
|
|
|
|
for (int j = 0; j < num_per; j++)
|
|
|
|
{
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
Vector meanj{mean.getCol(j)};
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &i : data)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
ConstVector col{i.getCol(j)};
|
2019-01-04 16:29:57 +01:00
|
|
|
meanj.add(mult, col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsDynamicStats::calcVariance()
|
|
|
|
{
|
|
|
|
if (data.size() > 1)
|
|
|
|
{
|
|
|
|
variance.zeros();
|
|
|
|
double mult = 1.0/(data.size()-1);
|
|
|
|
for (int j = 0; j < num_per; j++)
|
|
|
|
{
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
ConstVector meanj{mean.getCol(j)};
|
|
|
|
Vector varj{variance.getCol(j)};
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &i : data)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
Vector col{i.getCol(j)};
|
2019-01-04 16:29:57 +01:00
|
|
|
col.add(-1.0, meanj);
|
|
|
|
for (int k = 0; k < col.length(); k++)
|
|
|
|
col[k] = col[k]*col[k];
|
|
|
|
varj.add(mult, col);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-03-05 18:35:35 +01:00
|
|
|
variance.infs();
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsIRF::simulate(const DecisionRule &dr, Journal &journal)
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Performing " << control.getNumSets() << " IRF simulations for "
|
|
|
|
<< num_per << " periods; shock=" << ishock << ", impulse=" << imp << endrec;
|
|
|
|
simulate(dr);
|
|
|
|
int thrown = control.getNumSets() - data.size();
|
|
|
|
if (thrown > 0)
|
|
|
|
{
|
|
|
|
JournalRecord rec(journal);
|
|
|
|
rec << "I had to throw " << thrown
|
|
|
|
<< " simulations away due to Nan or Inf" << endrec;
|
|
|
|
}
|
|
|
|
calcMeans();
|
|
|
|
calcVariances();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsIRF::simulate(const DecisionRule &dr)
|
|
|
|
{
|
2019-01-28 18:39:42 +01:00
|
|
|
sthread::detach_thread_group gr;
|
2019-01-04 16:29:57 +01:00
|
|
|
for (int idata = 0; idata < control.getNumSets(); idata++)
|
2019-03-05 18:35:35 +01:00
|
|
|
gr.insert(std::make_unique<SimulationIRFWorker>(*this, dr, DecisionRule::emethod::horner,
|
2019-01-14 12:19:00 +01:00
|
|
|
num_per, idata, ishock, imp));
|
2019-01-04 16:29:57 +01:00
|
|
|
gr.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsIRF::calcMeans()
|
|
|
|
{
|
|
|
|
means.zeros();
|
|
|
|
if (data.size() > 0)
|
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &i : data)
|
|
|
|
means.add(1.0, i);
|
2019-01-04 16:29:57 +01:00
|
|
|
means.mult(1.0/data.size());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
SimResultsIRF::calcVariances()
|
|
|
|
{
|
|
|
|
if (data.size() > 1)
|
|
|
|
{
|
|
|
|
variances.zeros();
|
2019-03-05 18:35:35 +01:00
|
|
|
for (const auto &i : data)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
TwoDMatrix d(i);
|
2019-01-04 16:29:57 +01:00
|
|
|
d.add(-1.0, means);
|
|
|
|
for (int j = 0; j < d.nrows(); j++)
|
|
|
|
for (int k = 0; k < d.ncols(); k++)
|
|
|
|
variances.get(j, k) += d.get(j, k)*d.get(j, k);
|
|
|
|
d.mult(1.0/(data.size()-1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2019-03-05 18:35:35 +01:00
|
|
|
variances.infs();
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
SimResultsIRF::writeMat(mat_t *fd, const std::string &lname) const
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
means.writeMat(fd, lname + "_mean");
|
|
|
|
variances.writeMat(fd, lname + "_var");
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RTSimResultsStats::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
|
|
|
|
const TwoDMatrix &v, Journal &journal)
|
|
|
|
{
|
|
|
|
JournalRecordPair paa(journal);
|
|
|
|
paa << "Performing " << num_sim << " real-time stochastic simulations for "
|
|
|
|
<< num_per << " periods" << endrec;
|
|
|
|
simulate(num_sim, dr, start, v);
|
|
|
|
mean = nc.getMean();
|
|
|
|
mean.add(1.0, dr.getSteady());
|
|
|
|
nc.getVariance(vcov);
|
|
|
|
if (thrown_periods > 0)
|
|
|
|
{
|
|
|
|
JournalRecord rec(journal);
|
|
|
|
rec << "I had to throw " << thrown_periods << " periods away due to Nan or Inf" << endrec;
|
|
|
|
JournalRecord rec1(journal);
|
|
|
|
rec1 << "This affected " << incomplete_simulations << " out of "
|
|
|
|
<< num_sim << " simulations" << endrec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RTSimResultsStats::simulate(int num_sim, const DecisionRule &dr, const Vector &start,
|
|
|
|
const TwoDMatrix &vcov)
|
|
|
|
{
|
|
|
|
std::vector<RandomShockRealization> rsrs;
|
|
|
|
rsrs.reserve(num_sim);
|
|
|
|
|
2019-01-28 18:39:42 +01:00
|
|
|
sthread::detach_thread_group gr;
|
2019-01-04 16:29:57 +01:00
|
|
|
for (int i = 0; i < num_sim; i++)
|
|
|
|
{
|
2019-03-05 12:29:17 +01:00
|
|
|
RandomShockRealization sr(vcov, seed_generator::get_new_seed());
|
2019-01-04 16:29:57 +01:00
|
|
|
rsrs.push_back(sr);
|
2019-03-05 18:35:35 +01:00
|
|
|
gr.insert(std::make_unique<RTSimulationWorker>(*this, dr, DecisionRule::emethod::horner,
|
2019-01-14 12:19:00 +01:00
|
|
|
num_per, start, rsrs.back()));
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
gr.run();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
RTSimResultsStats::writeMat(mat_t *fd, const std::string &lname)
|
|
|
|
{
|
|
|
|
ConstTwoDMatrix(nc.getDim(), 1, mean).writeMat(fd, lname + "_rt_mean");
|
|
|
|
vcov.writeMat(fd, lname + "_rt_vcov");
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
IRFResults::IRFResults(const DynamicModel &mod, const DecisionRule &dr,
|
2019-02-06 15:50:01 +01:00
|
|
|
const SimResults &control, std::vector<int> ili,
|
2019-01-04 16:29:57 +01:00
|
|
|
Journal &journal)
|
2019-01-09 15:46:04 +01:00
|
|
|
: model(mod), irf_list_ind(std::move(ili))
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
int num_per = control.getNumPer();
|
|
|
|
JournalRecordPair pa(journal);
|
2019-03-05 18:35:35 +01:00
|
|
|
pa << "Calculating IRFs against control for " << static_cast<int>(irf_list_ind.size()) << " shocks and for "
|
2019-01-04 16:29:57 +01:00
|
|
|
<< num_per << " periods" << endrec;
|
|
|
|
const TwoDMatrix &vcov = mod.getVcov();
|
2019-01-09 15:44:26 +01:00
|
|
|
for (int ishock : irf_list_ind)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
double stderror = sqrt(vcov.get(ishock, ishock));
|
2019-03-05 18:35:35 +01:00
|
|
|
irf_res.emplace_back(control, model.numeq(), num_per,
|
|
|
|
ishock, stderror);
|
|
|
|
irf_res.emplace_back(control, model.numeq(), num_per,
|
|
|
|
ishock, -stderror);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned int ii = 0; ii < irf_list_ind.size(); ii++)
|
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
irf_res[2*ii].simulate(dr, journal);
|
|
|
|
irf_res[2*ii+1].simulate(dr, journal);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-03-05 18:35:35 +01:00
|
|
|
IRFResults::writeMat(mat_t *fd, const std::string &prefix) const
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
for (unsigned int i = 0; i < irf_list_ind.size(); i++)
|
|
|
|
{
|
|
|
|
int ishock = irf_list_ind[i];
|
2019-03-05 18:35:35 +01:00
|
|
|
auto shockname = model.getExogNames().getName(ishock);
|
|
|
|
irf_res[2*i].writeMat(fd, prefix + "_irfp_" + shockname);
|
|
|
|
irf_res[2*i+1].writeMat(fd, prefix + "_irfm_" + shockname);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-01-29 15:52:56 +01:00
|
|
|
SimulationWorker::operator()(std::mutex &mut)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
ExplicitShockRealization esr(sr, np);
|
|
|
|
TwoDMatrix m{dr.simulate(em, np, st, esr)};
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-01-29 15:52:56 +01:00
|
|
|
std::unique_lock<std::mutex> lk{mut};
|
2019-02-05 17:14:59 +01:00
|
|
|
res.addDataSet(m, esr, st);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
/* Here we create a new instance of ExplicitShockRealization of the
|
2019-01-04 16:29:57 +01:00
|
|
|
corresponding control, add the impulse, and simulate. */
|
|
|
|
|
|
|
|
void
|
2019-01-29 15:52:56 +01:00
|
|
|
SimulationIRFWorker::operator()(std::mutex &mut)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
ExplicitShockRealization esr(res.control.getShocks(idata));
|
|
|
|
esr.addToShock(ishock, 0, imp);
|
|
|
|
TwoDMatrix m{dr.simulate(em, np, res.control.getStart(idata), esr)};
|
|
|
|
m.add(-1.0, res.control.getData(idata));
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-01-29 15:52:56 +01:00
|
|
|
std::unique_lock<std::mutex> lk{mut};
|
2019-02-05 17:14:59 +01:00
|
|
|
res.addDataSet(m, esr, res.control.getStart(idata));
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2019-01-29 15:52:56 +01:00
|
|
|
RTSimulationWorker::operator()(std::mutex &mut)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
NormalConj nc(res.nc.getDim());
|
|
|
|
const PartitionY &ypart = dr.getYPart();
|
|
|
|
int nu = dr.nexog();
|
|
|
|
const Vector &ysteady = dr.getSteady();
|
|
|
|
|
|
|
|
// initialize vectors and subvectors for simulation
|
|
|
|
Vector dyu(ypart.nys()+nu);
|
|
|
|
ConstVector ystart_pred(ystart, ypart.nstat, ypart.nys());
|
|
|
|
ConstVector ysteady_pred(ysteady, ypart.nstat, ypart.nys());
|
|
|
|
Vector dy(dyu, 0, ypart.nys());
|
|
|
|
Vector u(dyu, ypart.nys(), nu);
|
|
|
|
Vector y(nc.getDim());
|
|
|
|
ConstVector ypred(y, ypart.nstat, ypart.nys());
|
|
|
|
|
|
|
|
// simulate the first real-time period
|
|
|
|
int ip = 0;
|
|
|
|
dy = ystart_pred;
|
|
|
|
dy.add(-1.0, ysteady_pred);
|
|
|
|
sr.get(ip, u);
|
|
|
|
dr.eval(em, y, dyu);
|
|
|
|
if (ip >= res.num_burn)
|
|
|
|
nc.update(y);
|
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
// simulate other real-time periods
|
2019-01-04 16:29:57 +01:00
|
|
|
while (y.isFinite() && ip < res.num_burn + res.num_per)
|
|
|
|
{
|
|
|
|
ip++;
|
|
|
|
dy = ypred;
|
|
|
|
sr.get(ip, u);
|
|
|
|
dr.eval(em, y, dyu);
|
|
|
|
if (ip >= res.num_burn)
|
|
|
|
nc.update(y);
|
|
|
|
}
|
|
|
|
{
|
2019-01-29 15:52:56 +01:00
|
|
|
std::unique_lock<std::mutex> lk{mut};
|
2019-01-04 16:29:57 +01:00
|
|
|
res.nc.update(nc);
|
|
|
|
if (res.num_per-ip > 0)
|
|
|
|
{
|
|
|
|
res.incomplete_simulations++;
|
|
|
|
res.thrown_periods += res.num_per-ip;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
/* This calculates factorization FFᵀ=V in the Cholesky way. It does
|
2019-01-04 16:29:57 +01:00
|
|
|
not work for semidefinite matrices. */
|
|
|
|
|
|
|
|
void
|
2019-01-24 15:22:36 +01:00
|
|
|
RandomShockRealization::choleskyFactor(const ConstTwoDMatrix &v)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
|
|
|
factor = v;
|
2019-01-24 13:08:05 +01:00
|
|
|
lapack_int rows = factor.nrows(), lda = factor.getLD();
|
2019-01-04 16:29:57 +01:00
|
|
|
for (int i = 0; i < rows; i++)
|
|
|
|
for (int j = i+1; j < rows; j++)
|
|
|
|
factor.get(i, j) = 0.0;
|
|
|
|
lapack_int info;
|
|
|
|
|
2019-01-24 13:08:05 +01:00
|
|
|
dpotrf("L", &rows, factor.base(), &lda, &info);
|
2019-01-04 16:29:57 +01:00
|
|
|
KORD_RAISE_IF(info != 0,
|
|
|
|
"Info!=0 in RandomShockRealization::choleskyFactor");
|
|
|
|
}
|
|
|
|
|
2019-05-10 18:41:23 +02:00
|
|
|
/* This calculates FFᵀ=V factorization by symmetric Schur
|
|
|
|
decomposition. It works for semidefinite matrices. */
|
2019-01-04 16:29:57 +01:00
|
|
|
|
|
|
|
void
|
2019-01-24 15:22:36 +01:00
|
|
|
RandomShockRealization::schurFactor(const ConstTwoDMatrix &v)
|
2019-01-04 16:29:57 +01:00
|
|
|
{
|
2019-03-05 18:35:35 +01:00
|
|
|
SymSchurDecomp(v).getFactor(factor);
|
2019-01-04 16:29:57 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
RandomShockRealization::get(int n, Vector &out)
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(out.length() != numShocks(),
|
|
|
|
"Wrong length of out vector in RandomShockRealization::get");
|
|
|
|
Vector d(out.length());
|
|
|
|
for (int i = 0; i < d.length(); i++)
|
2019-03-05 12:29:17 +01:00
|
|
|
d[i] = dis(mtwister);
|
2019-01-04 16:29:57 +01:00
|
|
|
out.zeros();
|
|
|
|
factor.multaVec(out, ConstVector(d));
|
|
|
|
}
|
|
|
|
|
|
|
|
ExplicitShockRealization::ExplicitShockRealization(ShockRealization &sr,
|
|
|
|
int num_per)
|
|
|
|
: shocks(sr.numShocks(), num_per)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < num_per; j++)
|
|
|
|
{
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
Vector jcol{shocks.getCol(j)};
|
2019-01-04 16:29:57 +01:00
|
|
|
sr.get(j, jcol);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExplicitShockRealization::get(int n, Vector &out)
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(out.length() != numShocks(),
|
|
|
|
"Wrong length of out vector in ExplicitShockRealization::get");
|
|
|
|
int i = n % shocks.ncols();
|
Dynare++ / sylvester equation solver: refactor Vector and ConstVector classes
- these classes now encapsulate a std::shared_ptr<{const, }double>, so that
they do not perform memory management, and several {Const,}Vector instances
can transparently share the same underlying data
- make converting constructor from ConstVector to Vector explicit, since that
entails memory allocation (but the reverse conversion is almost costless, so
keep it implicit); do the same for GeneralMatrix/ConstGeneralMatrix,
TwoDMatrix/ConstTwoDMatrix
- remove the constructors that were extracting a row/column from a matrix, and
replace them by getRow() and getCol() methods on {Const,}GeneralMatrix
- rename and change the API of the complex version Vector::add(), so that it is
explicit that it deals with complex numbers
- add constructors that take a MATLAB mxArray
2019-01-22 16:07:44 +01:00
|
|
|
ConstVector icol{shocks.getCol(i)};
|
2019-01-04 16:29:57 +01:00
|
|
|
out = icol;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ExplicitShockRealization::addToShock(int ishock, int iper, double val)
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(ishock < 0 || ishock > numShocks(),
|
|
|
|
"Wrong index of shock in ExplicitShockRealization::addToShock");
|
|
|
|
int j = iper % shocks.ncols();
|
|
|
|
shocks.get(ishock, j) += val;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
GenShockRealization::get(int n, Vector &out)
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(out.length() != numShocks(),
|
|
|
|
"Wrong length of out vector in GenShockRealization::get");
|
|
|
|
ExplicitShockRealization::get(n, out);
|
|
|
|
Vector r(numShocks());
|
|
|
|
RandomShockRealization::get(n, r);
|
|
|
|
for (int j = 0; j < numShocks(); j++)
|
2019-02-06 15:50:01 +01:00
|
|
|
if (!std::isfinite(out[j]))
|
2019-01-04 16:29:57 +01:00
|
|
|
out[j] = r[j];
|
|
|
|
}
|