DynamicSymmetry.h
Go to the documentation of this file.
1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2013 Christian Seiler <christian@iwakd.de>
5 //
6 // This Source Code Form is subject to the terms of the Mozilla
7 // Public License v. 2.0. If a copy of the MPL was not distributed
8 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 
10 #ifndef EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H
11 #define EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H
12 
13 #include "./InternalHeaderCheck.h"
14 
15 namespace Eigen {
16 
18 {
19  public:
20  inline explicit DynamicSGroup() : m_numIndices(1), m_elements(), m_generators(), m_globalFlags(0) { m_elements.push_back(ge(Generator(0, 0, 0))); }
24  inline DynamicSGroup& operator=(DynamicSGroup&& o) { m_numIndices = o.m_numIndices; std::swap(m_elements, o.m_elements); m_generators = o.m_generators; m_globalFlags = o.m_globalFlags; return *this; }
25 
26  void add(int one, int two, int flags = 0);
27 
28  template<typename Gen_>
29  inline void add(Gen_) { add(Gen_::One, Gen_::Two, Gen_::Flags); }
30  inline void addSymmetry(int one, int two) { add(one, two, 0); }
31  inline void addAntiSymmetry(int one, int two) { add(one, two, NegationFlag); }
32  inline void addHermiticity(int one, int two) { add(one, two, ConjugationFlag); }
33  inline void addAntiHermiticity(int one, int two) { add(one, two, NegationFlag | ConjugationFlag); }
34 
35  template<typename Op, typename RV, typename Index, std::size_t N, typename... Args>
36  inline RV apply(const std::array<Index, N>& idx, RV initial, Args&&... args) const
37  {
38  eigen_assert(N >= m_numIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
39  for (std::size_t i = 0; i < size(); i++)
40  initial = Op::run(h_permute(i, idx, typename internal::gen_numeric_list<int, N>::type()), m_elements[i].flags, initial, std::forward<Args>(args)...);
41  return initial;
42  }
43 
44  template<typename Op, typename RV, typename Index, typename... Args>
45  inline RV apply(const std::vector<Index>& idx, RV initial, Args&&... args) const
46  {
47  eigen_assert(idx.size() >= m_numIndices && "Can only apply symmetry group to objects that have at least the required amount of indices.");
48  for (std::size_t i = 0; i < size(); i++)
49  initial = Op::run(h_permute(i, idx), m_elements[i].flags, initial, std::forward<Args>(args)...);
50  return initial;
51  }
52 
53  inline int globalFlags() const { return m_globalFlags; }
54  inline std::size_t size() const { return m_elements.size(); }
55 
56  template<typename Tensor_, typename... IndexTypes>
57  inline internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup> operator()(Tensor_& tensor, typename Tensor_::Index firstIndex, IndexTypes... otherIndices) const
58  {
59  static_assert(sizeof...(otherIndices) + 1 == Tensor_::NumIndices, "Number of indices used to access a tensor coefficient must be equal to the rank of the tensor.");
60  return operator()(tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices>{{firstIndex, otherIndices...}});
61  }
62 
63  template<typename Tensor_>
64  inline internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup> operator()(Tensor_& tensor, std::array<typename Tensor_::Index, Tensor_::NumIndices> const& indices) const
65  {
66  return internal::tensor_symmetry_value_setter<Tensor_, DynamicSGroup>(tensor, *this, indices);
67  }
68  private:
69  struct GroupElement {
70  std::vector<int> representation;
71  int flags;
72  bool isId() const
73  {
74  for (std::size_t i = 0; i < representation.size(); i++)
75  if (i != (size_t)representation[i])
76  return false;
77  return true;
78  }
79  };
80  struct Generator {
81  int one;
82  int two;
83  int flags;
84  constexpr inline Generator(int one_, int two_, int flags_) : one(one_), two(two_), flags(flags_) {}
85  };
86 
87  std::size_t m_numIndices;
88  std::vector<GroupElement> m_elements;
89  std::vector<Generator> m_generators;
91 
92  template<typename Index, std::size_t N, int... n>
93  inline std::array<Index, N> h_permute(std::size_t which, const std::array<Index, N>& idx, internal::numeric_list<int, n...>) const
94  {
95  return std::array<Index, N>{{ idx[n >= m_numIndices ? n : m_elements[which].representation[n]]... }};
96  }
97 
98  template<typename Index>
99  inline std::vector<Index> h_permute(std::size_t which, std::vector<Index> idx) const
100  {
101  std::vector<Index> result;
102  result.reserve(idx.size());
103  for (auto k : m_elements[which].representation)
104  result.push_back(idx[k]);
105  for (std::size_t i = m_numIndices; i < idx.size(); i++)
106  result.push_back(idx[i]);
107  return result;
108  }
109 
110  inline GroupElement ge(Generator const& g) const
111  {
112  GroupElement result;
113  result.representation.reserve(m_numIndices);
114  result.flags = g.flags;
115  for (std::size_t k = 0; k < m_numIndices; k++) {
116  if (k == (std::size_t)g.one)
117  result.representation.push_back(g.two);
118  else if (k == (std::size_t)g.two)
119  result.representation.push_back(g.one);
120  else
121  result.representation.push_back(int(k));
122  }
123  return result;
124  }
125 
126  GroupElement mul(GroupElement, GroupElement) const;
127  inline GroupElement mul(Generator g1, GroupElement g2) const
128  {
129  return mul(ge(g1), g2);
130  }
131 
132  inline GroupElement mul(GroupElement g1, Generator g2) const
133  {
134  return mul(g1, ge(g2));
135  }
136 
137  inline GroupElement mul(Generator g1, Generator g2) const
138  {
139  return mul(ge(g1), ge(g2));
140  }
141 
142  inline int findElement(GroupElement e) const
143  {
144  for (auto ee : m_elements) {
145  if (ee.representation == e.representation)
146  return ee.flags ^ e.flags;
147  }
148  return -1;
149  }
150 
151  void updateGlobalFlags(int flagDiffOfSameGenerator);
152 };
153 
154 // dynamic symmetry group that auto-adds the template parameters in the constructor
155 template<typename... Gen>
157 {
158  public:
160  {
161  add_all(internal::type_list<Gen...>());
162  }
167 
168  private:
169  template<typename Gen1, typename... GenNext>
170  inline void add_all(internal::type_list<Gen1, GenNext...>)
171  {
172  add(Gen1());
173  add_all(internal::type_list<GenNext...>());
174  }
175 
176  inline void add_all(internal::type_list<>)
177  {
178  }
179 };
180 
182 {
185 
186  GroupElement result;
187  result.representation.reserve(m_numIndices);
188  for (std::size_t i = 0; i < m_numIndices; i++) {
189  int v = g2.representation[g1.representation[i]];
190  eigen_assert(v >= 0);
191  result.representation.push_back(v);
192  }
193  result.flags = g1.flags ^ g2.flags;
194  return result;
195 }
196 
197 inline void DynamicSGroup::add(int one, int two, int flags)
198 {
199  eigen_assert(one >= 0);
200  eigen_assert(two >= 0);
201  eigen_assert(one != two);
202 
203  if ((std::size_t)one >= m_numIndices || (std::size_t)two >= m_numIndices) {
204  std::size_t newNumIndices = (one > two) ? one : two + 1;
205  for (auto& gelem : m_elements) {
206  gelem.representation.reserve(newNumIndices);
207  for (std::size_t i = m_numIndices; i < newNumIndices; i++)
208  gelem.representation.push_back(i);
209  }
210  m_numIndices = newNumIndices;
211  }
212 
213  Generator g{one, two, flags};
214  GroupElement e = ge(g);
215 
216  /* special case for first generator */
217  if (m_elements.size() == 1) {
218  while (!e.isId()) {
219  m_elements.push_back(e);
220  e = mul(e, g);
221  }
222 
223  if (e.flags > 0)
224  updateGlobalFlags(e.flags);
225 
226  // only add in case we didn't have identity
227  if (m_elements.size() > 1)
228  m_generators.push_back(g);
229  return;
230  }
231 
232  int p = findElement(e);
233  if (p >= 0) {
235  return;
236  }
237 
238  std::size_t coset_order = m_elements.size();
239  m_elements.push_back(e);
240  for (std::size_t i = 1; i < coset_order; i++)
241  m_elements.push_back(mul(m_elements[i], e));
242  m_generators.push_back(g);
243 
244  std::size_t coset_rep = coset_order;
245  do {
246  for (auto g : m_generators) {
247  e = mul(m_elements[coset_rep], g);
248  p = findElement(e);
249  if (p < 0) {
250  // element not yet in group
251  m_elements.push_back(e);
252  for (std::size_t i = 1; i < coset_order; i++)
253  m_elements.push_back(mul(m_elements[i], e));
254  } else if (p > 0) {
256  }
257  }
258  coset_rep += coset_order;
259  } while (coset_rep < m_elements.size());
260 }
261 
262 inline void DynamicSGroup::updateGlobalFlags(int flagDiffOfSameGenerator)
263 {
264  switch (flagDiffOfSameGenerator) {
265  case 0:
266  default:
267  // nothing happened
268  break;
269  case NegationFlag:
270  // every element is it's own negative => whole tensor is zero
272  break;
273  case ConjugationFlag:
274  // every element is it's own conjugate => whole tensor is real
276  break;
277  case (NegationFlag | ConjugationFlag):
278  // every element is it's own negative conjugate => whole tensor is imaginary
280  break;
281  /* NOTE:
282  * since GlobalZeroFlag == GlobalRealFlag | GlobalImagFlag, if one generator
283  * causes the tensor to be real and the next one to be imaginary, this will
284  * trivially give the correct result
285  */
286  }
287 }
288 
289 } // end namespace Eigen
290 
291 #endif // EIGEN_CXX11_TENSORSYMMETRY_DYNAMICSYMMETRY_H
292 
293 /*
294  * kate: space-indent on; indent-width 2; mixedindent off; indent-mode cstyle;
295  */
Array< int, Dynamic, 1 > v
int n
int i
Array< double, 1, 3 > e(1./3., 0.5, 2.)
#define eigen_internal_assert(x)
#define eigen_assert(x)
float * p
DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs const &other)
void add_all(internal::type_list< Gen1, GenNext... >)
DynamicSGroupFromTemplateArgs< Gen... > & operator=(DynamicSGroupFromTemplateArgs< Gen... > &&o)
DynamicSGroupFromTemplateArgs< Gen... > & operator=(const DynamicSGroupFromTemplateArgs< Gen... > &o)
void add_all(internal::type_list<>)
DynamicSGroupFromTemplateArgs(DynamicSGroupFromTemplateArgs &&other)
Dynamic symmetry group.
GroupElement mul(GroupElement g1, Generator g2) const
internal::tensor_symmetry_value_setter< Tensor_, DynamicSGroup > operator()(Tensor_ &tensor, typename Tensor_::Index firstIndex, IndexTypes... otherIndices) const
std::vector< Index > h_permute(std::size_t which, std::vector< Index > idx) const
DynamicSGroup & operator=(const DynamicSGroup &o)
std::array< Index, N > h_permute(std::size_t which, const std::array< Index, N > &idx, internal::numeric_list< int, n... >) const
std::size_t m_numIndices
void updateGlobalFlags(int flagDiffOfSameGenerator)
internal::tensor_symmetry_value_setter< Tensor_, DynamicSGroup > operator()(Tensor_ &tensor, std::array< typename Tensor_::Index, Tensor_::NumIndices > const &indices) const
void addSymmetry(int one, int two)
void addHermiticity(int one, int two)
GroupElement mul(Generator g1, Generator g2) const
void addAntiHermiticity(int one, int two)
std::vector< Generator > m_generators
DynamicSGroup(const DynamicSGroup &o)
DynamicSGroup & operator=(DynamicSGroup &&o)
DynamicSGroup(DynamicSGroup &&o)
void add(int one, int two, int flags=0)
GroupElement mul(GroupElement, GroupElement) const
void addAntiSymmetry(int one, int two)
std::size_t size() const
int findElement(GroupElement e) const
RV apply(const std::array< Index, N > &idx, RV initial, Args &&... args) const
std::vector< GroupElement > m_elements
RV apply(const std::vector< Index > &idx, RV initial, Args &&... args) const
GroupElement ge(Generator const &g) const
GroupElement mul(Generator g1, GroupElement g2) const
: TensorContractionSycl.h, provides various tensor contraction kernel for SYCL backend
@ NegationFlag
Definition: Symmetry.h:18
@ ConjugationFlag
Definition: Symmetry.h:19
@ GlobalZeroFlag
Definition: Symmetry.h:25
@ GlobalRealFlag
Definition: Symmetry.h:23
@ GlobalImagFlag
Definition: Symmetry.h:24
EIGEN_DEFAULT_DENSE_INDEX_TYPE Index
constexpr Generator(int one_, int two_, int flags_)