2009-09-08 15:55:19 +02:00
|
|
|
@q $Id: korder.hweb 2332 2009-01-14 10:26:54Z kamenik $ @>
|
|
|
|
@q Copyright 2004, Ondra Kamenik @>
|
|
|
|
|
|
|
|
@*2 Higher order at deterministic steady. Start of {\tt korder.h} file.
|
|
|
|
|
|
|
|
The main purpose of this file is to implement a perturbation method
|
|
|
|
algorithm for an SDGE model for higher order approximations. The input
|
|
|
|
of the algorithm are sparse tensors as derivatives of the dynamic
|
|
|
|
system, then dimensions of vector variables, then the first order
|
|
|
|
approximation to the decision rule and finally a covariance matrix of
|
|
|
|
exogenous shocks. The output are higher order derivatives of decision
|
|
|
|
rule $y_t=g(y^*_{t-1},u_t,\sigma)$. The class provides also a method
|
|
|
|
for checking a size of residuals of the solved equations.
|
|
|
|
|
|
|
|
The algorithm is implemented in |KOrder| class. The class contains
|
|
|
|
both unfolded and folded containers to allow for switching (usually
|
|
|
|
from unfold to fold) during the calculations. The algorithm is
|
|
|
|
implemented in a few templated methods. To do this, we need some
|
|
|
|
container type traits, which are in |ctraits| struct. Also, the
|
|
|
|
|KOrder| class contains some information encapsulated in other
|
|
|
|
classes, which are defined here. These include: |PartitionY|,
|
|
|
|
|MatrixA|, |MatrixS| and |MatrixB|.
|
|
|
|
|
|
|
|
@s KOrder int
|
|
|
|
@s ctraits int
|
|
|
|
@s PartitionY int
|
|
|
|
@s MatrixA int
|
|
|
|
@s MatrixB int
|
|
|
|
@s MatrixS int
|
|
|
|
@s PLUMatrix int
|
|
|
|
@s FGSTensor int
|
|
|
|
@s UGSTensor int
|
|
|
|
@s FGSContainer int
|
|
|
|
@s UGSContainer int
|
|
|
|
@s FSSparseTensor int
|
|
|
|
@s TensorContainer int
|
|
|
|
@s UNormalMoments int
|
|
|
|
@s FNormalMoments int
|
|
|
|
@s FoldedZContainer int
|
|
|
|
@s UnfoldedZContainer int
|
|
|
|
@s FoldedGContainer int
|
|
|
|
@s UnfoldedGContainer int
|
|
|
|
@s FoldedZXContainer int
|
|
|
|
@s UnfoldedZXContainer int
|
|
|
|
@s FoldedGXContainer int
|
|
|
|
@s UnfoldedGXContainer int
|
|
|
|
@s TwoDMatrix int
|
|
|
|
@s ConstTwoDMatrix int
|
|
|
|
@s IntSequence int
|
|
|
|
@s Symmetry int
|
|
|
|
@s SymmetrySet int
|
|
|
|
@s symiterator int
|
|
|
|
@s TensorDimens int
|
|
|
|
@s Vector int
|
|
|
|
@s ConstVector int
|
|
|
|
@s UTensorPolynomial int
|
|
|
|
@s FTensorPolynomial int
|
|
|
|
@s UFSTensor int
|
|
|
|
@s FFSTensor int
|
|
|
|
@s GeneralSylvester int
|
|
|
|
|
|
|
|
@c
|
|
|
|
#ifndef KORDER_H
|
|
|
|
#define KORDER_H
|
|
|
|
|
|
|
|
#include "int_sequence.h"
|
|
|
|
#include "fs_tensor.h"
|
|
|
|
#include "gs_tensor.h"
|
|
|
|
#include "t_container.h"
|
|
|
|
#include "stack_container.h"
|
|
|
|
#include "normal_moments.h"
|
|
|
|
#include "t_polynomial.h"
|
|
|
|
#include "faa_di_bruno.h"
|
|
|
|
#include "journal.h"
|
|
|
|
|
|
|
|
#include "kord_exception.h"
|
|
|
|
#include "GeneralSylvester.h"
|
|
|
|
|
2009-10-02 12:23:49 +02:00
|
|
|
#include <dynlapack.h>
|
|
|
|
|
2009-09-08 15:55:19 +02:00
|
|
|
#include <cmath>
|
|
|
|
|
|
|
|
#define TYPENAME typename
|
|
|
|
|
|
|
|
@<|ctraits| type traits declaration@>;
|
|
|
|
@<|PartitionY| struct declaration@>;
|
|
|
|
@<|PLUMatrix| class declaration@>;
|
|
|
|
@<|MatrixA| class declaration@>;
|
|
|
|
@<|MatrixS| class declaration@>;
|
|
|
|
@<|MatrixB| class declaration@>;
|
|
|
|
@<|KOrder| class declaration@>;
|
|
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
@ Here we use a classical IF template, and in |ctraits| we define a
|
|
|
|
number of types. We have a type for tensor |Ttensor|, and types for
|
|
|
|
each pair of folded/unfolded containers used as a member in |KOrder|.
|
|
|
|
|
|
|
|
Note that we have enumeration |fold| and |unfold|. These must have the
|
|
|
|
same value as the same enumeration in |KOrder|.
|
|
|
|
|
|
|
|
@s IF int
|
|
|
|
@s Then int
|
|
|
|
@s Else int
|
|
|
|
@s RET int
|
|
|
|
|
|
|
|
@<|ctraits| type traits declaration@>=
|
|
|
|
class FoldedZXContainer;
|
|
|
|
class UnfoldedZXContainer;
|
|
|
|
class FoldedGXContainer;
|
|
|
|
class UnfoldedGXContainer;
|
|
|
|
|
|
|
|
template<bool condition, class Then, class Else>
|
|
|
|
struct IF {
|
|
|
|
typedef Then RET;
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class Then, class Else>
|
|
|
|
struct IF<false, Then, Else> {
|
|
|
|
typedef Else RET;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <int type>
|
|
|
|
class ctraits {
|
|
|
|
public:@;
|
|
|
|
enum {@+ fold, unfold@+};
|
|
|
|
typedef TYPENAME IF<type==fold, FGSTensor, UGSTensor>::RET Ttensor;
|
|
|
|
typedef TYPENAME IF<type==fold, FFSTensor, UFSTensor>::RET Ttensym;
|
|
|
|
typedef TYPENAME IF<type==fold, FGSContainer, UGSContainer>::RET Tg;
|
|
|
|
typedef TYPENAME IF<type==fold, FGSContainer, UGSContainer>::RET Tgs;
|
|
|
|
typedef TYPENAME IF<type==fold, FGSContainer, UGSContainer>::RET Tgss;
|
|
|
|
typedef TYPENAME IF<type==fold, FGSContainer, UGSContainer>::RET TG;
|
|
|
|
typedef TYPENAME IF<type==fold, FoldedZContainer, UnfoldedZContainer>::RET TZstack;
|
|
|
|
typedef TYPENAME IF<type==fold, FoldedGContainer, UnfoldedGContainer>::RET TGstack;
|
|
|
|
typedef TYPENAME IF<type==fold, FNormalMoments, UNormalMoments>::RET Tm;
|
|
|
|
typedef TYPENAME IF<type==fold, FTensorPolynomial, UTensorPolynomial>::RET Tpol;
|
|
|
|
typedef TYPENAME IF<type==fold, FoldedZXContainer, UnfoldedZXContainer>::RET TZXstack;
|
|
|
|
typedef TYPENAME IF<type==fold, FoldedGXContainer, UnfoldedGXContainer>::RET TGXstack;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@ The |PartitionY| class defines the partitioning of state variables
|
|
|
|
$y$. The vector $y$, and subvector $y^*$, and $y^{**}$ are defined.
|
|
|
|
$$y=\left[\matrix{\hbox{static}\cr\hbox{predeter}\cr\hbox{both}\cr
|
|
|
|
\hbox{forward}}\right],\quad
|
|
|
|
y^*=\left[\matrix{\hbox{predeter}\cr\hbox{both}}\right],\quad
|
|
|
|
y^{**}=\left[\matrix{\hbox{both}\cr\hbox{forward}}\right],$$
|
|
|
|
where ``static'' means variables appearing only at time $t$,
|
|
|
|
``predeter'' means variables appearing at time $t-1$, but not at
|
|
|
|
$t+1$, ``both'' means variables appearing both at $t-1$ and $t+1$
|
|
|
|
(regardless appearance at $t$), and ``forward'' means variables
|
|
|
|
appearing at $t+1$, but not at $t-1$.
|
|
|
|
|
|
|
|
The class maintains the four lengths, and returns the whole length,
|
|
|
|
length of $y^s$, and length of $y^{**}$.
|
|
|
|
|
|
|
|
@<|PartitionY| struct declaration@>=
|
|
|
|
struct PartitionY {
|
|
|
|
const int nstat;
|
|
|
|
const int npred;
|
|
|
|
const int nboth;
|
|
|
|
const int nforw;
|
|
|
|
PartitionY(int num_stat, int num_pred,
|
|
|
|
int num_both, int num_forw)
|
|
|
|
: nstat(num_stat), npred(num_pred),
|
|
|
|
nboth(num_both), nforw(num_forw)
|
|
|
|
{}
|
|
|
|
int ny() const
|
|
|
|
{@+ return nstat+npred+nboth+nforw;@+}
|
|
|
|
int nys() const
|
|
|
|
{@+ return npred+nboth;@+}
|
|
|
|
int nyss() const
|
|
|
|
{@+ return nboth+nforw;@+}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@ This is an abstraction for a square matrix with attached PLU
|
|
|
|
factorization. It can calculate the PLU factorization and apply the
|
|
|
|
inverse with some given matrix.
|
|
|
|
|
|
|
|
We use LAPACK $PLU$ decomposition for the inverse. We store the $L$
|
|
|
|
and $U$ in the |inv| array and |ipiv| is the permutation $P$.
|
|
|
|
|
|
|
|
@<|PLUMatrix| class declaration@>=
|
|
|
|
class PLUMatrix : public TwoDMatrix {
|
|
|
|
public:@;
|
|
|
|
PLUMatrix(int n)
|
|
|
|
: TwoDMatrix(n,n),
|
|
|
|
inv(nrows()*ncols()),
|
2009-10-02 12:23:49 +02:00
|
|
|
ipiv(new lapack_int[nrows()]) {}
|
2009-09-08 15:55:19 +02:00
|
|
|
PLUMatrix(const PLUMatrix& plu);
|
|
|
|
virtual ~PLUMatrix()
|
|
|
|
{delete [] ipiv;}
|
|
|
|
void multInv(TwoDMatrix& m) const;
|
|
|
|
private:@;
|
|
|
|
Vector inv;
|
2009-10-02 12:23:49 +02:00
|
|
|
lapack_int* ipiv;
|
2009-09-08 15:55:19 +02:00
|
|
|
protected:@;
|
|
|
|
void calcPLU();
|
|
|
|
};
|
|
|
|
|
|
|
|
@ The class |MatrixA| is used for matrix $\left[f_{y}\right]+ \left[0
|
|
|
|
\left[f_{y^{**}_+}\right]\cdot\left[g^{**}_{y^*}\right] 0\right]$,
|
|
|
|
which is central for the perturbation method step.
|
|
|
|
|
|
|
|
@<|MatrixA| class declaration@>=
|
|
|
|
class MatrixA : public PLUMatrix {
|
|
|
|
public:@;
|
|
|
|
MatrixA(const FSSparseTensor& f, const IntSequence& ss,
|
|
|
|
const TwoDMatrix& gy, const PartitionY& ypart);
|
|
|
|
};
|
|
|
|
|
|
|
|
@ The class |MatrixS| slightly differs from |MatrixA|. It is used for
|
|
|
|
matrix $$\left[f_{y}\right]+ \left[0
|
|
|
|
\quad\left[f_{y^{**}_+}\right]\cdot\left[g^{**}_{y^*}\right]\quad
|
|
|
|
0\right]+\left[0\quad 0\quad\left[f_{y^{**}_+}\right]\right]$$, which is
|
|
|
|
needed when recovering $g_{\sigma^k}$.
|
|
|
|
|
|
|
|
@<|MatrixS| class declaration@>=
|
|
|
|
class MatrixS : public PLUMatrix {
|
|
|
|
public:@;
|
|
|
|
MatrixS(const FSSparseTensor& f, const IntSequence& ss,
|
|
|
|
const TwoDMatrix& gy, const PartitionY& ypart);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@ The $B$ matrix is equal to $\left[f_{y^{**}_+}\right]$. We have just
|
|
|
|
a constructor.
|
|
|
|
|
|
|
|
@<|MatrixB| class declaration@>=
|
|
|
|
class MatrixB : public TwoDMatrix {
|
|
|
|
public:@;
|
|
|
|
MatrixB(const FSSparseTensor& f, const IntSequence& ss)
|
|
|
|
: TwoDMatrix(FGSTensor(f, ss, IntSequence(1,0),
|
|
|
|
TensorDimens(ss, IntSequence(1,0))))
|
|
|
|
{}
|
|
|
|
};
|
|
|
|
|
|
|
|
@ Here we have the class for the higher order approximations. It
|
|
|
|
contains the following data:
|
|
|
|
|
|
|
|
\halign{\kern\parindent\vrule height12pt width0pt
|
|
|
|
\vtop{\hsize=4cm\noindent\raggedright #}&\kern0.5cm\vtop{\hsize=10cm\noindent #}\cr
|
|
|
|
variable sizes ypart& |PartitionY| struct maintaining partitions of
|
|
|
|
$y$, see |@<|PartitionY| struct declaration@>|\cr
|
|
|
|
tensor variable dimension |nvs|& variable sizes of all tensors in
|
|
|
|
containers, sizes of $y^*$, $u$, $u'$@q'@> and $\sigma$\cr
|
|
|
|
tensor containers & folded and unfolded containers for $g$, $g_{y^*}$,
|
|
|
|
$g_{y^**}$ (the latter two collect appropriate subtensors of $g$, they
|
|
|
|
do not allocate any new space), $G$, $G$ stack, $Z$ stack\cr
|
|
|
|
dynamic model derivatives & just a reference to the container of
|
|
|
|
sparse tensors of the system derivatives, lives outside the class\cr
|
|
|
|
moments & both folded and unfolded normal moment containers, both are
|
|
|
|
calculated at initialization\cr
|
|
|
|
matrices & matrix $A$, matrix $S$, and matrix $B$, see |@<|MatrixA| class
|
|
|
|
declaration@>| and |@<|MatrixB| class declaration@>|\cr
|
|
|
|
}
|
|
|
|
|
|
|
|
\kern 0.4cm
|
|
|
|
|
|
|
|
The methods are the following:
|
|
|
|
\halign{\kern\parindent\vrule height12pt width0pt
|
|
|
|
\vtop{\hsize=4cm\noindent\raggedright #}&\kern0.5cm\vtop{\hsize=10cm\noindent #}\cr
|
|
|
|
member access & we declare template methods for accessing containers
|
|
|
|
depending on |fold| and |unfold| flag, we implement their
|
|
|
|
specializations\cr
|
|
|
|
|performStep| & this performs $k$-order step provided that $k=2$ or
|
|
|
|
the $k-1$-th step has been run, this is the core method\cr
|
|
|
|
|check| & this calculates residuals of all solved equations for
|
|
|
|
$k$-order and reports their sizes, it is runnable after $k$-order
|
|
|
|
|performStep| has been run\cr
|
|
|
|
|insertDerivative| & inserts a $g$ derivative to the $g$ container and
|
|
|
|
also creates subtensors and insert them to $g_{y^*}$ and $g_{y^{**}}$
|
|
|
|
containers\cr
|
|
|
|
|sylvesterSolve| & solve the sylvester equation (templated fold, and
|
|
|
|
unfold)\cr
|
|
|
|
|faaDiBrunoZ| & calculates derivatives of $F$ by Faa Di Bruno for the
|
|
|
|
sparse container of system derivatives and $Z$ stack container\cr
|
|
|
|
|faaDiBrunoG| & calculates derivatives of $G$ by Faa Di Bruno for the
|
|
|
|
dense container $g^{**}$ and $G$ stack\cr
|
|
|
|
|recover_y| & recovers $g_{y^{*i}}$\cr
|
|
|
|
|recover_yu| & recovers $g_{y^{*i}u^j}$\cr
|
|
|
|
|recover_ys| & recovers $g_{y^{*i}\sigma^j}$\cr
|
|
|
|
|recover_yus| & recovers $g_{y^{*i}u^j\sigma^k}$\cr
|
|
|
|
|recover_s| & recovers $g_{\sigma^i}$\cr
|
|
|
|
|fillG| & calculates specified derivatives of $G$ and inserts them to
|
|
|
|
the container\cr
|
|
|
|
|calcE_ijk|& calculates $E_{ijk}$\cr
|
|
|
|
|calcD_ijk|& calculates $D_{ijk}$\cr
|
|
|
|
}
|
|
|
|
|
|
|
|
\kern 0.3cm
|
|
|
|
|
|
|
|
Most of the code is templated, and template types are calculated in
|
|
|
|
|ctraits|. So all templated methods get a template argument |T|, which
|
|
|
|
can be either |fold|, or |unfold|. To shorten a reference to a type
|
|
|
|
calculated by |ctraits| for a particular |t|, we define the following
|
|
|
|
macros.
|
|
|
|
|
|
|
|
@s _Ttensor int
|
|
|
|
@s _Ttensym int
|
|
|
|
@s _Tg int
|
|
|
|
@s _Tgs int
|
|
|
|
@s _Tgss int
|
|
|
|
@s _TG int
|
|
|
|
@s _TZstack int
|
|
|
|
@s _TGstack int
|
|
|
|
@s _TZXstack int
|
|
|
|
@s _TGXstack int
|
2009-10-30 19:19:42 +01:00
|
|
|
@s __Tm int
|
2009-09-08 15:55:19 +02:00
|
|
|
@s _Tpol int
|
|
|
|
@d _Ttensor TYPENAME ctraits<t>::Ttensor
|
|
|
|
@d _Ttensym TYPENAME ctraits<t>::Ttensym
|
|
|
|
@d _Tg TYPENAME ctraits<t>::Tg
|
|
|
|
@d _Tgs TYPENAME ctraits<t>::Tgs
|
|
|
|
@d _Tgss TYPENAME ctraits<t>::Tgss
|
|
|
|
@d _TG TYPENAME ctraits<t>::TG
|
|
|
|
@d _TZstack TYPENAME ctraits<t>::TZstack
|
|
|
|
@d _TGstack TYPENAME ctraits<t>::TGstack
|
|
|
|
@d _TZXstack TYPENAME ctraits<t>::TZXstack
|
|
|
|
@d _TGXstack TYPENAME ctraits<t>::TGXstack
|
2009-10-30 19:19:42 +01:00
|
|
|
@d __Tm TYPENAME ctraits<t>::Tm
|
2009-09-08 15:55:19 +02:00
|
|
|
@d _Tpol TYPENAME ctraits<t>::Tpol
|
|
|
|
|
|
|
|
|
|
|
|
@<|KOrder| class declaration@>=
|
|
|
|
class KOrder {
|
|
|
|
protected:@;
|
|
|
|
const PartitionY ypart;
|
|
|
|
const int ny;
|
|
|
|
const int nu;
|
|
|
|
const int maxk;
|
|
|
|
IntSequence nvs;
|
|
|
|
@<|KOrder| container members@>;
|
|
|
|
const MatrixA matA;
|
|
|
|
const MatrixS matS;
|
|
|
|
const MatrixB matB;
|
|
|
|
@<|KOrder| member access method declarations@>;
|
|
|
|
Journal& journal;
|
|
|
|
public:@;
|
|
|
|
KOrder(int num_stat, int num_pred, int num_both, int num_forw,
|
|
|
|
const TensorContainer<FSSparseTensor>& fcont,
|
|
|
|
const TwoDMatrix& gy, const TwoDMatrix& gu, const TwoDMatrix& v,
|
|
|
|
Journal& jr);
|
|
|
|
enum {@+ fold, unfold@+ };
|
|
|
|
@<|KOrder::performStep| templated code@>;
|
|
|
|
@<|KOrder::check| templated code@>;
|
|
|
|
@<|KOrder::calcStochShift| templated code@>;
|
|
|
|
void switchToFolded();
|
|
|
|
const PartitionY& getPartY() const
|
|
|
|
{@+ return ypart;@+}
|
|
|
|
const FGSContainer& getFoldDers() const
|
|
|
|
{@+ return _fg;@+}
|
|
|
|
const UGSContainer& getUnfoldDers() const
|
|
|
|
{@+ return _ug;@+}
|
|
|
|
static bool is_even(int i)
|
|
|
|
{@+ return (i/2)*2 == i;@+}
|
|
|
|
protected:@;
|
|
|
|
@<|KOrder::insertDerivative| templated code@>;
|
|
|
|
template<int t>
|
|
|
|
void sylvesterSolve(_Ttensor& der) const;
|
|
|
|
|
|
|
|
@<|KOrder::faaDiBrunoZ| templated code@>;
|
|
|
|
@<|KOrder::faaDiBrunoG| templated code@>;
|
|
|
|
|
|
|
|
@<|KOrder::recover_y| templated code@>;
|
|
|
|
@<|KOrder::recover_yu| templated code@>;
|
|
|
|
@<|KOrder::recover_ys| templated code@>;
|
|
|
|
@<|KOrder::recover_yus| templated code@>;
|
|
|
|
@<|KOrder::recover_s| templated code@>;
|
|
|
|
@<|KOrder::fillG| templated code@>;
|
|
|
|
|
|
|
|
@<|KOrder::calcD_ijk| templated code@>;
|
|
|
|
@<|KOrder::calcD_ik| templated code@>;
|
|
|
|
@<|KOrder::calcD_k| templated code@>;
|
|
|
|
|
|
|
|
@<|KOrder::calcE_ijk| templated code@>;
|
|
|
|
@<|KOrder::calcE_ik| templated code@>;
|
|
|
|
@<|KOrder::calcE_k| templated code@>;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ Here we insert the result to the container. Along the insertion, we
|
|
|
|
also create subtensors and insert as well.
|
|
|
|
|
|
|
|
@<|KOrder::insertDerivative| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void insertDerivative(_Ttensor* der)
|
|
|
|
{
|
|
|
|
g<t>().insert(der);
|
|
|
|
gs<t>().insert(new _Ttensor(ypart.nstat, ypart.nys(), *der));
|
|
|
|
gss<t>().insert(new _Ttensor(ypart.nstat+ypart.npred,
|
|
|
|
ypart.nyss(), *der));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ Here we implement Faa Di Bruno formula
|
|
|
|
$$\sum_{l=1}^k\left[f_{z^l}\right]_{\gamma_1\ldots\gamma_l}
|
|
|
|
\sum_{c\in M_{l,k}}\prod_{m=1}^l\left[z_{s(c_m)}\right]^{\gamma_m},
|
|
|
|
$$
|
|
|
|
where $s$ is a given outer symmetry and $k$ is the dimension of the
|
|
|
|
symmetry.
|
|
|
|
|
|
|
|
@<|KOrder::faaDiBrunoZ| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* faaDiBrunoZ(const Symmetry& sym) const
|
|
|
|
{
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Faa Di Bruno Z container for " << sym << endrec;
|
|
|
|
_Ttensor* res = new _Ttensor(ny, TensorDimens(sym, nvs));
|
|
|
|
FaaDiBruno bruno(journal);
|
|
|
|
bruno.calculate(Zstack<t>(), f, *res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ The same as |@<|KOrder::faaDiBrunoZ| templated code@>|, but for
|
|
|
|
$g^{**}$ and $G$ stack.
|
|
|
|
|
|
|
|
@<|KOrder::faaDiBrunoG| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* faaDiBrunoG(const Symmetry& sym) const
|
|
|
|
{
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Faa Di Bruno G container for " << sym << endrec;
|
|
|
|
TensorDimens tdims(sym, nvs);
|
|
|
|
_Ttensor* res = new _Ttensor(ypart.nyss(), tdims);
|
|
|
|
FaaDiBruno bruno(journal);
|
|
|
|
bruno.calculate(Gstack<t>(), gss<t>(), *res);
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we solve $\left[F_{y^i}\right]=0$. First we calculate
|
|
|
|
conditional $G_{y^i}$ (it misses $l=1$ and $l=i$ since $g_{y^i}$ does
|
|
|
|
not exist yet). Then calculate conditional $F_{y^i}$ and we have the
|
|
|
|
right hand side of equation. Since we miss two orders, we solve by
|
|
|
|
Sylvester, and insert the solution as the derivative $g_{y^i}$. Then
|
|
|
|
we need to update $G_{y^i}$ running |multAndAdd| for both dimensions
|
|
|
|
$1$ and $i$.
|
|
|
|
|
|
|
|
{\bf Requires:} everything at order $\leq i-1$
|
|
|
|
|
|
|
|
{\bf Provides:} $g_{y^i}$, and $G_{y^i}$
|
|
|
|
|
|
|
|
@<|KOrder::recover_y| templated code@>=
|
|
|
|
template<int t>
|
|
|
|
void recover_y(int i)
|
|
|
|
{
|
|
|
|
Symmetry sym(i,0,0,0);
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Recovering symmetry " << sym << endrec;
|
|
|
|
|
|
|
|
_Ttensor* G_yi = faaDiBrunoG<t>(sym);
|
|
|
|
G<t>().insert(G_yi);
|
|
|
|
|
|
|
|
_Ttensor* g_yi = faaDiBrunoZ<t>(sym);
|
|
|
|
g_yi->mult(-1.0);
|
|
|
|
|
|
|
|
sylvesterSolve<t>(*g_yi);
|
|
|
|
|
|
|
|
insertDerivative<t>(g_yi);
|
|
|
|
|
|
|
|
_Ttensor* gss_y = gss<t>().get(Symmetry(1,0,0,0));
|
|
|
|
gs<t>().multAndAdd(*gss_y, *G_yi);
|
|
|
|
_Ttensor* gss_yi = gss<t>().get(sym);
|
|
|
|
gs<t>().multAndAdd(*gss_yi, *G_yi);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ Here we solve $\left[F_{y^iu^j}\right]=0$ to obtain $g_{y^iu^j}$ for
|
|
|
|
$j>0$. We calculate conditional $G_{y^iu^j}$ (this misses only $l=1$)
|
|
|
|
and calculate conditional $F_{y^iu^j}$ and we have the right hand
|
|
|
|
side. It is solved by multiplication of inversion of $A$. Then we insert
|
|
|
|
the result, and update $G_{y^iu^j}$ by |multAndAdd| for $l=1$.
|
|
|
|
|
|
|
|
{\bf Requires:} everything at order $\leq i+j-1$, $G_{y^{i+j}}$, and
|
|
|
|
$g_{y^{i+j}}$.
|
|
|
|
|
|
|
|
{\bf Provides:} $g_{y^iu^j}$, and $G_{y^iu^j}$
|
|
|
|
|
|
|
|
@<|KOrder::recover_yu| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void recover_yu(int i, int j)
|
|
|
|
{
|
|
|
|
Symmetry sym(i,j,0,0);
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Recovering symmetry " << sym << endrec;
|
|
|
|
|
|
|
|
_Ttensor* G_yiuj = faaDiBrunoG<t>(sym);
|
|
|
|
G<t>().insert(G_yiuj);
|
|
|
|
|
|
|
|
_Ttensor* g_yiuj = faaDiBrunoZ<t>(sym);
|
|
|
|
g_yiuj->mult(-1.0);
|
|
|
|
matA.multInv(*g_yiuj);
|
|
|
|
insertDerivative<t>(g_yiuj);
|
|
|
|
|
|
|
|
gs<t>().multAndAdd(*(gss<t>().get(Symmetry(1,0,0,0))), *G_yiuj);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we solve
|
|
|
|
$\left[F_{y^i\sigma^j}\right]+\left[D_{ij}\right]+\left[E_{ij}\right]=0$
|
|
|
|
to obtain $g_{y^i\sigma^j}$. We calculate conditional
|
|
|
|
$G_{y^i\sigma^j}$ (missing dimensions $1$ and $i+j$), calculate
|
|
|
|
conditional $F_{y^i\sigma^j}$. Before we can calculate $D_{ij}$ and
|
|
|
|
$E_{ij}$, we have to calculate $G_{y^iu'^m\sigma^{j-m}}$ for
|
|
|
|
$m=1,\ldots,j$. Then we add the $D_{ij}$ and $E_{ij}$ to obtain the
|
|
|
|
right hand side. Then we solve the sylvester to obtain
|
|
|
|
$g_{y^i\sigma^j}$. Then we update $G_{y^i\sigma^j}$ for $l=1$ and
|
|
|
|
$l=i+j$.
|
|
|
|
|
|
|
|
{\bf Requires:} everything at order $\leq i+j-1$, $g_{y^{i+j}}$,
|
|
|
|
$G_{y^iu'^j}$ and $g_{y^iu^j}$ through $D_{ij}$,
|
|
|
|
$g_{y^iu^m\sigma^{j-m}}$ for
|
|
|
|
$m=1,\ldots,j-1$ through $E_{ij}$.
|
|
|
|
|
|
|
|
{\bf Provides:} $g_{y^i\sigma^j}$ and $G_{y^i\sigma^j}$, and finally
|
|
|
|
$G_{y^iu'^m\sigma^{j-m}}$ for $m=1,\ldots,j$. The latter is calculated
|
|
|
|
by |fillG| before the actual calculation.
|
|
|
|
|
|
|
|
@<|KOrder::recover_ys| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void recover_ys(int i, int j)
|
|
|
|
{
|
|
|
|
Symmetry sym(i,0,0,j);
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Recovering symmetry " << sym << endrec;
|
|
|
|
|
|
|
|
fillG<t>(i, 0, j);
|
|
|
|
|
|
|
|
if (is_even(j)) {
|
|
|
|
_Ttensor* G_yisj = faaDiBrunoG<t>(sym);
|
|
|
|
G<t>().insert(G_yisj);
|
|
|
|
|
|
|
|
_Ttensor* g_yisj = faaDiBrunoZ<t>(sym);
|
|
|
|
|
|
|
|
{
|
|
|
|
_Ttensor* D_ij = calcD_ik<t>(i, j);
|
|
|
|
g_yisj->add(1.0, *D_ij);
|
|
|
|
delete D_ij;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (j >= 3) {
|
|
|
|
_Ttensor* E_ij = calcE_ik<t>(i, j);
|
|
|
|
g_yisj->add(1.0, *E_ij);
|
|
|
|
delete E_ij;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_yisj->mult(-1.0);
|
|
|
|
|
|
|
|
sylvesterSolve<t>(*g_yisj);
|
|
|
|
|
|
|
|
insertDerivative<t>(g_yisj);
|
|
|
|
|
|
|
|
Gstack<t>().multAndAdd(1, gss<t>(), *G_yisj);
|
|
|
|
Gstack<t>().multAndAdd(i+j, gss<t>(), *G_yisj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we solve
|
|
|
|
$\left[F_{y^iu^j\sigma^k}\right]+\left[D_{ijk}\right]+\left[E_{ijk}\right]=0$
|
|
|
|
to obtain $g_{y^iu^j\sigma^k}$. First we calculate conditional
|
|
|
|
$G_{y^iu^j\sigma^k}$ (missing only for dimension $l=1$), then we
|
|
|
|
evaluate conditional $F_{y^iu^j\sigma^k}$. Before we can calculate
|
|
|
|
$D_{ijk}$, and $E_{ijk}$, we need to insert
|
|
|
|
$G_{y^iu^ju'^m\sigma^{k-m}}$ for $m=1,\ldots, k$. This is done by
|
|
|
|
|fillG|. Then we have right hand side and we multiply by $A^{-1}$ to
|
|
|
|
obtain $g_{y^iu^j\sigma^k}$. Finally we have to update
|
|
|
|
$G_{y^iu^j\sigma^k}$ by |multAndAdd| for dimension $l=1$.
|
|
|
|
|
|
|
|
{\bf Requires:} everything at order $\leq i+j+k$, $g_{y^{i+j}\sigma^k}$
|
|
|
|
through $G_{y^iu^j\sigma^k}$ involved in right hand side, then
|
|
|
|
$g_{y^iu^{j+k}}$ through $D_{ijk}$, and $g_{y^iu^{j+m}\sigma^{k-m}}$
|
|
|
|
for $m=1,\ldots,k-1$ through $E_{ijk}$.
|
|
|
|
|
|
|
|
{\bf Provides:} $g_{y^iu^j\sigma^k}$, $G_{y^iu^j\sigma^k}$, and
|
|
|
|
$G_{y^iu^ju'^m\sigma^{k-m}}$ for $m=1,\ldots, k$
|
|
|
|
|
|
|
|
@<|KOrder::recover_yus| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void recover_yus(int i, int j, int k)
|
|
|
|
{
|
|
|
|
Symmetry sym(i,j,0,k);
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Recovering symmetry " << sym << endrec;
|
|
|
|
|
|
|
|
fillG<t>(i, j, k);
|
|
|
|
|
|
|
|
if (is_even(k)) {
|
|
|
|
_Ttensor* G_yiujsk = faaDiBrunoG<t>(sym);
|
|
|
|
G<t>().insert(G_yiujsk);
|
|
|
|
|
|
|
|
_Ttensor* g_yiujsk = faaDiBrunoZ<t>(sym);
|
|
|
|
|
|
|
|
{
|
|
|
|
_Ttensor* D_ijk = calcD_ijk<t>(i,j,k);
|
|
|
|
g_yiujsk->add(1.0, *D_ijk);
|
|
|
|
delete D_ijk;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (k >= 3) {
|
|
|
|
_Ttensor* E_ijk = calcE_ijk<t>(i,j,k);
|
|
|
|
g_yiujsk->add(1.0, *E_ijk);
|
|
|
|
delete E_ijk;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_yiujsk->mult(-1.0);
|
|
|
|
|
|
|
|
matA.multInv(*g_yiujsk);
|
|
|
|
insertDerivative<t>(g_yiujsk);
|
|
|
|
|
|
|
|
Gstack<t>().multAndAdd(1, gss<t>(), *G_yiujsk);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we solve
|
|
|
|
$\left[F_{\sigma^i}\right]+\left[D_i\right]+\left[E_i\right]=0$ to
|
|
|
|
recover $g_{\sigma^i}$. First we calculate conditional $G_{\sigma^i}$
|
|
|
|
(missing dimension $l=1$ and $l=i$), then we calculate conditional
|
|
|
|
$F_{\sigma^i}$. Before we can calculate $D_i$ and $E_i$, we have to
|
|
|
|
obtain $G_{u'm\sigma^{i-m}}$ for $m=1,\ldots,i$. Than
|
|
|
|
adding $D_i$ and $E_i$ we have the right hand side. We solve by
|
|
|
|
$S^{-1}$ multiplication and update $G_{\sigma^i}$ by calling
|
|
|
|
|multAndAdd| for dimension $l=1$.
|
|
|
|
|
|
|
|
Recall that the solved equation here is:
|
|
|
|
$$
|
|
|
|
\left[f_y\right]\left[g_{\sigma^k}\right]+
|
|
|
|
\left[f_{y^{**}_+}\right]\left[g^{**}_{y^*}\right]\left[g^*_{\sigma^k}\right]+
|
|
|
|
\left[f_{y^{**}_+}\right]\left[g^{**}_{\sigma^k}\right]=\hbox{RHS}
|
|
|
|
$$
|
|
|
|
This is a sort of deficient sylvester equation (sylvester equation for
|
|
|
|
dimension=0), we solve it by $S^{-1}$. See |@<|MatrixS| constructor
|
|
|
|
code@>| to see how $S$ looks like.
|
|
|
|
|
|
|
|
{\bf Requires:} everything at order $\leq i-1$, $g_{y^i}$ and
|
|
|
|
$g_{y^{i-j}\sigma^j}$, then $g_{u^k}$ through $F_{u'^k}$, and
|
|
|
|
$g_{y^mu^j\sigma^k}$ for $j=1,\ldots,i-1$ and $m+j+k=i$ through
|
|
|
|
$F_{u'j\sigma^{i-j}}$.
|
|
|
|
|
|
|
|
{\bf Provides:} $g_{\sigma^i}$, $G_{\sigma^i}$, and
|
|
|
|
$G_{u'^m\sigma^{i-m}}$ for $m=1,\ldots,i$
|
|
|
|
|
|
|
|
@<|KOrder::recover_s| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void recover_s(int i)
|
|
|
|
{
|
|
|
|
Symmetry sym(0,0,0,i);
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Recovering symmetry " << sym << endrec;
|
|
|
|
|
|
|
|
fillG<t>(0, 0, i);
|
|
|
|
|
|
|
|
if (is_even(i)) {
|
|
|
|
_Ttensor* G_si = faaDiBrunoG<t>(sym);
|
|
|
|
G<t>().insert(G_si);
|
|
|
|
|
|
|
|
_Ttensor* g_si = faaDiBrunoZ<t>(sym);
|
|
|
|
|
|
|
|
{
|
|
|
|
_Ttensor* D_i = calcD_k<t>(i);
|
|
|
|
g_si->add(1.0, *D_i);
|
|
|
|
delete D_i;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= 3) {
|
|
|
|
_Ttensor* E_i = calcE_k<t>(i);
|
|
|
|
g_si->add(1.0, *E_i);
|
|
|
|
delete E_i;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_si->mult(-1.0);
|
|
|
|
|
|
|
|
|
|
|
|
matS.multInv(*g_si);
|
|
|
|
insertDerivative<t>(g_si);
|
|
|
|
|
|
|
|
Gstack<t>().multAndAdd(1, gss<t>(), *G_si);
|
|
|
|
Gstack<t>().multAndAdd(i, gss<t>(), *G_si);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we calculate and insert $G_{y^iu^ju'^m\sigma^{k-m}}$ for
|
|
|
|
$m=1,\ldots, k$. The derivatives are inserted only for $k-m$ being
|
|
|
|
even.
|
|
|
|
|
|
|
|
@<|KOrder::fillG| templated code@>=
|
|
|
|
template<int t>
|
|
|
|
void fillG(int i, int j, int k)
|
|
|
|
{
|
|
|
|
for (int m = 1; m <= k; m++) {
|
|
|
|
if (is_even(k-m)) {
|
|
|
|
_Ttensor* G_yiujupms = faaDiBrunoG<t>(Symmetry(i,j,m,k-m));
|
|
|
|
G<t>().insert(G_yiujupms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ Here we calculate
|
|
|
|
$$\left[D_{ijk}\right]_{\alpha_1\ldots\alpha_i\beta_1\ldots\beta_j}=
|
|
|
|
\left[F_{y^iu^ju'^k}\right]
|
|
|
|
_{\alpha_1\ldots\alpha_i\beta_1\ldots\beta_j\gamma_1\ldots\gamma_k}
|
|
|
|
\left[\Sigma\right]^{\gamma_1\ldots\gamma_k}$$
|
|
|
|
So it is non zero only for even $k$.
|
|
|
|
|
|
|
|
@<|KOrder::calcD_ijk| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcD_ijk(int i, int j, int k) const
|
|
|
|
{
|
|
|
|
_Ttensor* res = new _Ttensor(ny, TensorDimens(Symmetry(i,j,0,0), nvs));
|
|
|
|
res->zeros();
|
|
|
|
if (is_even(k)) {
|
|
|
|
_Ttensor* tmp = faaDiBrunoZ<t>(Symmetry(i,j,k,0));
|
|
|
|
tmp->contractAndAdd(2, *res, *(m<t>().get(Symmetry(k))));
|
|
|
|
delete tmp;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ Here we calculate
|
|
|
|
$$\left[E_{ijk}\right]_{\alpha_1\ldots\alpha_i\beta_1\ldots\beta_j}=
|
|
|
|
\sum_{m=1}^{k-1}\left(\matrix{k\cr m}\right)\left[F_{y^iu^ju'^m\sigma^{k-m}}\right]
|
|
|
|
_{\alpha_1\ldots\alpha_i\beta_1\ldots\beta_j\gamma_1\ldots\gamma_m}
|
|
|
|
\left[\Sigma\right]^{\gamma_1\ldots\gamma_m}$$
|
|
|
|
The sum can sum only for even $m$.
|
|
|
|
|
|
|
|
@<|KOrder::calcE_ijk| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcE_ijk(int i, int j, int k) const
|
|
|
|
{
|
|
|
|
_Ttensor* res = new _Ttensor(ny, TensorDimens(Symmetry(i,j,0,0), nvs));
|
|
|
|
res->zeros();
|
|
|
|
for (int n = 2; n <= k-1; n+=2) {
|
|
|
|
_Ttensor* tmp = faaDiBrunoZ<t>(Symmetry(i,j,n,k-n));
|
|
|
|
tmp->mult((double)(Tensor::noverk(k,n)));
|
|
|
|
tmp->contractAndAdd(2, *res, *(m<t>().get(Symmetry(n))));
|
|
|
|
delete tmp;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
@
|
|
|
|
@<|KOrder::calcD_ik| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcD_ik(int i, int k) const
|
|
|
|
{
|
|
|
|
return calcD_ijk<t>(i, 0, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
@
|
|
|
|
@<|KOrder::calcD_k| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcD_k(int k) const
|
|
|
|
{
|
|
|
|
return calcD_ijk<t>(0, 0, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
@
|
|
|
|
@<|KOrder::calcE_ik| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcE_ik(int i, int k) const
|
|
|
|
{
|
|
|
|
return calcE_ijk<t>(i, 0, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
@
|
|
|
|
@<|KOrder::calcE_k| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
_Ttensor* calcE_k(int k) const
|
|
|
|
{
|
|
|
|
return calcE_ijk<t>(0, 0, k);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here is the core routine. It calls methods recovering derivatives in
|
|
|
|
the right order. Recall, that the code, namely Faa Di Bruno's formula,
|
|
|
|
is implemented as to be run conditionally on the current contents of
|
|
|
|
containers. So, if some call of Faa Di Bruno evaluates derivatives,
|
|
|
|
and some derivatives are not present in the container, then it is
|
|
|
|
considered to be zero. So, we have to be very careful to put
|
|
|
|
everything in the right order. The order here can be derived from
|
|
|
|
dependencies, or it is in the paper.
|
|
|
|
|
|
|
|
The method recovers all the derivatives of the given |order|.
|
|
|
|
|
|
|
|
The precondition of the method is that all tensors of order |order-1|,
|
|
|
|
which are not zero, exist (including $G$). The postcondition of of the
|
|
|
|
method is derivatives of $g$ and $G$ of order |order| are calculated
|
|
|
|
and stored in the containers. Responsibility of precondition lays upon
|
|
|
|
the constructor (for |order==2|), or upon the previous call of
|
|
|
|
|performStep|.
|
|
|
|
|
|
|
|
From the code, it is clear, that all $g$ are calculated. If one goes
|
|
|
|
through all the recovering methods, he should find out that also all
|
|
|
|
$G$ are provided.
|
|
|
|
|
|
|
|
@<|KOrder::performStep| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
void performStep(int order)
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(order-1 != g<t>().getMaxDim(),
|
|
|
|
"Wrong order for KOrder::performStep");
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Performing step for order = " << order << endrec;
|
|
|
|
|
|
|
|
recover_y<t>(order);
|
|
|
|
|
|
|
|
for (int i = 0; i < order; i++) {
|
|
|
|
recover_yu<t>(i, order-i);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int j = 1; j < order; j++) {
|
|
|
|
for (int i = j-1; i >= 1; i--) {
|
|
|
|
recover_yus<t>(order-j,i,j-i);
|
|
|
|
}
|
|
|
|
recover_ys<t>(order-j, j);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int i = order-1; i >= 1; i--) {
|
|
|
|
recover_yus<t>(0, i, order-i);
|
|
|
|
}
|
|
|
|
recover_s<t>(order);
|
|
|
|
}
|
|
|
|
|
|
|
|
@ Here we check for residuals of all the solved equations at the given
|
|
|
|
order. The method returns the largest residual size. Each check simply
|
|
|
|
evaluates the equation.
|
|
|
|
|
|
|
|
@<|KOrder::check| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
double check(int dim) const
|
|
|
|
{
|
|
|
|
KORD_RAISE_IF(dim > g<t>().getMaxDim(),
|
|
|
|
"Wrong dimension for KOrder::check");
|
|
|
|
JournalRecordPair pa(journal);
|
|
|
|
pa << "Checking residuals for order = " << dim << endrec;
|
|
|
|
|
|
|
|
double maxerror = 0.0;
|
|
|
|
|
|
|
|
@<check for $F_{y^iu^j}=0$@>;
|
|
|
|
@<check for $F_{y^iu^ju'^k}+D_{ijk}+E_{ijk}=0$@>;@q'@>
|
|
|
|
@<check for $F_{\sigma^i}+D_i+E_i=0$@>;
|
|
|
|
|
|
|
|
return maxerror;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@
|
|
|
|
@<check for $F_{y^iu^j}=0$@>=
|
|
|
|
for (int i = 0; i <= dim; i++) {
|
|
|
|
Symmetry sym(dim-i, i, 0, 0);
|
|
|
|
_Ttensor* r = faaDiBrunoZ<t>(sym);
|
|
|
|
double err = r->getData().getMax();
|
|
|
|
JournalRecord(journal) << "\terror for symmetry " << sym << "\tis " << err << endrec;
|
|
|
|
if (err > maxerror)
|
|
|
|
maxerror = err;
|
|
|
|
delete r;
|
|
|
|
}
|
|
|
|
|
|
|
|
@
|
|
|
|
@<check for $F_{y^iu^ju'^k}+D_{ijk}+E_{ijk}=0$@>=
|
|
|
|
SymmetrySet ss(dim, 3);
|
|
|
|
for (symiterator si(ss); !si.isEnd(); ++si) {
|
|
|
|
int i = (*si)[0];
|
|
|
|
int j = (*si)[1];
|
|
|
|
int k = (*si)[2];
|
|
|
|
if (i+j > 0 && k > 0) {
|
|
|
|
Symmetry sym(i, j, 0, k);
|
|
|
|
_Ttensor* r = faaDiBrunoZ<t>(sym);
|
|
|
|
_Ttensor* D_ijk = calcD_ijk<t>(i,j,k);
|
|
|
|
r->add(1.0, *D_ijk);
|
|
|
|
delete D_ijk;
|
|
|
|
_Ttensor* E_ijk = calcE_ijk<t>(i,j,k);
|
|
|
|
r->add(1.0, *E_ijk);
|
|
|
|
delete E_ijk;
|
|
|
|
double err = r->getData().getMax();
|
|
|
|
JournalRecord(journal) << "\terror for symmetry " << sym << "\tis " << err << endrec;
|
|
|
|
delete r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@
|
|
|
|
@<check for $F_{\sigma^i}+D_i+E_i=0$@>=
|
|
|
|
_Ttensor* r = faaDiBrunoZ<t>(Symmetry(0,0,0,dim));
|
|
|
|
_Ttensor* D_k = calcD_k<t>(dim);
|
|
|
|
r->add(1.0, *D_k);
|
|
|
|
delete D_k;
|
|
|
|
_Ttensor* E_k = calcE_k<t>(dim);
|
|
|
|
r->add(1.0, *E_k);
|
|
|
|
delete E_k;
|
|
|
|
double err = r->getData().getMax();
|
|
|
|
Symmetry sym(0,0,0,dim);
|
|
|
|
JournalRecord(journal) << "\terror for symmetry " << sym << "\tis " << err << endrec;
|
|
|
|
if (err > maxerror)
|
|
|
|
maxerror = err;
|
|
|
|
delete r;
|
|
|
|
|
|
|
|
@
|
|
|
|
@<|KOrder::calcStochShift| templated code@>=
|
|
|
|
template <int t>
|
|
|
|
Vector* calcStochShift(int order, double sigma) const
|
|
|
|
{
|
|
|
|
Vector* res = new Vector(ny);
|
|
|
|
res->zeros();
|
|
|
|
int jfac = 1;
|
|
|
|
for (int j = 1; j <= order; j++, jfac *= j)
|
|
|
|
if (is_even(j)) {
|
|
|
|
_Ttensor* ten = calcD_k<t>(j);
|
|
|
|
res->add(std::pow(sigma, j)/jfac, ten->getData());
|
|
|
|
delete ten;
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ These are containers. The names are not important because they do
|
|
|
|
not appear anywhere else since we access them by template functions.
|
|
|
|
|
|
|
|
@<|KOrder| container members@>=
|
|
|
|
UGSContainer _ug;
|
|
|
|
FGSContainer _fg;
|
|
|
|
UGSContainer _ugs;
|
|
|
|
FGSContainer _fgs;
|
|
|
|
UGSContainer _ugss;
|
|
|
|
FGSContainer _fgss;
|
|
|
|
UGSContainer _uG;
|
|
|
|
FGSContainer _fG;
|
|
|
|
UnfoldedZContainer _uZstack;
|
|
|
|
FoldedZContainer _fZstack;
|
|
|
|
UnfoldedGContainer _uGstack;
|
|
|
|
FoldedGContainer _fGstack;
|
|
|
|
UNormalMoments _um;
|
|
|
|
FNormalMoments _fm;
|
|
|
|
const TensorContainer<FSSparseTensor>& f;
|
|
|
|
|
|
|
|
@ These are the declarations of the template functions accessing the
|
|
|
|
containers.
|
|
|
|
|
|
|
|
@<|KOrder| member access method declarations@>=
|
|
|
|
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> _Tgss& gss();
|
|
|
|
template<int t> const _Tgss& gss() const;
|
|
|
|
template<int t> _TG& G();
|
|
|
|
template<int t> const _TG& G() const;
|
|
|
|
template<int t> _TZstack& Zstack();
|
|
|
|
template<int t> const _TZstack& Zstack() const;
|
|
|
|
template<int t> _TGstack& Gstack();
|
|
|
|
template<int t> const _TGstack& Gstack() const;
|
2009-10-30 19:19:42 +01:00
|
|
|
template<int t> __Tm& m();
|
|
|
|
template<int t> const __Tm& m() const;
|
2009-09-08 15:55:19 +02:00
|
|
|
|
|
|
|
|
|
|
|
@ End of {\tt korder.h} file.
|