dynare/dynare++/kord/korder_stoch.hweb

539 lines
18 KiB
Plaintext

@q $Id: korder_stoch.hweb 418 2005-08-16 15:10:06Z kamenik $ @>
@q Copyright 2005, Ondra Kamenik @>
@*2 Higher order at stochastic steady. Start of {\tt korder\_stoch.h} file.
This file defines a number of classes of which |KOrderStoch| is the
main purpose. Basically, |KOrderStoch| calculates first and higher
order Taylor expansion of a policy rule at $\sigma>0$ with explicit
forward $g^{**}$. More formally, we have to solve a policy rule $g$
from
$$E_t\left[f(g^{**}(g^*(y^*_t,u_t,\sigma),u_{t+1},\sigma),g(y^*,u_t,\sigma),y^*,u_t)\right]$$
As an introduction in {\tt approximation.hweb} argues, $g^{**}$ at
tine $t+1$ must be given from outside. Let the explicit
$E_t(g^{**}(y^*,u_{t+1},\sigma)$ be equal to $h(y^*,\sigma)$. Then we
have to solve
$$f(h(g^*(y^*,u,\sigma),\sigma),g(y,u,\sigma),y,u),$$
which is much easier than fully implicit system for $\sigma=0$.
Besides the class |KOrderStoch|, we declare here also classes for the
new containers corresponding to
$f(h(g^*(y^*,u,\sigma),\sigma),g(y,u,\sigma),y,u)$. Further, we
declare |IntegDerivs| and |StochForwardDerivs| classes which basically
calculate $h$ as an extrapolation based on an approximation to $g$ at
lower $\sigma$.
@s IntegDerivs int
@s StochForwardDerivs int
@s GContainer int
@s ZContainer int
@s GXContainer int
@s ZXContainer int
@s MatrixAA int
@s KOrderStoch int
@s StackContainer int
@s _Ttype int
@s _Ctype int
@s UnfoldedStackContainer int
@s FoldedStackContainer int
@c
#include "korder.h"
#include "faa_di_bruno.h"
#include "journal.h"
@<|IntegDerivs| class declaration@>;
@<|StochForwardDerivs| class declaration@>;
@<|GXContainer| class declaration@>;
@<|ZXContainer| class declaration@>;
@<|UnfoldedGXContainer| class declaration@>;
@<|FoldedGXContainer| class declaration@>;
@<|UnfoldedZXContainer| class declaration@>;
@<|FoldedZXContainer| class declaration@>;
@<|MatrixAA| class declaration@>;
@<|KOrderStoch| class declaration@>;
@ This class is a container, which has a specialized constructor
integrating the policy rule at given $\sigma$.
@<|IntegDerivs| class declaration@>=
template <int t>
class IntegDerivs : public ctraits<t>::Tgss {
public:@;
@<|IntegDerivs| constructor code@>;
};
@ This constuctor integrates a rule (namely its $g^{**}$ part) with
respect to $u=\tilde\sigma\eta$, and stores to the object the
derivatives of this integral $h$ at $(y^*,u,\sigma)=(\tilde
y^*,0,\tilde\sigma)$. The original container of $g^{**}$, the moments of
the stochastic shocks |mom| and the $\tilde\sigma$ are input.
The code follows the following derivation
\def\lims{\vbox{\baselineskip=0pt\lineskip=1pt
\setbox0=\hbox{$\scriptstyle n+k=p$}\hbox to\wd0{\hss$\scriptstyle m=0$\hss}\box0}}
$$
\eqalign{h(y,\sigma)&=E_t\left[g(y,u',\sigma)\right]=\cr
&=\tilde y+\sum_{d=1}{1\over d!}\sum_{i+j+k=d}\pmatrix{d\cr i,j,k}\left[g_{y^iu^j\sigma^k}\right]
(y^*-\tilde y^*)^i\sigma^j\Sigma^j(\sigma-\tilde\sigma)^k\cr
&=\tilde y+\sum_{d=1}{1\over d!}\sum_{i+m+n+k=d}\pmatrix{d\cr i,m+n,k}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\hat y^{*i}\Sigma^{m+n}\pmatrix{m+n\cr m,n}{\tilde\sigma}^m\hat\sigma^{k+n}\cr
&=\tilde y+\sum_{d=1}{1\over d!}\sum_{i+m+n+k=d}\pmatrix{d\cr i,m,n,k}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\Sigma^{m+n}{\tilde\sigma}^m\hat y^{*i}\hat\sigma^{k+n}\cr
&=\tilde y+\sum_{d=1}{1\over d!}\sum_{i+p=d}\sum_{\lims}\pmatrix{d\cr i,m,n,k}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\Sigma^{m+n}{\tilde\sigma}^m\hat y^{*i}\hat\sigma^{k+n}\cr
&=\tilde y+\sum_{d=1}{1\over d!}\sum_{i+p=d}\pmatrix{d\cr i,p}
\left[\sum_{\lims}\pmatrix{p\cr n,k}{1\over m!}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\Sigma^{m+n}{\tilde\sigma}^m\right]\hat y^{*i}\hat\sigma^{k+n},
}
$$
where $\pmatrix{a\cr b_1,\ldots, b_n}$ is a generalized combination
number, $p=k+n$, $\hat\sigma=\sigma-\tilde\sigma$, $\hat
y^*=y^*-\tilde y$, and we dropped writing the multidimensional indexes
in Einstein summation.
This implies that
$$h_{y^i\sigma^p}=\sum_{\lims}\pmatrix{p\cr n,k}{1\over m!}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\Sigma^{m+n}{\tilde\sigma}^m$$
and this is exactly what the code does.
@<|IntegDerivs| constructor code@>=
IntegDerivs(int r, const IntSequence& nvs, const _Tgss& g, const __Tm& mom,
double at_sigma)
: ctraits<t>::Tgss(4)
{
int maxd = g.getMaxDim();
for (int d = 1; d <= maxd; d++) {
for (int i = 0; i <= d; i++) {
int p = d-i;
Symmetry sym(i,0,0,p);
_Ttensor* ten = new _Ttensor(r, TensorDimens(sym, nvs));
@<calculate derivative $h_{y^i\sigma^p}$@>;
this->insert(ten);
}
}
}
@ This code calculates
$$h_{y^i\sigma^p}=\sum_{\lims}\pmatrix{p\cr n,k}{1\over m!}
\left[g_{y^iu^{m+n}\sigma^k}\right]
\Sigma^{m+n}{\tilde\sigma}^m$$
and stores it in |ten|.
@<calculate derivative $h_{y^i\sigma^p}$@>=
ten->zeros();
for (int n = 0; n <= p; n++) {
int k = p-n;
int povern = Tensor::noverk(p,n);
int mfac = 1;
for (int m = 0; i+m+n+k <= maxd; m++, mfac*=m) {
double mult = (pow(at_sigma,m)*povern)/mfac;
Symmetry sym_mn(i,m+n,0,k);
if (m+n == 0 && g.check(sym_mn))
ten->add(mult, *(g.get(sym_mn)));
if (m+n > 0 && KOrder::is_even(m+n) && g.check(sym_mn)) {
_Ttensor gtmp(*(g.get(sym_mn)));
gtmp.mult(mult);
gtmp.contractAndAdd(1, *ten, *(mom.get(Symmetry(m+n))));
}
}
}
@ This class calculates an extrapolation of expectation of forward
derivatives. It is a container, all calculations are done in a
constructor.
The class calculates derivatives of $E[g(y*,u,\sigma)]$ at $(\bar
y^*,\bar\sigma)$. The derivatives are extrapolated based on
derivatives at $(\tilde y^*,\tilde\sigma)$.
@<|StochForwardDerivs| class declaration@>=
template <int t>
class StochForwardDerivs : public ctraits<t>::Tgss {
public:@;
@<|StochForwardDerivs| constructor code@>;
};
@ This is the constructor which performs the integration and the
extrapolation. Its parameters are: |g| is the container of derivatives
at $(\tilde y,\tilde\sigma)$; |m| are the moments of stochastic
shocks; |ydelta| is a difference of the steady states $\bar y-\tilde
y$; |sdelta| is a difference between new sigma and old sigma
$\bar\sigma-\tilde\sigma$, and |at_sigma| is $\tilde\sigma$. There is
no need of inputing the $\tilde y$.
We do the operation in four steps:
\orderedlist
\li Integrate $g^{**}$, the derivatives are at $(\tilde y,\tilde\sigma)$
\li Form the (full symmetric) polynomial from the derivatives stacking
$\left[\matrix{y^*\cr\sigma}\right]$
\li Centralize this polynomial about $(\bar y,\bar\sigma)$
\li Recover general symmetry tensors from the (full symmetric) polynomial
\endorderedlist
@<|StochForwardDerivs| constructor code@>=
StochForwardDerivs(const PartitionY& ypart, int nu,
const _Tgss& g, const __Tm& m,
const Vector& ydelta, double sdelta,
double at_sigma)
: ctraits<t>::Tgss(4)
{
int maxd = g.getMaxDim();
int r = ypart.nyss();
@<make |g_int| be integral of $g^{**}$ at $(\tilde y,\tilde\sigma)$@>;
@<make |g_int_sym| be full symmetric polynomial from |g_int|@>;
@<make |g_int_cent| the centralized polynomial about $(\bar y,\bar\sigma)$@>;
@<pull out general symmetry tensors from |g_int_cent|@>;
}
@ This simply constructs |IntegDerivs| class. Note that the |nvs| of
the tensors has zero dimensions for shocks, this is because we need to
make easily stacks of the form $\left[\matrix{y^*\cr\sigma}\right]$ in
the next step.
@<make |g_int| be integral of $g^{**}$ at $(\tilde y,\tilde\sigma)$@>=
IntSequence nvs(4);
nvs[0] = ypart.nys(); nvs[1] = 0; nvs[2] = 0; nvs[3] = 1;
IntegDerivs<t> g_int(r, nvs, g, m, at_sigma);
@ Here we just form a polynomial whose unique variable corresponds to
$\left[\matrix{y^*\cr\sigma}\right]$ stack.
@<make |g_int_sym| be full symmetric polynomial from |g_int|@>=
_Tpol g_int_sym(r, ypart.nys()+1);
for (int d = 1; d <= maxd; d++) {
_Ttensym* ten = new _Ttensym(r, ypart.nys()+1, d);
ten->zeros();
for (int i = 0; i <= d; i++) {
int k = d-i;
if (g_int.check(Symmetry(i,0,0,k)))
ten->addSubTensor(*(g_int.get(Symmetry(i,0,0,k))));
}
g_int_sym.insert(ten);
}
@ Here we centralize the polynomial to $(\bar y,\bar\sigma)$ knowing
that the polynomial was centralized about $(\tilde
y,\tilde\sigma)$. This is done by derivating and evaluating the
derivated polynomial at $(\bar y-\tilde
y,\bar\sigma-\tilde\sigma)$. The stack of this vector is |delta| in
the code.
@<make |g_int_cent| the centralized polynomial about $(\bar y,\bar\sigma)$@>=
Vector delta(ypart.nys()+1);
Vector dy(delta, 0, ypart.nys());
ConstVector dy_in(ydelta, ypart.nstat, ypart.nys());
dy = dy_in;
delta[ypart.nys()] = sdelta;
_Tpol g_int_cent(r, ypart.nys()+1);
for (int d = 1; d <= maxd; d++) {
g_int_sym.derivative(d-1);
_Ttensym* der = g_int_sym.evalPartially(d, delta);
g_int_cent.insert(der);
}
@ Here we only recover the general symmetry derivatives from the full
symmetric polynomial. Note that the derivative get the true |nvs|.
@<pull out general symmetry tensors from |g_int_cent|@>=
IntSequence ss(4);
ss[0]=ypart.nys(); ss[1]=0; ss[2]=0; ss[3]=1;
IntSequence pp(4);
pp[0]=0; pp[1]=1; pp[2]=2; pp[3]=3;
IntSequence true_nvs(nvs);
true_nvs[1]=nu; true_nvs[2]=nu;
for (int d = 1; d <= maxd; d++) {
if (g_int_cent.check(Symmetry(d))) {
for (int i = 0; i <= d; i++) {
Symmetry sym(i, 0, 0, d-i);
IntSequence coor(sym, pp);
_Ttensor* ten = new _Ttensor(*(g_int_cent.get(Symmetry(d))), ss, coor,
TensorDimens(sym, true_nvs));
this->insert(ten);
}
}
}
@ This container corresponds to $h(g^*(y,u,\sigma),\sigma)$. Note that
in our application, the $\sigma$ as a second argument to $h$ will be
its fourth variable in symmetry, so we have to do four member stack
having the second and third stack dummy.
@<|GXContainer| class declaration@>=
template <class _Ttype>
class GXContainer : public GContainer<_Ttype> {
public:@;
typedef StackContainerInterface<_Ttype> _Stype;
typedef typename StackContainer<_Ttype>::_Ctype _Ctype;
typedef typename StackContainer<_Ttype>::itype itype;
GXContainer(const _Ctype* gs, int ngs, int nu)
: GContainer<_Ttype>(gs, ngs, nu)@+ {}
@<|GXContainer::getType| code@>;
};
@ This routine corresponds to this stack:
$$\left[\matrix{g^*(y,u,\sigma)\cr dummy\cr dummy\cr\sigma}\right]$$
@<|GXContainer::getType| code@>=
itype getType(int i, const Symmetry& s) const
{
if (i == 0)
if (s[2] > 0)
return _Stype::zero;
else
return _Stype::matrix;
if (i == 1)
return _Stype::zero;
if (i == 2)
return _Stype::zero;
if (i == 3)
if (s == Symmetry(0,0,0,1))
return _Stype::unit;
else
return _Stype::zero;
KORD_RAISE("Wrong stack index in GXContainer::getType");
}
@ This container corresponds to $f(H(y,u,\sigma),g(y,u,sigma),y,u)$,
where the $H$ has the size (number of rows) as $g^{**}$. Since it is
very simmilar to |ZContainer|, we inherit form it and override only
|getType| method.
@<|ZXContainer| class declaration@>=
template <class _Ttype>
class ZXContainer : public ZContainer<_Ttype> {
public:@;
typedef StackContainerInterface<_Ttype> _Stype;
typedef typename StackContainer<_Ttype>::_Ctype _Ctype;
typedef typename StackContainer<_Ttype>::itype itype;
ZXContainer(const _Ctype* gss, int ngss, const _Ctype* g, int ng, int ny, int nu)
: ZContainer<_Ttype>(gss, ngss, g, ng, ny, nu) @+{}
@<|ZXContainer::getType| code@>;
};
@ This |getType| method corresponds to this stack:
$$\left[\matrix{H(y,u,\sigma)\cr g(y,u,\sigma)\cr y\cr u}\right]$$
@<|ZXContainer::getType| code@>=
itype getType(int i, const Symmetry& s) const
{
if (i == 0)
if (s[2] > 0)
return _Stype::zero;
else
return _Stype::matrix;
if (i == 1)
if (s[2] > 0)
return _Stype::zero;
else
return _Stype::matrix;
if (i == 2)
if (s == Symmetry(1,0,0,0))
return _Stype::unit;
else
return _Stype::zero;
if (i == 3)
if (s == Symmetry(0,1,0,0))
return _Stype::unit;
else
return _Stype::zero;
KORD_RAISE("Wrong stack index in ZXContainer::getType");
}
@
@<|UnfoldedGXContainer| class declaration@>=
class UnfoldedGXContainer : public GXContainer<UGSTensor>, public UnfoldedStackContainer {
public:@;
typedef TensorContainer<UGSTensor> _Ctype;
UnfoldedGXContainer(const _Ctype* gs, int ngs, int nu)
: GXContainer<UGSTensor>(gs, ngs, nu)@+ {}
};
@
@<|FoldedGXContainer| class declaration@>=
class FoldedGXContainer : public GXContainer<FGSTensor>, public FoldedStackContainer {
public:@;
typedef TensorContainer<FGSTensor> _Ctype;
FoldedGXContainer(const _Ctype* gs, int ngs, int nu)
: GXContainer<FGSTensor>(gs, ngs, nu)@+ {}
};
@
@<|UnfoldedZXContainer| class declaration@>=
class UnfoldedZXContainer : public ZXContainer<UGSTensor>, public UnfoldedStackContainer {
public:@;
typedef TensorContainer<UGSTensor> _Ctype;
UnfoldedZXContainer(const _Ctype* gss, int ngss, const _Ctype* g, int ng, int ny, int nu)
: ZXContainer<UGSTensor>(gss, ngss, g, ng, ny, nu)@+ {}
};
@
@<|FoldedZXContainer| class declaration@>=
class FoldedZXContainer : public ZXContainer<FGSTensor>, public FoldedStackContainer {
public:@;
typedef TensorContainer<FGSTensor> _Ctype;
FoldedZXContainer(const _Ctype* gss, int ngss, const _Ctype* g, int ng, int ny, int nu)
: ZXContainer<FGSTensor>(gss, ngss, g, ng, ny, nu)@+ {}
};
@ This matrix corresponds to
$$\left[f_{y}\right]+ \left[0
\left[f_{y^{**}_+}\right]\cdot\left[h^{**}_{y^*}\right] 0\right]$$
This is very the same as |MatrixA|, the only difference that the
|MatrixA| is constructed from whole $h_{y^*}$, not only from
$h^{**}_{y^*}$, hence the new abstraction.
@<|MatrixAA| class declaration@>=
class MatrixAA : public PLUMatrix {
public:@;
MatrixAA(const FSSparseTensor& f, const IntSequence& ss,
const TwoDMatrix& gyss, const PartitionY& ypart);
};
@ This class calculates derivatives of $g$ given implicitly by
$f(h(g^*(y,u,\sigma),\sigma),g(y,u,\sigma),y,u)$, where $h(y,\sigma)$
is given from outside.
Structurally, the class is very similar to |KOrder|, but calculations
are much easier. The two constructors construct an object from sparse
derivatives of $f$, and derivatives of $h$. The caller must ensure
that the both derivatives are done at the same point.
The calculation for order $k$ (including $k=1$) is done by a call
|performStep(k)|. The derivatives can be retrived by |getFoldDers()|
or |getUnfoldDers()|.
@<|KOrderStoch| class declaration@>=
class KOrderStoch {
protected:@;
IntSequence nvs;
PartitionY ypart;
Journal& journal;
UGSContainer _ug;
FGSContainer _fg;
UGSContainer _ugs;
FGSContainer _fgs;
UGSContainer _uG;
FGSContainer _fG;
const UGSContainer* _uh;
const FGSContainer* _fh;
UnfoldedZXContainer _uZstack;
FoldedZXContainer _fZstack;
UnfoldedGXContainer _uGstack;
FoldedGXContainer _fGstack;
const TensorContainer<FSSparseTensor>& f;
MatrixAA matA;
public:@;
KOrderStoch(const PartitionY& ypart, int nu, const TensorContainer<FSSparseTensor>& fcont,
const FGSContainer& hh, Journal& jr);
KOrderStoch(const PartitionY& ypart, int nu, const TensorContainer<FSSparseTensor>& fcont,
const UGSContainer& hh, Journal& jr);
@<|KOrderStoch::performStep| templated code@>;
const FGSContainer& getFoldDers() const
{@+ return _fg;@+}
const UGSContainer& getUnfoldDers() const
{@+ return _ug;@+}
protected:@;
@<|KOrderStoch::faaDiBrunoZ| templated code@>;
@<|KOrderStoch::faaDiBrunoG| templated code@>;
@<|KOrderStoch| convenience access methods@>;
};
@ This calculates a derivative of $f(G(y,u,\sigma),g(y,u,\sigma),y,u)$
of a given symmetry.
@<|KOrderStoch::faaDiBrunoZ| templated code@>=
template <int t>
_Ttensor* faaDiBrunoZ(const Symmetry& sym) const
{
JournalRecordPair pa(journal);
pa << "Faa Di Bruno ZX container for " << sym << endrec;
_Ttensor* res = new _Ttensor(ypart.ny(), TensorDimens(sym, nvs));
FaaDiBruno bruno(journal);
bruno.calculate(Zstack<t>(), f, *res);
return res;
}
@ This calculates a derivative of
$G(y,u,\sigma)=h(g^*(y,u,\sigma),\sigma)$ of a given symmetry.
@<|KOrderStoch::faaDiBrunoG| templated code@>=
template <int t>
_Ttensor* faaDiBrunoG(const Symmetry& sym) const
{
JournalRecordPair pa(journal);
pa << "Faa Di Bruno GX container for " << sym << endrec;
TensorDimens tdims(sym, nvs);
_Ttensor* res = new _Ttensor(ypart.nyss(), tdims);
FaaDiBruno bruno(journal);
bruno.calculate(Gstack<t>(), h<t>(), *res);
return res;
}
@ This retrives all $g$ derivatives of a given dimension from implicit
$f(h(g^*(y,u,\sigma),\sigma),g(y,u,\sigma),y,u)$. It suppose that all
derivatives of smaller dimensions have been retrieved.
So, we go through all symmetries $s$, calculate $G_s$ conditional on
$g_s=0$, insert the derivative to the $G$ container, then calculate
$F_s$ conditional on $g_s=0$. This is a righthand side. The left hand
side is $matA\cdot g_s$. The $g_s$ is retrieved as
$$g_s=-matA^{-1}\cdot RHS.$$ Finally we have to update $G_s$ by
calling |Gstack<t>().multAndAdd(1, h<t>(), *G_sym)|.
@<|KOrderStoch::performStep| templated code@>=
template <int t>
void performStep(int order)
{
int maxd = g<t>().getMaxDim();
KORD_RAISE_IF(order-1 != maxd && (order != 1 || maxd != -1),
"Wrong order for KOrderStoch::performStep");
SymmetrySet ss(order, 4);
for (symiterator si(ss); !si.isEnd(); ++si) {
if ((*si)[2] == 0) {
JournalRecordPair pa(journal);
pa << "Recovering symmetry " << *si << endrec;
_Ttensor* G_sym = faaDiBrunoG<t>(*si);
G<t>().insert(G_sym);
_Ttensor* g_sym = faaDiBrunoZ<t>(*si);
g_sym->mult(-1.0);
matA.multInv(*g_sym);
g<t>().insert(g_sym);
gs<t>().insert(new _Ttensor(ypart.nstat, ypart.nys(), *g_sym));
Gstack<t>().multAndAdd(1, h<t>(), *G_sym);
}
}
}
@
@<|KOrderStoch| convenience access methods@>=
template<int t> _Tg& g();
template<int t> const _Tg& g() const;
template<int t> _Tgs& gs();
template<int t> const _Tgs& gs() const;
template<int t> const _Tgss& h() const;
template<int t> _TG& G();
template<int t> const _TG& G() const;
template<int t> _TZXstack& Zstack();
template<int t> const _TZXstack& Zstack() const;
template<int t> _TGXstack& Gstack();
template<int t> const _TGXstack& Gstack() const;
@ End of {\tt korder\_stoch.h} file.