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 // Full symmetry tensor.
22 
23 /* Here we define folded and unfolded tensors for full symmetry. All
24    tensors from here are identifying the multidimensional index with
25    columns. */
26 
27 #ifndef FS_TENSOR_H
28 #define FS_TENSOR_H
29 
30 #include "tensor.hh"
31 #include "symmetry.hh"
32 #include "int_power.hh"
33 
34 class FGSTensor;
35 class UGSTensor;
36 class FRSingleTensor;
37 class FSSparseTensor;
38 
39 /* Folded tensor with full symmetry maintains only information about
40    number of symmetrical variables nv. Further, we implement what is
41    left from the super class FTensor.
42 
43    We implement getOffset() which should be used with care since
44    its complexity.
45 
46    We implement a method adding a given general symmetry tensor to the
47    full symmetry tensor supposing the variables of the general symmetry
48    tensor are stacked giving only one variable of the full symmetry
49    tensor.             ⎛y⎞
50    For instance, if x= ⎝u⎠, then we can add tensor [g_y²u] to tensor [g_x³].
51    This is done in method addSubTensor(). Consult FGSTensor class declaration
52    to know what is general symmetry tensor.
53 
54    Note that the past-the-end index is of the form (nv,…,nv), because
55    of the specific implementation of FFSTensor::increment().
56 */
57 
58 class UFSTensor;
59 class FFSTensor : public FTensor
60 {
61   int nv;
62 public:
63   /* Constructs given the number of rows (explicit since the tensor is
64      column-oriented), the number of variables in each dimension, and the
65      number of dimensions */
FFSTensor(int r,int nvar,int d)66   FFSTensor(int r, int nvar, int d)
67     : FTensor(indor::along_col, IntSequence(d, nvar),
68               r, calcMaxOffset(nvar, d), d),
69       nv(nvar)
70   {
71   }
72 
73   /* Constructs a tensor by one-dimensional contraction from the higher
74      dimensional tensor t. This is, it constructs a tensor
75 
76      [g_yⁿ]_α₁…αₙ = [t_yⁿ⁺¹]_α₁…αₙβ [x]^β
77 
78      See the implementation for details. */
79   FFSTensor(const FFSTensor &t, const ConstVector &x);
80 
81   /* Converts from sparse tensor (which is fully symmetric and folded by
82      nature). */
83   explicit FFSTensor(const FSSparseTensor &t);
84 
85   FFSTensor(const FFSTensor &) = default;
86   FFSTensor(FFSTensor &&) = default;
87 
88   // Constructs from unfolded fully symmetric
89   explicit FFSTensor(const UFSTensor &ut);
90 
91   // Constructs a subtensor of selected rows
FFSTensor(int first_row,int num,FFSTensor & t)92   FFSTensor(int first_row, int num, FFSTensor &t)
93     : FTensor(first_row, num, t), nv(t.nv)
94   {
95   }
96 
97   void increment(IntSequence &v) const override;
98   void decrement(IntSequence &v) const override;
99   std::unique_ptr<UTensor> unfold() const override;
100   Symmetry
getSym() const101   getSym() const
102   {
103     return Symmetry{dimen()};
104   }
105 
106   int getOffset(const IntSequence &v) const override;
107   void addSubTensor(const FGSTensor &t);
108   int
nvar() const109   nvar() const
110   {
111     return nv;
112   }
113   static int calcMaxOffset(int nvar, int d);
114 };
115 
116 /* Unfolded fully symmetric tensor is almost the same in structure as
117    FFSTensor, but the method unfoldData(). It takes columns which also
118    exist in folded version and copies them to all their symmetrical
119    locations. This is useful when constructing unfolded tensor from
120    folded one. */
121 
122 class UFSTensor : public UTensor
123 {
124   int nv;
125 public:
UFSTensor(int r,int nvar,int d)126   UFSTensor(int r, int nvar, int d)
127     : UTensor(indor::along_col, IntSequence(d, nvar),
128               r, calcMaxOffset(nvar, d), d),
129       nv(nvar)
130   {
131   }
132   UFSTensor(const UFSTensor &t, const ConstVector &x);
133   UFSTensor(const UFSTensor &) = default;
134   UFSTensor(UFSTensor &&) = default;
135   explicit UFSTensor(const FFSTensor &ft);
UFSTensor(int first_row,int num,UFSTensor & t)136   UFSTensor(int first_row, int num, UFSTensor &t)
137     : UTensor(first_row, num, t), nv(t.nv)
138   {
139   }
140 
141   void increment(IntSequence &v) const override;
142   void decrement(IntSequence &v) const override;
143   std::unique_ptr<FTensor> fold() const override;
144   Symmetry
getSym() const145   getSym() const
146   {
147     return Symmetry{dimen()};
148   }
149 
150   int getOffset(const IntSequence &v) const override;
151   void addSubTensor(const UGSTensor &t);
152   int
nvar() const153   nvar() const
154   {
155     return nv;
156   }
157   static int
calcMaxOffset(int nvar,int d)158   calcMaxOffset(int nvar, int d)
159   {
160     return power(nvar, d);
161   }
162 private:
163   void unfoldData();
164 };
165 
166 #endif
167