1 /*
2  * Copyright © 2004 Ondra Kamenik
3  * Copyright © 2019 Dynare Team
4  *
5  * This file is part of Dynare.
6  *
7  * Dynare is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Dynare is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with Dynare.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 // Multiplying tensor columns.
22 
23 /* In here, we implement the Faà Di Bruno for folded
24    tensors. Recall, that one step of the Faà Di Bruno is a formula:
25 
26 27     [B_sᵏ]_α₁…αₗ = [h_yˡ]_γ₁…γₗ  ∏  [g_{s^|cₘ|}]_cₘ(α)^γₘ
28                                 ᵐ⁼¹
29 
30    In contrast to unfolded implementation of UGSContainer::multAndAdd()
31    with help of KronProdAll and UPSTensor, we take a completely
32    different strategy. We cannot afford full instantiation of
33 
34 35        ∑     ∏  [g_{s^|cₘ|}]_cₘ(α)^γₘ
36     c∈ℳₗ,ₖ ᵐ⁼¹
37 
38    and therefore we do it per partes. We select some number of columns,
39    for instance 10, calculate 10 continuous iterators of tensor B. Then we
40    form unfolded tensor
41 
42                   ⎡         ₗ                       ⎤
43     [G]_S^γ₁…γₗ = ⎢   ∑     ∏  [g_{s^|cₘ|}]_cₘ(α)^γₘ⎥
44                   ⎣c∈ℳₗ,ₖ ᵐ⁼¹                       ⎦_S
45 
46    where S is the selected set of 10 indices. This is done as Kronecker
47    product of vectors corresponding to selected columns. Note that, in
48    general, there is no symmetry in G, its type is special class for
49    this purpose.
50 
51    If g is folded, then we have to form the folded version of G. There is
52    no symmetry in G data, so we sum all unfolded indices corresponding
53    to folded index together. This is perfectly OK, since we multiply
54    these groups of (equivalent) items with the same number in fully
55    symmetric g.
56 
57    After this, we perform ordinary matrix multiplication to obtain a
58    selected set of columns of B.
59 
60    In here, we define a class for forming and representing [G]_S^γ₁…γₗ.
61    Basically, this tensor is row-oriented (multidimensional index is along
62    rows), and it is fully symmetric. So we inherit from URTensor. If we need
63    its folded version, we simply use a suitable conversion. The new abstraction
64    will have only a new constructor allowing a construction from the given set
65    of indices S, and given set of tensors g. The rest of the process is
66    implemented in FGSContainer::multAndAdd() unfolded code or
67    FGSContainer::multAndAdd() folded code. */
68 
69 #ifndef PYRAMID_PROD_H
70 #define PYRAMID_PROD_H
71 
72 #include "int_sequence.hh"
73 #include "rfs_tensor.hh"
74 #include "gs_tensor.hh"
75 #include "t_container.hh"
76 
77 #include <vector>
78 
79 /* Here we define the new tensor for representing [G]_S^γ₁…γₗ. It allows a
80    construction from container of folded general symmetry tensors ‘cont’, and
81    set of indices ‘ts’. Also we have to supply dimensions of resulting tensor
82    B, and dimensions of tensor h. */
83 
84 class USubTensor : public URTensor
85 {
86 public:
87   USubTensor(const TensorDimens &bdims, const TensorDimens &hdims,
88              const FGSContainer &cont, const std::vector<IntSequence> &lst);
89   void addKronColumn(int i, const std::vector<const FGSTensor *> &ts,
90                      const IntSequence &pindex);
91 };
92 
93 #endif
94