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 // Symmetry. 22 23 /* Symmetry is an abstraction for a term of the form y³u². It manages only 24 indices, not the variable names. So if one uses this abstraction, it must 25 be kept in mind that y is the first and u is the second. 26 27 In fact, the symmetry is a special case of equivalence, but its 28 implementation is much simpler. We do not need an abstraction for the 29 term “yyuyu” but due to Green theorem we can have term y³u². That 30 is why the equivalence is too general for our purposes. 31 32 One of a main purposes of the tensor library is to calculate something like: 33 34 ₗ 35 [B_y²u³]_α₁α₂β₁β₂β₃ = [f_zˡ]_γ₁…γₗ ∑ ∏ [g_{s^|cₘ|}]_cₘ(α,β)^γₘ 36 c∈ℳₗ,₅ ᵐ⁼¹ 37 38 We must be able to calculate a symmetry induced by symmetry y²u³ and by an 39 equivalence class from equivalence c. For equivalence class {0,4} the 40 induced symmetry is “yu”, since we pick first and fifth variable from y²u³. 41 For a given outer symmetry, the class InducedSymmetries does this for all 42 classes of a given equivalence. 43 44 We need also to cycle through all possible symmetries yielding the 45 given dimension. For this purpose we define classes SymmetrySet and 46 symiterator. 47 48 The symmetry is implemented as IntSequence, in fact, it inherits 49 from it. */ 50 51 #ifndef SYMMETRY_H 52 #define SYMMETRY_H 53 54 #include "equivalence.hh" 55 #include "int_sequence.hh" 56 57 #include <list> 58 #include <vector> 59 #include <initializer_list> 60 #include <utility> 61 #include <memory> 62 63 /* Clear. The method isFull() returns true if and only if the symmetry 64 allows for any permutation of indices. 65 66 WARNING: Symmetry(n) and Symmetry{n} are not the same. The former 67 initializes a symmetry of n elements, while the latter is a full symmetry of 68 order n. This is similar to the behaviour of std::vector. */ 69 70 class Symmetry : public IntSequence 71 { 72 public: 73 // Constructor allocating a given length of (zero-initialized) data Symmetry(int len)74 explicit Symmetry(int len) 75 : IntSequence(len, 0) 76 { 77 } 78 /* Constructor using an initializer list, that gives the contents of the 79 Symmetry. Typically used for symmetries of the form yⁿ, yⁿuᵐ, yⁿuᵐσᵏ */ Symmetry(std::initializer_list<int> init)80 Symmetry(std::initializer_list<int> init) 81 : IntSequence(std::move(init)) 82 { 83 } 84 // Constructor of implied symmetry for a symmetry and an equivalence class 85 Symmetry(const Symmetry &s, const OrdSequence &cl); 86 /* Subsymmetry, which takes the given length of symmetry from the end (shares 87 data pointer) */ Symmetry(Symmetry & s,int len)88 Symmetry(Symmetry &s, int len) 89 : IntSequence(s, s.size()-len, s.size()) 90 { 91 } 92 93 int num() const94 num() const 95 { 96 return size(); 97 } 98 int dimen() const99 dimen() const 100 { 101 return sum(); 102 } 103 int findClass(int i) const; 104 bool isFull() const; 105 }; 106 107 /* This is an iterator that iterates over all symmetries of given length and 108 dimension (see the SymmetrySet class for details). 109 110 The beginning iterator is (0, …, 0, dim). 111 Increasing it gives (0, … , 1, dim−1) 112 The just-before-end iterator is (dim, 0, …, 0) 113 The past-the-end iterator is (dim+1, 0, …, 0) 114 115 The constructor creates the iterator which starts from the given symmetry 116 symmetry (beginning). */ 117 118 class symiterator 119 { 120 const int dim; 121 Symmetry run; 122 public: 123 symiterator(int dim_arg, Symmetry run_arg); 124 ~symiterator() = default; 125 symiterator &operator++(); 126 const Symmetry & operator *() const127 operator*() const 128 { 129 return run; 130 } 131 bool operator =(const symiterator & it)132 operator=(const symiterator &it) 133 { 134 return dim == it.dim && run == it.run; 135 } 136 bool operator !=(const symiterator & it)137 operator!=(const symiterator &it) 138 { 139 return !operator=(it); 140 } 141 }; 142 143 /* The class SymmetrySet defines a set of symmetries of the given length 144 having given dimension (i.e. it represents all the lists of integers of 145 length ‘len’ and of sum equal to ‘dim’). It does not store all the 146 symmetries, it is just a convenience class for iteration. 147 148 The typical usage of the abstractions for SymmetrySet and 149 symiterator is as follows: 150 151 for (auto &si : SymmetrySet(6, 4)) 152 153 It goes through all symmetries of lenght 4 having dimension 6. One can use 154 ‘si’ as the symmetry in the body. */ 155 156 class SymmetrySet 157 { 158 public: 159 const int len; 160 const int dim; SymmetrySet(int dim_arg,int len_arg)161 SymmetrySet(int dim_arg, int len_arg) 162 : len(len_arg), dim(dim_arg) 163 { 164 } 165 symiterator begin() const166 begin() const 167 { 168 Symmetry run(len); 169 run[len-1] = dim; 170 return { dim, run }; 171 } 172 symiterator end() const173 end() const 174 { 175 Symmetry run(len); 176 run[0] = dim+1; 177 return { dim, run }; 178 } 179 }; 180 181 /* This simple abstraction just constructs a vector of induced 182 symmetries from the given equivalence and outer symmetry. A 183 permutation might optionally permute the classes of the equivalence. */ 184 185 class InducedSymmetries : public std::vector<Symmetry> 186 { 187 public: 188 InducedSymmetries(const Equivalence &e, const Symmetry &s); 189 InducedSymmetries(const Equivalence &e, const Permutation &p, const Symmetry &s); 190 void print() const; 191 }; 192 193 #endif 194