Dynare++: improvements to comments

[skip ci]
time-shift
Sébastien Villemot 2019-04-05 18:39:47 +02:00
parent bdc95f23aa
commit e67c172000
No known key found for this signature in database
GPG Key ID: 2CECE9350ECEBE4A
5 changed files with 125 additions and 141 deletions

View File

@ -4,17 +4,16 @@
#include "permutation.hh" #include "permutation.hh"
#include "tl_exception.hh" #include "tl_exception.hh"
/* Here we construct the |USubTensor| object. We allocate space via the /* Here we construct the USubTensor object. We allocate space via the parent
parent |URTensor|. Number of columns is a length of the list of URTensor. Number of columns is a length of the list of indices lst, number
indices |lst|, number of variables and dimensions are of the tensor of variables and dimensions are of the tensor $h$, this is given by hdims.
$h$, this is given by |hdims|.
We go through all equivalences with number of classes equal to We go through all equivalences with number of classes equal to dimension of
dimension of $B$. For each equivalence we make a permutation B. For each equivalence we make a permutation per. Then we fetch all the
|per|. Then we fetch all the necessary tensors $g$ with symmetries necessary tensors g with symmetries implied by symmetry of B and the
implied by symmetry of $B$ and the equivalence. Then we go through the equivalence. Then we go through the list of indices, permute them by the
list of indices, permute them by the permutation and add the Kronecker permutation and add the Kronecker product of the selected columns. This is
product of the selected columns. This is done by |addKronColumn|. */ done by addKronColumn(). */
USubTensor::USubTensor(const TensorDimens &bdims, USubTensor::USubTensor(const TensorDimens &bdims,
const TensorDimens &hdims, const TensorDimens &hdims,
@ -43,19 +42,18 @@ USubTensor::USubTensor(const TensorDimens &bdims,
} }
} }
/* This makes a Kronecker product of appropriate columns from tensors /* This makes a Kronecker product of appropriate columns from tensors in fs
in |fs| and adds such data to |i|-th column of this matrix. The and adds such data to i-th column of this matrix. The appropriate columns
appropriate columns are defined by |pindex| sequence. A column of a are defined by pindex sequence. A column of a tensor has index created
tensor has index created from a corresponding part of |pindex|. The from a corresponding part of pindex. The sizes of these parts are given by
sizes of these parts are given by dimensions of the tensors in |ts|. dimensions of the tensors in ts.
Here we break the given index |pindex| according to the dimensions of Here we break the given index pindex according to the dimensions of the
the tensors in |ts|, and for each subsequence of the |pindex| we find tensors in ts, and for each subsequence of the pindex we find an index
an index of the folded tensor, which involves calling |getOffset| for of the folded tensor, which involves calling getOffset() for folded tensor,
folded tensor, which might be costly. We gather all columns to a which might be costly. We gather all columns to a vector tmpcols which are
vector |tmpcols| which are Kronecker multiplied in constructor of Kronecker multiplied in constructor of URSingleTensor. Finally we add data
|URSingleTensor|. Finally we add data of |URSingleTensor| to the of URSingleTensor to the i-th column. */
|i|-th column. */
void void
USubTensor::addKronColumn(int i, const std::vector<const FGSTensor *> &ts, USubTensor::addKronColumn(int i, const std::vector<const FGSTensor *> &ts,

View File

@ -4,45 +4,49 @@
/* In here, we implement the Faà Di Bruno for folded /* In here, we implement the Faà Di Bruno for folded
tensors. Recall, that one step of the Faà Di Bruno is a formula: tensors. Recall, that one step of the Faà Di Bruno is a formula:
$$\left[B_{s^k}\right]_{\alpha_1\ldots\alpha_k}=
[h_{y^l}]_{\gamma_1\ldots\gamma_l}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}
$$
In contrast to unfolded implementation of |UGSContainer::multAndAdd|
with help of |KronProdAll| and |UPSTensor|, we take a completely [B_s]_αα = [h_yˡ]_γγ [g_(s^|c|)]_c(α)^γ
¹
In contrast to unfolded implementation of UGSContainer::multAndAdd()
with help of KronProdAll and UPSTensor, we take a completely
different strategy. We cannot afford full instantiation of different strategy. We cannot afford full instantiation of
$$\sum_{c\in M_{l,k}}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}$$
[g_(s^|c|)]_c(α)^γ
c, ¹
and therefore we do it per partes. We select some number of columns, and therefore we do it per partes. We select some number of columns,
for instance 10, calculate 10 continuous iterators of tensor $B$. Then we for instance 10, calculate 10 continuous iterators of tensor B. Then we
form unfolded tensor form unfolded tensor
$$[G]_S^{\gamma_1\ldots\gamma_l}=\left[\sum_{c\in M_{l,k}}
\prod_{m=1}^l\left[g_{s^{\vert c_m\vert}}\right]^{\gamma_m}_{c_m(\alpha)}
\right]_S$$ [G]_S^γγ = [g_(s^|c|)]_c(α)^γ
where $S$ is the selected set of 10 indices. This is done as Kronecker c, ¹ _S
where S is the selected set of 10 indices. This is done as Kronecker
product of vectors corresponding to selected columns. Note that, in product of vectors corresponding to selected columns. Note that, in
general, there is no symmetry in $G$, its type is special class for general, there is no symmetry in G, its type is special class for
this purpose. this purpose.
If $g$ is folded, then we have to form folded version of $G$. There is If g is folded, then we have to form the folded version of G. There is
no symmetry in $G$ data, so we sum all unfolded indices corresponding no symmetry in G data, so we sum all unfolded indices corresponding
to folded index together. This is perfectly OK, since we multiply to folded index together. This is perfectly OK, since we multiply
these groups of (equivalent) items with the same number in fully these groups of (equivalent) items with the same number in fully
symmetric $g$. symmetric g.
After this, we perform ordinary matrix multiplication to obtain a After this, we perform ordinary matrix multiplication to obtain a
selected set of columns of $B$. selected set of columns of B.
In here, we define a class for forming and representing In here, we define a class for forming and representing [G]_S^γγ.
$[G]_S^{\gamma_1\ldots\gamma_l}$. Basically, this tensor is Basically, this tensor is row-oriented (multidimensional index is along
row-oriented (multidimensional index is along rows), and it is fully rows), and it is fully symmetric. So we inherit from URTensor. If we need
symmetric. So we inherit from |URTensor|. If we need its folded its folded version, we simply use a suitable conversion. The new abstraction
version, we simply use a suitable conversion. The new abstraction will will have only a new constructor allowing a construction from the given set
have only a new constructor allowing a construction from the given set of indices S, and given set of tensors g. The rest of the process is
of indices $S$, and given set of tensors $g$. The rest of the process implemented in FGSContainer::multAndAdd() unfolded code or
is implemented in |@<|FGSContainer::multAndAdd| unfolded code@>| or FGSContainer::multAndAdd() folded code. */
|@<|FGSContainer::multAndAdd| folded code@>|. */
#ifndef PYRAMID_PROD_H #ifndef PYRAMID_PROD_H
#define PYRAMID_PROD_H #define PYRAMID_PROD_H
@ -54,11 +58,10 @@
#include <vector> #include <vector>
/* Here we define the new tensor for representing /* Here we define the new tensor for representing [G]_S^γ₁…γₗ. It allows a
$[G]_S^{\gamma_1\ldots\gamma_l}$. It allows a construction from construction from container of folded general symmetry tensors cont, and
container of folded general symmetry tensors |cont|, and set of set of indices ts. Also we have to supply dimensions of resulting tensor
indices |ts|. Also we have to supply dimensions of resulting tensor B, and dimensions of tensor h. */
$B$, and dimensions of tensor $h$. */
class USubTensor : public URTensor class USubTensor : public URTensor
{ {

View File

@ -3,9 +3,9 @@
#include "pyramid_prod2.hh" #include "pyramid_prod2.hh"
#include "rfs_tensor.hh" #include "rfs_tensor.hh"
/* Here we only call |sp.createPackedColumns(c, cols, unit_flag)| which /* Here we only call sp.createPackedColumns(c, cols, unit_flag) which
fills |cols| and |unit_flag| for the given column |c|. Then we set fills cols and unit_flag for the given column c. Then we set
|end_seq| according to |unit_flag| and columns lengths. */ end_seq according to unit_flag and columns lengths. */
IrregTensorHeader::IrregTensorHeader(const StackProduct<FGSTensor> &sp, IrregTensorHeader::IrregTensorHeader(const StackProduct<FGSTensor> &sp,
const IntSequence &c) const IntSequence &c)
@ -36,10 +36,10 @@ IrregTensorHeader::increment(IntSequence &v) const
return; return;
int i = v.size()-1; int i = v.size()-1;
// increment |i|-th item in coordinate |v| // increment i-th item in coordinate v
/* Here we increment item of coordinates. Whenever we reached end of /* Here we increment item of coordinates. Whenever we reached end of
column coming from matrices, and |unit_flag| is not $-1$, we have to column coming from matrices, and unit_flag is not -1, we have to
jump to that |unit_flag|. */ jump to that unit_flag. */
v[i]++; v[i]++;
if (unit_flag[i] != -1 && v[i] == cols[i]->length()-1) if (unit_flag[i] != -1 && v[i] == cols[i]->length()-1)
v[i] = unit_flag[i]; v[i] = unit_flag[i];
@ -48,7 +48,7 @@ IrregTensorHeader::increment(IntSequence &v) const
{ {
v[i] = 0; v[i] = 0;
i--; i--;
// increment |i|-th item in coordinate |v| // increment i-th item in coordinate v
/* Same code as above */ /* Same code as above */
v[i]++; v[i]++;
if (unit_flag[i] != -1 && v[i] == cols[i]->length()-1) if (unit_flag[i] != -1 && v[i] == cols[i]->length()-1)
@ -67,7 +67,7 @@ IrregTensorHeader::calcMaxOffset() const
return res; return res;
} }
/* Everything is done in |IrregTensorHeader|, only we have to Kronecker /* Everything is done in IrregTensorHeader, only we have to Kronecker
multiply all columns of the header. */ multiply all columns of the header. */
IrregTensor::IrregTensor(const IrregTensorHeader &h) IrregTensor::IrregTensor(const IrregTensorHeader &h)

View File

@ -3,67 +3,51 @@
// Multiplying stacked tensor columns. // Multiplying stacked tensor columns.
/* We need to calculate the following tensor product: /* We need to calculate the following tensor product:
$$\left[f_{s^j}\right]_{\alpha_1\ldots\alpha_j}=
\sum_{l=1}^j\left[f_{z^l}\right]_{\beta_1\ldots\beta_l} [f_sʲ]_αα = [f_zˡ]_ββ [z_(s^|c|)]_c(α)^β
\sum_{c\in M_{l,j}}\prod_{m=1}^l\left[z_{c_m}\right]^{\beta_m}_{c_m(\alpha)} ˡ¹ c, ¹
$$ where s=(y,u,u,σ), and z is a composition of four variables, say (v,w,y,u).
where $s=[y,u,u',\sigma]$, and $z$ is a composition of four variables, Note that z ends with y and u, and the only non-zero derivative of the
say $[v,w,y,u]$. Note that $z$ ends with $y$ and $u$, and the only trailing part of z involving y or u is the first derivative and is the unit
non-zero derivative of the trailing part of $z$ involving $y$ or $u$ matrix y_y=(1) or u=(1). Also, we suppose that the dependence of v, and w
is the first derivative and is the unit matrix $y_y=[1]$ or on s is such that whenever derivative of w is nonzero, then also of v. This
$u_u=[1]$. Also, we suppose that the dependence of $v$, and $w$ on $s$ means that there for any derivative and any index there is a continuous part
is such that whenever derivative of $w$ is nonzero, then also of of derivatives of v and optionally of w followed by column of zeros
$v$. This means that there for any derivative and any index there is a containing at most one 1.
continuous part of derivatives of $v$ and optionally of $w$ followed by
column of zeros containing at most one $1$.
This structure can be modelled and exploited with some costs at This structure can be modelled and exploited with some costs at
programming. For example, let us consider the following product: programming. For example, let us consider the following product:
$$\left[B_{y^2u^3}\right]_{\alpha_1\alpha_2\beta_1\beta_2\beta_3}=
\ldots [B_y²u³]_ααβββ = + [f_z³]_γγγ [z_yu]^γ_αβ [z_y]^γ_α [z]^γ_ββ +
\left[f_{z^3}\right]_{\gamma_1\gamma_2\gamma_3}
\left[z_{yu}\right]^{\gamma_1}_{\alpha_1\beta_1} The term corresponds to equivalence { {0,2}, {1}, {3,4} }. For the fixed
\left[z_{y}\right]^{\gamma_2}_{\alpha_2} index ααβββ we have to make a Kronecker product of the columns
\left[z_{uu}\right]^{\gamma_3}_{\beta_2\beta_3}
\ldots$$ [z_yu]_αβ [z_y]_α [z]_ββ
The term corresponds to equivalence $\{\{0,2\},\{1\},\{3,4\}\}$. For
the fixed index $\alpha_1\alpha_2\beta_1\beta_2\beta_3$ we have to which can be written as:
make a Kronecker product of the columns
$$ [v_yu]_αβ [v_y]_α [v]_ββ
\left[z_{yu}\right]_{\alpha_1\beta_1}\otimes [w_yu]_αβ [w_y]_α [w]_ββ
\left[z_{y}\right]_{\alpha_2}\otimes 0 1_α 0
\left[z_{uu}\right]_{\beta_2\beta_3} 0 0 0
$$ where 1_α is a column of zeros having the only 1 at α index.
which can be written as
$$
\left[\matrix{\left[v_{yu}\right]_{\alpha_1\beta_1}\cr
\left[w_{yu}\right]_{\alpha_1\beta_1}\cr 0\cr 0}\right]\otimes
\left[\matrix{\left[v_y\right]_{\alpha_2\vphantom{(}}\cr
\left[w_y\right]_{\alpha_2}\cr 1_{\alpha_2}\cr 0}\right]\otimes
\left[\matrix{\left[v_{uu}\right]_{\beta_2\beta_3\vphantom{(}}\cr
\left[w_{uu}\right]_{\beta_2\beta_3}\cr 0\cr 0}\right]
$$
where $1_{\alpha_2}$ is a column of zeros having the only $1$ at
$\alpha_2$ index.
This file develops the abstraction for this Kronecker product column This file develops the abstraction for this Kronecker product column
without multiplication of the zeros at the top. Basically, it will be without multiplication of the zeros at the top. Basically, it will be
a column which is a Kronecker product of the columns without the a column which is a Kronecker product of the columns without the
zeros: zeros:
$$
\left[\matrix{\left[v_{yu}\right]_{\alpha_1\beta_1}\cr [v_y]_α
\left[w_{yu}\right]_{\alpha_1\beta_1}}\right]\otimes [v_yu]_αβ [w_y]_α[v]_ββ
\left[\matrix{\left[v_y\right]_{\alpha_2}\cr [w_yu]_αβ 1 [w]_ββ
\left[w_y\right]_{\alpha_2}\cr 1}\right]\otimes
\left[\matrix{\left[v_{uu}\right]_{\beta_2\beta_3}\cr The class will have a tensor infrastructure introducing index which
\left[w_{uu}\right]_{\beta_2\beta_3}}\right] iterates over all items in the column with γγγ
$$ as coordinates in [f_z³]. The data of such a tensor is
The class will have a tensor infrastructure introducing |index| which
iterates over all items in the column with $\gamma_1\gamma_2\gamma_3$
as coordinates in $\left[f_{z^3}\right]$. The data of such a tensor is
not suitable for any matrix operation and will have to be accessed not suitable for any matrix operation and will have to be accessed
only through the |index|. Note that this does not matter, since only through the index. Note that this does not matter, since
$\left[f_{z^l}\right]$ are sparse. */ [f_zˡ] are sparse. */
#ifndef PYRAMID_PROD2_H #ifndef PYRAMID_PROD2_H
#define PYRAMID_PROD2_H #define PYRAMID_PROD2_H
@ -80,14 +64,14 @@
/* First we declare a helper class for the tensor. Its purpose is to /* First we declare a helper class for the tensor. Its purpose is to
gather the columns which are going to be Kronecker multiplied. The gather the columns which are going to be Kronecker multiplied. The
input of this helper class is |StackProduct<FGSTensor>| and coordinate input of this helper class is StackProduct<FGSTensor> and coordinate
|c| of the column. c of the column.
It maintains |unit_flag| array which says for what columns we must It maintains unit_flag array which says for what columns we must
stack 1 below $v$ and $w$. In this case, the value of |unit_flag| is stack 1 below v and w. In this case, the value of unit_flag is
an index of the $1$, otherwise the value of |unit_flag| is -1. an index of the 1, otherwise the value of unit_flag is -1.
Also we have storage for the stacked columns |cols|. The object is Also we have storage for the stacked columns cols. The object is
responsible for memory management associated to this storage. That is responsible for memory management associated to this storage. That is
why we do not allow any copy constructor, since we need to be sure why we do not allow any copy constructor, since we need to be sure
that no accidental copies take place. We declare the copy constructor that no accidental copies take place. We declare the copy constructor
@ -112,21 +96,20 @@ public:
int calcMaxOffset() const; int calcMaxOffset() const;
}; };
/* Here we declare the irregular tensor. There is no special logic /* Here we declare the irregular tensor. There is no special logic here. We
here. We inherit from |Tensor| and we must implement three methods, inherit from Tensor and we must implement three methods, increment(),
|increment|, |decrement| and |getOffset|. The last two are not decrement() and getOffset(). The last two are not implemented now, since
implemented now, since they are not needed, and they raise an they are not needed, and they raise an exception. The first just calls
exception. The first just calls |increment| of the header. Also we increment() of the header. Also we declare a method addTo() which adds this
declare a method |addTo| which adds this unfolded irregular single unfolded irregular single column tensor to folded (regular) single column
column tensor to folded (regular) single column tensor. tensor.
The header |IrregTensorHeader| lives with an object by a The header IrregTensorHeader lives with an object by a reference. This is
reference. This is dangerous. However, we will use this class only in dangerous. However, we will use this class only in a simple loop and both
a simple loop and both |IrregTensor| and |IrregTensorHeader| will be IrregTensor and IrregTensorHeader will be destructed at the end of a block.
destructed at the end of a block. Since the super class |Tensor| must Since the super class Tensor must be initialized before any member, we could
be initialized before any member, we could do either a save copy of do either a save copy of IrregTensorHeader, or relatively dangerous the
|IrregTensorHeader|, or relatively dangerous the reference member. For reference member. For the reason above we chose the latter. */
the reason above we chose the latter. */
class IrregTensor : public Tensor class IrregTensor : public Tensor
{ {

View File

@ -5,16 +5,16 @@
/* Here we develop abstractions for stacked containers of tensors. For /* Here we develop abstractions for stacked containers of tensors. For
instance, in perturbation methods for DSGE models, we need the function: instance, in perturbation methods for DSGE models, we need the function:
G(y*,u,u,σ) G(y*,u,u,σ)
z(y*,u,u,σ) = g(y*,u,σ) z(y*,u,u,σ) = g(y*,u,σ)
y* y*
u u
and we need to calculate one step of Faà Di Bruno formula: and we need to calculate one step of Faà Di Bruno formula:
[B_s]_α,,α = [f_zˡ]_β,,β [z_(s^|c|)]_c(α)^β [B_s]_αα = [f_zˡ]_ββ [z_(s^|c|)]_c(α)^β
c, ¹ c, ¹
where we have containers for derivatives of G and g. where we have containers for derivatives of G and g.