TiledArray  0.7.0
permutation.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 Valeev
19  * Department of Chemistry, Virginia Tech
20  *
21  * permutation.h
22  * May 13, 2015
23  *
24  */
25 
26 #ifndef TILEDARRAY_SYMM_PERMUTATION_H__INCLUDED
27 #define TILEDARRAY_SYMM_PERMUTATION_H__INCLUDED
28 
29 #include <array>
30 #include <vector>
31 #include <map>
32 #include <set>
33 
34 #include <algorithm>
35 
36 #include <TiledArray/type_traits.h>
37 #include <TiledArray/error.h>
38 
39 namespace TiledArray {
40 
46  namespace symmetry {
47 
48  namespace detail {
49 
51 
59  template <typename Perm, typename Arg, typename Result>
60  inline void permute_array(const Perm& perm, const Arg& arg, Result& result) {
61  TA_ASSERT(result.size() == arg.size());
62  if (perm.domain_size() < arg.size()) {
63  std::copy(arg.begin(), arg.end(), result.begin()); // if perm does not map every element of arg, copy arg to result first
64  }
65  for(const auto& p: perm.data()) {
66  TA_ASSERT(result.size() > p.second);
67  TA_ASSERT(arg.size() > p.second);
68  result[p.second] = arg[p.first];
69  }
70  }
71  } // namespace detail
72 
74 
141  class Permutation {
142  public:
144  typedef unsigned int index_type;
145  typedef std::map<index_type,index_type> Map;
146  typedef Map::const_iterator const_iterator;
147 
148  private:
149 
151  Map p_;
152 
153  static std::ostream& print_map(std::ostream& output, const Map& p) {
154  for (auto i=p.cbegin(); i!=p.cend();) {
155  output << i->first << "->" << i->second;
156  if (++i != p.cend())
157  output << ", ";
158  }
159  return output;
160  }
161  friend inline std::ostream& operator<<(std::ostream& output, const Permutation& p);
162 
165  template <typename InIter>
166  static bool valid_permutation(InIter first, InIter last) {
167  bool result = true;
168  for(; first != last; ++first) {
169  const auto value = *first;
170  result = result && value >= 0 && (std::count(first, last, *first) == 1ul);
171  }
172  return result;
173  }
174 
177  template <typename Map>
178  static bool valid_permutation(const Map& input) {
179  std::set<index_type> keys;
180  std::set<index_type> values;
181  for(const auto& e: input) {
182  const auto& key = e.first;
183  const auto& value = e.second;
184  if (keys.find(key) == keys.end())
185  keys.insert(key);
186  else {
187  //print_map(std::cout, input);
188  return false; // key is found more than once
189  }
190  if (values.find(value) == values.end())
191  values.insert(value);
192  else {
193  //print_map(std::cout, input);
194  return false; // value is found more than once
195  }
196  }
197  return keys == values; // must map domain into itself
198  }
199 
200  // Used to select the correct constructor based on input template types
201  struct Enabler { };
202 
203  public:
204 
205  Permutation() = default; // makes an identity permutation
206  Permutation(const Permutation&) = default;
207  Permutation(Permutation&&) = default;
208  ~Permutation() = default;
209  Permutation& operator=(const Permutation&) = default;
210  Permutation& operator=(Permutation&& other) = default;
211 
213 
218  template <typename InIter,
219  typename std::enable_if<TiledArray::detail::is_input_iterator<InIter>::value>::type* = nullptr>
220  Permutation(InIter first, InIter last)
221  {
222  TA_ASSERT( valid_permutation(first, last) );
223  size_t i=0;
224  for(auto e=first; e!=last; ++e, ++i) {
225  auto p_i = *e;
226  if (i != p_i) p_[i] = p_i;
227  }
228  }
229 
231 
234  explicit Permutation(const std::vector<index_type>& a) :
235  Permutation(a.begin(), a.end())
236  {
237  }
238 
240 
242  explicit Permutation(std::initializer_list<index_type> list) :
243  Permutation(list.begin(), list.end())
244  {
245  }
246 
248 
250  Permutation(Map p) : p_(std::move(p))
251  {
252  TA_ASSERT(valid_permutation(p_));
253  }
254 
256 
258  unsigned int domain_size() const { return p_.size(); }
259 
266 
268 
270  const_iterator begin() const { return p_.begin(); }
271 
273 
275  const_iterator cbegin() const { return p_.cbegin(); }
276 
278 
280  const_iterator end() const { return p_.end(); }
281 
283 
285  const_iterator cend() const { return p_.cend(); }
286 
288 
290 
294  auto e_image_iter = p_.find(e);
295  if (e_image_iter != p_.end())
296  return e_image_iter->second;
297  else
298  return e;
299  }
300 
302 
305  template <typename Set>
306  Set domain() const {
307  Set result;
308  for(const auto& e: this->p_) {
309  result.insert(result.begin(), e.first);
310  }
311  //std::sort(result.begin(), result.end());
312  return result;
313  }
314 
316 
320  template <typename Integer,
321  typename std::enable_if<std::is_integral<Integer>::value>::type* = nullptr>
322  bool is_in_domain(Integer i) const {
323  return p_.find(i) != p_.end();
324  }
325 
327 
338  std::vector<std::vector<index_type> > cycles() const {
339 
340  std::vector<std::vector<index_type>> result;
341 
342  std::set<index_type> placed_in_cycle;
343 
344  // safe to use non-const operator[] due to properties of Permutation (domain==image)
345  auto& p_nonconst_ = const_cast<Map&>(p_);
346 
347  // 1. for each i compute its orbit
348  // 2. if the orbit is longer than 1, sort and add to the list of cycles
349  for(const auto& e: p_) {
350  auto i = e.first;
351  if (placed_in_cycle.find(i) == placed_in_cycle.end()) { // not in a cycle yet?
352  std::vector<index_type> cycle(1,i);
353  placed_in_cycle.insert(i);
354 
355  index_type next_i = p_nonconst_[i];
356  while (next_i != i) {
357  cycle.push_back(next_i);
358  placed_in_cycle.insert(next_i);
359  next_i = p_nonconst_[next_i];
360  }
361 
362  if (cycle.size() != 1) {
363  std::sort(cycle.begin(), cycle.end());
364  result.emplace_back(cycle);
365  }
366 
367  } // this i already in a cycle
368  } // loop over i
369 
370  return result;
371  }
372 
374 
377  Permutation mult(const Permutation& other) const {
378  // 1. domain of product = domain of this U domain of other
379  using iset = std::set<index_type>;
380  auto product_domain = this->domain<iset>();
381  auto other_domain = other.domain<iset>();
382  product_domain.insert(other_domain.begin(), other_domain.end());
383 
384  Map result;
385  for(const auto& d: product_domain) {
386  const auto d_image = other[(*this)[d]];
387  if (d_image != d)
388  result[d] = d_image;
389  }
390 
391  return Permutation(result);
392  }
393 
395 
399  Permutation inv() const {
400  Map result;
401  for(const auto& iter: p_) {
402  const auto i = iter.first;
403  const auto pi = iter.second;
404  result.insert(std::make_pair(pi,i));
405  }
406  return Permutation(std::move(result));
407  }
408 
410 
415  Permutation pow(int n) const {
416  // Initialize the algorithm inputs
417  int power;
418  Permutation value;
419  if(n < 0) {
420  value = inv();
421  power = -n;
422  } else {
423  value = *this;
424  power = n;
425  }
426 
427  Permutation result;
428 
429  while(power) {
430  if(power & 1)
431  result = result.mult(value);
432  value = value.mult(value);
433  power >>= 1;
434  }
435 
436  return result;
437  }
438 
440 
443  const Map& data() const { return p_; }
444 
446 
449  return Permutation();
450  }
451 
453 
457  template <typename Archive>
458  void serialize(Archive& ar) {
459  ar & p_;
460  }
461 
462  }; // class Permutation
463 
465 
470  inline bool operator==(const Permutation& p1, const Permutation& p2) {
471  return (p1.domain_size() == p2.domain_size())
472  && p1.data() == p2.data();
473  }
474 
476 
481  inline bool operator!=(const Permutation& p1, const Permutation& p2) {
482  return ! operator==(p1, p2);
483  }
484 
486 
491  inline bool operator<(const Permutation& p1, const Permutation& p2) {
492  if (&p1 == &p2) return false;
493  return std::lexicographical_compare(p1.data().begin(), p1.data().end(),
494  p2.data().begin(), p2.data().end());
495  }
496 
498 
502  inline std::ostream& operator<<(std::ostream& output, const Permutation& p) {
503  output << "{";
504  Permutation::print_map(output, p.data());
505  output << "}";
506  return output;
507  }
508 
510 
513  inline Permutation operator -(const Permutation& perm) {
514  return perm.inv();
515  }
516 
518 
523  inline Permutation operator*(const Permutation& p1, const Permutation& p2) {
524  return p1.mult(p2);
525  }
526 
527 
529  inline Permutation& operator*=(Permutation& p1, const Permutation& p2) {
530  return (p1 = p1 * p2);
531  }
532 
534 
540  inline Permutation operator^(const Permutation& perm, int n) {
541  return perm.pow(n);
542  }
543 
547 
556  template <typename T, std::size_t N>
557  inline std::array<T,N> operator*(const Permutation& perm, const std::array<T, N>& a) {
558  std::array<T,N> result;
559  symmetry::detail::permute_array(perm, a, result);
560  return result;
561  }
562 
564 
572  template <typename T, std::size_t N>
573  inline std::array<T,N>& operator*=(std::array<T,N>& a, const Permutation& perm) {
574  const std::array<T,N> temp = a;
575  symmetry::detail::permute_array(perm, temp, a);
576  return a;
577  }
578 
580 
588  template <typename T, typename A>
589  inline std::vector<T> operator*(const Permutation& perm, const std::vector<T, A>& v) {
590  std::vector<T> result(v.size());
591  symmetry::detail::permute_array(perm, v, result);
592  return result;
593  }
594 
596 
604  template <typename T, typename A>
605  inline std::vector<T, A>& operator*=(std::vector<T, A>& v, const Permutation& perm) {
606  const std::vector<T, A> temp = v;
607  symmetry::detail::permute_array(perm, temp, v);
608  return v;
609  }
610 
611  } // namespace symmetry
612 
615 } // namespace TiledArray
616 
617 #endif // TILEDARRAY_SYMM_PERMUTATION_H__INCLUDED
Map::const_iterator const_iterator
Definition: permutation.h:146
Permutation operator-(const Permutation &perm)
Inverse permutation operator.
Definition: permutation.h:513
friend std::ostream & operator<<(std::ostream &output, const Permutation &p)
Add permutation to an output stream.
Definition: permutation.h:502
Set domain() const
Computes the domain of this permutation.
Definition: permutation.h:306
Permutation(const std::vector< index_type > &a)
std::vector constructor
Definition: permutation.h:234
index_type operator[](index_type e) const
Computes image of an element under this permutation.
Definition: permutation.h:293
unsigned int domain_size() const
Permutation domain size.
Definition: permutation.h:258
const_iterator cend() const
End element iterator factory function.
Definition: permutation.h:285
Permutation pow(int n) const
Raise this permutation to the n-th power.
Definition: permutation.h:415
const_iterator end() const
End element iterator factory function.
Definition: permutation.h:280
Permutation inv() const
Construct the inverse of this permutation.
Definition: permutation.h:399
Permutation & operator=(const Permutation &)=default
STL namespace.
Permutation(Map p)
Construct permutation using its compressed 2-line form given by std::map.
Definition: permutation.h:250
Permutation & operator*=(Permutation &p1, const Permutation &p2)
return *this ^ other
Definition: permutation.h:529
Permutation operator*(const Permutation &p1, const Permutation &p2)
Permutation multiplication operator.
Definition: permutation.h:523
Permutation(std::initializer_list< index_type > list)
Construct permutation with an initializer list.
Definition: permutation.h:242
Permutation mult(const Permutation &other) const
Product of this permutation by other.
Definition: permutation.h:377
bool is_in_domain(Integer i) const
Test if an index is in the domain of this permutation.
Definition: permutation.h:322
bool operator!=(const Permutation &p1, const Permutation &p2)
Permutation inequality operator.
Definition: permutation.h:481
Permutation operator^(const Permutation &perm, int n)
Raise perm to the n-th power.
Definition: permutation.h:540
#define TA_ASSERT(a)
Definition: error.h:107
Permutation(InIter first, InIter last)
Construct permutation using its 1-line form given by range [first,last)
Definition: permutation.h:220
const_iterator cbegin() const
Begin element iterator factory function.
Definition: permutation.h:275
std::ostream & operator<<(std::ostream &output, const Permutation &p)
Add permutation to an output stream.
Definition: permutation.h:502
const_iterator begin() const
Begin element iterator factory function.
Definition: permutation.h:270
Permutation identity() const
Idenity permutation factory method.
Definition: permutation.h:448
DistArray< Tile, Policy > copy(const DistArray< Tile, Policy > &a)
Definition: utils.h:58
bool operator==(const Permutation &p1, const Permutation &p2)
Permutation equality operator.
Definition: permutation.h:470
void permute_array(const Perm &perm, const Arg &arg, Result &result)
Create a permuted copy of an array.
Definition: permutation.h:60
void serialize(Archive &ar)
Serialize permutation.
Definition: permutation.h:458
bool operator<(const Permutation &p1, const Permutation &p2)
Permutation less-than operator.
Definition: permutation.h:491
const Map & data() const
Data accessor.
Definition: permutation.h:443
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:141
std::vector< std::vector< index_type > > cycles() const
Cycles decomposition.
Definition: permutation.h:338
std::map< index_type, index_type > Map
Definition: permutation.h:145