dynare/dynare++/tl/cc/normal_moments.cc

92 lines
3.0 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Copyright 2004, Ondra Kamenik
#include <memory>
#include "normal_moments.hh"
#include "permutation.hh"
#include "kron_prod.hh"
#include "tl_static.hh"
UNormalMoments::UNormalMoments(int maxdim, const TwoDMatrix &v)
: TensorContainer<URSingleTensor>(1)
{
if (maxdim >= 2)
generateMoments(maxdim, v);
}
/* Here we fill up the container with the tensors for d=2,4,6,… up to the given
dimension. Each tensor of moments is equal to Fₙ(⊗ⁿv). This has a dimension
equal to 2n. See the header file for proof and details.
Here we sequentially construct the Kronecker power ⊗ⁿv and apply Fₙ.
*/
void
UNormalMoments::generateMoments(int maxdim, const TwoDMatrix &v)
{
TL_RAISE_IF(v.nrows() != v.ncols(),
"Variance-covariance matrix is not square in UNormalMoments constructor");
int nv = v.nrows();
auto mom2 = std::make_unique<URSingleTensor>(nv, 2);
mom2->getData() = v.getData();
insert(std::move(mom2));
auto kronv = std::make_unique<URSingleTensor>(nv, 2);
kronv->getData() = v.getData();
for (int d = 4; d <= maxdim; d += 2)
{
auto newkronv = std::make_unique<URSingleTensor>(nv, d);
KronProd::kronMult(ConstVector(v.getData()),
ConstVector(kronv->getData()),
newkronv->getData());
kronv = std::move(newkronv);
auto mom = std::make_unique<URSingleTensor>(nv, d);
// apply Fₙ to kronv
/* Here we go through all equivalences, select only those having 2
elements in each class, then go through all elements in kronv and
add to permuted location of mom.
The permutation must be taken as inverse of the permutation implied by
the equivalence, since we need a permutation which after application
to identity of indices yileds indices in the equivalence classes. Note
how the Equivalence::apply() method works. */
mom->zeros();
const EquivalenceSet eset = TLStatic::getEquiv(d);
for (const auto &cit : eset)
if (selectEquiv(cit))
{
Permutation per(cit);
per.inverse();
for (Tensor::index it = kronv->begin(); it != kronv->end(); ++it)
{
IntSequence ind(kronv->dimen());
per.apply(it.getCoor(), ind);
Tensor::index it2(*mom, ind);
mom->get(*it2, 0) += kronv->get(*it, 0);
}
}
insert(std::move(mom));
}
}
/* We return true for an equivalence whose each class has 2 elements. */
bool
UNormalMoments::selectEquiv(const Equivalence &e)
{
if (2*e.numClasses() != e.getN())
return false;
for (const auto &si : e)
if (si.length() != 2)
return false;
return true;
}
/* Here we go through all the unfolded container, fold each tensor and
insert it. */
FNormalMoments::FNormalMoments(const UNormalMoments &moms)
: TensorContainer<FRSingleTensor>(1)
{
for (const auto &mom : moms)
insert(std::make_unique<FRSingleTensor>(*(mom.second)));
}