permutation_group.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2015 Virginia Tech
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * Edward F Valeev, Justus Calvin
19  * Department of Chemistry, Virginia Tech
20  *
21  * permutation_group.h
22  * May 13, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_SYMM_PERMUTATION_GROUP_H__INCLUDED
27 #define TILEDARRAY_SYMM_PERMUTATION_GROUP_H__INCLUDED
28 
29 #include <algorithm>
30 #include <cassert>
31 #include <numeric>
32 
34 
35 namespace TiledArray {
36 
37 namespace symmetry {
38 
44 
50  public:
53 
54  protected:
56  std::vector<Permutation> generators_;
58  std::vector<Permutation> elements_;
59 
60  public:
61  // Compiler generated functions
66 
68 
74  PermutationGroup(std::vector<Permutation> generators)
75  : generators_(std::move(generators)) {
77  }
78 
80 
84  unsigned int order() const { return elements_.size(); }
85 
87 
89  static Permutation identity() { return Permutation(); }
90 
92 
96  const Permutation& operator[](unsigned int i) const {
97  TA_ASSERT(i < elements_.size());
98  return elements_[i];
99  }
100 
102 
105  const std::vector<Permutation>& elements() const { return elements_; }
106 
108 
111  const std::vector<Permutation>& generators() const { return generators_; }
112 
114 
119 
121 
124  std::vector<Permutation>::const_iterator begin() const {
125  return elements_.begin();
126  }
127 
129 
132  std::vector<Permutation>::const_iterator cbegin() const {
133  return elements_.cbegin();
134  }
135 
137 
140  std::vector<Permutation>::const_iterator end() const {
141  return elements_.end();
142  }
143 
145 
148  std::vector<Permutation>::const_iterator cend() const {
149  return elements_.cend();
150  }
151 
153 
155 
158  template <typename Set>
159  Set domain() const {
160  Set result;
161  // sufficient to loop over generators
162  for (const auto& e : generators_) {
163  const auto e_domain = e.domain<Set>();
164  result.insert(e_domain.begin(), e_domain.end());
165  }
166  return result;
167  }
168 
169  protected:
170  PermutationGroup() {} // makes uninitialized group, all initialization is
171  // left to the derived class
172 
177  static void init(std::vector<Permutation>& generators,
178  std::vector<Permutation>& elements) {
179  sort(generators.begin(), generators.end());
180  auto unique_last = std::unique(generators.begin(), generators.end());
181  generators.erase(unique_last, generators.end());
182  { // eliminate identity from the generator list
183  auto I_iter =
184  std::find(generators.begin(), generators.end(), Permutation());
185  if (I_iter != generators.end()) generators.erase(I_iter);
186  }
187 
188  // add the identity element first
189  elements.emplace_back();
190 
192  for (const auto& g : generators) {
193  elements.push_back(g);
194  }
195 
196  // Generate the remaining elements in the group by multiplying by generators
197  for (unsigned int g = 1u; g < elements.size(); ++g) {
198  for (const auto& G : generators) {
199  Permutation e = elements[g] * G;
200  if (std::find(elements.cbegin(), elements.cend(), e) ==
201  elements.cend()) {
202  elements.emplace_back(std::move(e));
203  }
204  }
205  }
206 
207  sort(elements.begin(), elements.end());
208  }
209 
210 }; // class PermutationGroup
211 
213 
218 inline bool operator==(const PermutationGroup& p1, const PermutationGroup& p2) {
219  return (p1.order() == p2.order()) && p1.elements() == p2.elements();
220 }
221 
223 
228 inline bool operator!=(const PermutationGroup& p1, const PermutationGroup& p2) {
229  return !operator==(p1, p2);
230 }
231 
233 
238 inline bool operator<(const PermutationGroup& p1, const PermutationGroup& p2) {
239  return std::lexicographical_compare(p1.cbegin(), p1.cend(), p2.cbegin(),
240  p2.cend());
241 }
242 
244 
248 inline std::ostream& operator<<(std::ostream& output,
249  const PermutationGroup& p) {
250  output << "{";
251  for (auto i = p.cbegin(); i != p.cend();) {
252  output << *i;
253  if (++i != p.cend()) output << ", ";
254  }
255  output << "}";
256  return output;
257 }
258 
260 
264 class SymmetricGroup final : public PermutationGroup {
265  public:
267 
268  // Compiler generated functions
269  SymmetricGroup() = delete;
270  SymmetricGroup(const SymmetricGroup&) = default;
274 
277  SymmetricGroup(unsigned int degree)
278  : SymmetricGroup(SymmetricGroup::iota_vector(degree)) {}
279 
284  template <typename InputIterator,
285  typename std::enable_if< ::TiledArray::detail::is_input_iterator<
286  InputIterator>::value>::type* = nullptr>
287  SymmetricGroup(InputIterator begin, InputIterator end)
288  : PermutationGroup(), domain_(begin, end) {
289  for (auto iter = begin; iter != end; ++iter) {
290  TA_ASSERT(*iter >= 0);
291  }
292 
293  const auto degree = domain_.size();
294 
295  // Add generators to the list of elements
296  if (degree > 2u) {
297  for (unsigned int i = 0u; i < degree; ++i) {
298  // Construct the generator and add to the list
299  unsigned int i1 = (i + 1u) % degree;
300  generators_.emplace_back(Permutation::Map{{domain_[i], domain_[i1]},
301  {domain_[i1], domain_[i]}});
302  }
303  } else if (degree == 2u) {
304  // Construct the generator
305  generators_.emplace_back(
306  Permutation::Map{{domain_[0], domain_[1]}, {domain_[1], domain_[0]}});
307  }
308 
310  }
311 
313 
316  template <typename Integer,
317  typename std::enable_if<std::is_integral<Integer>::value>::type* =
318  nullptr>
319  explicit SymmetricGroup(std::initializer_list<Integer> list)
320  : SymmetricGroup(list.begin(), list.end()) {}
321 
323 
326  unsigned int degree() const { return domain_.size(); }
327 
328  private:
329  std::vector<index_type> domain_;
330 
332  static std::vector<index_type> iota_vector(size_t n) {
333  std::vector<index_type> result(n);
334  std::iota(result.begin(), result.end(), 0);
335  return result;
336  }
337 
338  SymmetricGroup(const std::vector<index_type>& domain)
340 };
341 
350 template <typename MultiIndex>
351 bool is_lexicographically_smallest(const MultiIndex& idx,
352  const PermutationGroup& pg) {
353  const auto idx_size = idx.size();
354  for (const auto& p : pg) {
355  for (size_t i = 0; i != idx_size; ++i) {
356  auto idx_i = idx[i];
357  auto idx_p_i = idx[p[i]];
358  if (idx_p_i < idx_i) return false;
359  if (idx_p_i > idx_i) break;
360  }
361  }
362  return true;
363 }
364 
366 
378  std::vector<PermutationGroup::Permutation> conjugate_generators;
379  const auto h_inv = h.inv();
380  for (const auto& generator : G.generators()) {
381  conjugate_generators.emplace_back(h * generator * h_inv);
382  }
383  return PermutationGroup{std::move(conjugate_generators)};
384 }
385 
391  const PermutationGroup& G2) {
392  std::vector<PermutationGroup::Permutation> intersect_elements;
393  std::set_intersection(G1.begin(), G1.end(), G2.begin(), G2.end(),
394  std::back_inserter(intersect_elements));
395  return PermutationGroup{std::move(intersect_elements)};
396 }
397 
400 
405 template <typename Set>
406 inline PermutationGroup stabilizer(const PermutationGroup& G, const Set& f) {
407  std::vector<PermutationGroup::Permutation> stabilizer_generators;
408  for (const auto& generator : G.generators()) {
409  bool fixes_set = true;
410  for (const auto& i : f) {
411  if (generator.is_in_domain(i)) {
412  fixes_set = false;
413  break;
414  }
415  }
416  if (fixes_set) stabilizer_generators.push_back(generator);
417  }
418  return PermutationGroup{std::move(stabilizer_generators)};
419 }
420 
423 } // namespace symmetry
424 } // namespace TiledArray
425 
426 #endif // TILEDARRAY_SYMM_PERMUTATION_GROUP_H__INCLUDED
std::vector< Permutation > generators_
Group generators.
bool operator!=(const Permutation &p1, const Permutation &p2)
Permutation inequality operator.
Definition: permutation.h:460
SymmetricGroup(SymmetricGroup &&)=default
PermutationGroup conjugate(const PermutationGroup &G, const PermutationGroup::Permutation &h)
Computes conjugate permutation group obtained by the action of a permutation.
PermutationGroup intersect(const PermutationGroup &G1, const PermutationGroup &G2)
std::ostream & operator<<(std::ostream &output, const Permutation &p)
Add permutation to an output stream.
Definition: permutation.h:481
const Permutation & operator[](unsigned int i) const
Group element accessor.
std::vector< Permutation >::const_iterator cend() const
forward iterator over the group elements pointing past the last element
SymmetricGroup & operator=(SymmetricGroup &&)=default
bool operator==(const Permutation &p1, const Permutation &p2)
Permutation equality operator.
Definition: permutation.h:450
std::map< index_type, index_type > Map
Definition: permutation.h:123
SymmetricGroup & operator=(const SymmetricGroup &)=default
SymmetricGroup(InputIterator begin, InputIterator end)
bool is_lexicographically_smallest(const MultiIndex &idx, const PermutationGroup &pg)
Set domain() const
Computes the domain of this group.
PermutationGroup(PermutationGroup &&)=default
std::vector< Permutation >::const_iterator cbegin() const
forward iterator over the group elements pointing to the first element
SymmetricGroup(std::initializer_list< Integer > list)
Construct symmetric group using domain as an initializer list.
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
bool operator<(const Permutation &p1, const Permutation &p2)
Permutation less-than operator.
Definition: permutation.h:470
const std::vector< Permutation > & generators() const
Generators vector accessor.
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:117
unsigned int order() const
Group order accessor.
static Permutation identity()
Idenity element accessor.
Permutation inv() const
Construct the inverse of this permutation.
Definition: permutation.h:381
PermutationGroup stabilizer(const PermutationGroup &G, const Set &f)
static void init(std::vector< Permutation > &generators, std::vector< Permutation > &elements)
TiledArray::symmetry::Permutation Permutation
unsigned int degree() const
Degree accessor.
const std::vector< Permutation > & elements() const
Elements vector accessor.
PermutationGroup(std::vector< Permutation > generators)
General constructor.
SymmetricGroup(const SymmetricGroup &)=default
PermutationGroup(const PermutationGroup &)=default
std::vector< Permutation > elements_
Group elements.
PermutationGroup & operator=(const PermutationGroup &)=default
std::vector< Permutation >::const_iterator begin() const
forward iterator over the group elements pointing to the first element
PermutationGroup & operator=(PermutationGroup &&)=default
std::vector< Permutation >::const_iterator end() const
forward iterator over the group elements pointing past the last element