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 // Row-wise full symmetry tensor.
22 
23 /* Here we define classes for full symmetry tensors with the multidimensional
24    index identified with rows. The primary usage is for storage of data coming
25    from (or from a sum of)
26 27       ∏  [g_{s^|cₘ|}]_cₘ(α)^γₘ
28      ᵐ⁼¹
29    where α comes from a multidimensional index that goes through some set S,
30    and cₘ is some equivalence class. So we model a tensor of the form:
31 
32      ⎡ ₗ                       ⎤
33      ⎢ ∏  [g_{s^|cₘ|}]_cₘ(α)^γₘ⎥
34      ⎣ᵐ⁼¹                      ⎦S^γ₁…γₗ
35 
36    Since all γ₁…γₗ correspond to the same variable, the tensor is fully
37    symmetric. The set of indices S cannot be very large and sometimes it is
38    only one element. This case is handled in a special subclass.
39 
40    We provide both folded and unfolded versions. Their logic is perfectly the
41    same as in UFSTensor and FFSTensor with two exceptions. One has been already
42    mentioned, the multidimensional index is along the rows. The second are
43    conversions between the two types. Since this kind of tensor is used to
44    multiply (from the right) a tensor whose multidimensional index is
45    identified with columns, we will need a different way of a conversion. If
46    the multiplication of two folded tensors is to be equivalent with
47    multiplication of two unfolded, the folding of the right tensor must sum all
48    equivalent elements since they are multiplied with the same number from the
49    folded tensor. (Equivalent here means all elements of unfolded tensor
50    corresponding to one element in folded tensor.) For this reason, it is
51    necessary to calculate a column number from the given sequence, so we
52    implement getOffset(). Process of unfolding is not used, so we implemented
53    it so that unfolding and then folding a tensor would yield the same data. */
54 
55 #ifndef RFS_TENSOR_H
56 #define RFS_TENSOR_H
57 
58 #include "tensor.hh"
59 #include "fs_tensor.hh"
60 #include "symmetry.hh"
61 
62 /* This is straightforward and very similar to UFSTensor. */
63 
64 class FRTensor;
65 class URTensor : public UTensor
66 {
67   int nv;
68 public:
URTensor(int c,int nvar,int d)69   URTensor(int c, int nvar, int d)
70     : UTensor(indor::along_row, IntSequence(d, nvar),
71               UFSTensor::calcMaxOffset(nvar, d), c, d), nv(nvar)
72   {
73   }
74   URTensor(const URTensor &) = default;
75   URTensor(URTensor &&) = default;
76   explicit URTensor(const FRTensor &ft);
77 
78   ~URTensor() override = default;
79 
80   void increment(IntSequence &v) const override;
81   void decrement(IntSequence &v) const override;
82   std::unique_ptr<FTensor> fold() const override;
83 
84   int getOffset(const IntSequence &v) const override;
85   int
nvar() const86   nvar() const
87   {
88     return nv;
89   }
90   Symmetry
getSym() const91   getSym() const
92   {
93     return Symmetry{dimen()};
94   }
95 };
96 
97 /* This is straightforward and very similar to FFSTensor. */
98 
99 class FRTensor : public FTensor
100 {
101   int nv;
102 public:
FRTensor(int c,int nvar,int d)103   FRTensor(int c, int nvar, int d)
104     : FTensor(indor::along_row, IntSequence(d, nvar),
105               FFSTensor::calcMaxOffset(nvar, d), c, d), nv(nvar)
106   {
107   }
108   FRTensor(const FRTensor &) = default;
109   FRTensor(FRTensor &&) = default;
110   explicit FRTensor(const URTensor &ut);
111 
112   ~FRTensor() override = default;
113 
114   void increment(IntSequence &v) const override;
115   void decrement(IntSequence &v) const override;
116   std::unique_ptr<UTensor> unfold() const override;
117 
118   int
nvar() const119   nvar() const
120   {
121     return nv;
122   }
123   int
getOffset(const IntSequence & v) const124   getOffset(const IntSequence &v) const override
125   {
126     return FTensor::getOffset(v, nv);
127   }
128   Symmetry
getSym() const129   getSym() const
130   {
131     return Symmetry{dimen()};
132   }
133 };
134 
135 /* The following class represents specialization of URTensor coming from
136    Kronecker multiplication of a few vectors. So the resulting row-oriented
137    tensor has one column. We provide two constructors, one constructs the
138    tensor from a few vectors stored as std::vector<ConstVector>. The second
139    makes the Kronecker power of one given vector. */
140 
141 class URSingleTensor : public URTensor
142 {
143 public:
URSingleTensor(int nvar,int d)144   URSingleTensor(int nvar, int d)
145     : URTensor(1, nvar, d)
146   {
147   }
148   URSingleTensor(const std::vector<ConstVector> &cols);
149   URSingleTensor(const ConstVector &v, int d);
150   URSingleTensor(const URSingleTensor &) = default;
151   URSingleTensor(URSingleTensor &&) = default;
152   ~URSingleTensor() override = default;
153   std::unique_ptr<FTensor> fold() const override;
154 };
155 
156 /* This class represents one column row-oriented tensor. The only way to
157    construct it is from URSingleTensor or from scratch. The folding algorithm
158    is the same as folding of general URTensor. Only its implementation is
159    different, since we do not copy rows, but only elements. */
160 
161 class FRSingleTensor : public FRTensor
162 {
163 public:
FRSingleTensor(int nvar,int d)164   FRSingleTensor(int nvar, int d)
165     : FRTensor(1, nvar, d)
166   {
167   }
168   explicit FRSingleTensor(const URSingleTensor &ut);
169   FRSingleTensor(const FRSingleTensor &) = default;
170   FRSingleTensor(FRSingleTensor &&) = default;
171   ~FRSingleTensor() override = default;
172 };
173 
174 #endif
175