permutation.h
Go to the documentation of this file.
1 /*
2  * This file is a part of TiledArray.
3  * Copyright (C) 2013 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  */
19 
20 #ifndef TILEDARRAY_PERMUTATION_H__INCLUDED
21 #define TILEDARRAY_PERMUTATION_H__INCLUDED
22 
23 #include <algorithm>
24 #include <array>
25 #include <numeric>
26 
27 #include <TiledArray/error.h>
29 #include <TiledArray/type_traits.h>
30 #include <TiledArray/util/vector.h>
31 #include <TiledArray/utility.h>
32 
33 namespace TiledArray {
34 
35 // Forward declarations
36 class Permutation;
37 bool operator==(const Permutation&, const Permutation&);
38 std::ostream& operator<<(std::ostream&, const Permutation&);
39 template <typename T, std::size_t N>
40 inline std::array<T, N> operator*(const Permutation&, const std::array<T, N>&);
41 template <typename T, std::size_t N>
42 inline std::array<T, N>& operator*=(std::array<T, N>&, const Permutation&);
43 template <typename T, typename A>
44 inline std::vector<T> operator*(const Permutation&, const std::vector<T, A>&);
45 template <typename T, typename A>
46 inline std::vector<T, A>& operator*=(std::vector<T, A>&, const Permutation&);
47 template <typename T>
48 inline std::vector<T> operator*(const Permutation&,
49  const T* MADNESS_RESTRICT const);
50 
51 class BipartitePermutation;
52 bool operator==(const BipartitePermutation&, const BipartitePermutation&);
53 
54 namespace detail {
55 
57 
64 template <typename Perm, typename Arg, typename Result,
65  typename = std::enable_if_t<is_permutation_v<Perm>>>
66 inline void permute_array(const Perm& perm, const Arg& arg, Result& result) {
67  using std::size;
68  TA_ASSERT(size(result) == size(arg));
69  const unsigned int n = size(arg);
70  for (unsigned int i = 0u; i < n; ++i) {
71  const typename Perm::index_type pi = perm[i];
72  TA_ASSERT(i < size(arg));
73  TA_ASSERT(pi < size(result));
74  result[pi] = arg[i];
75  }
76 }
77 } // namespace detail
78 
84 
130 class Permutation {
131  public:
133  typedef unsigned int index_type;
134  template <typename T>
137 
138  private:
142  template <typename InIter>
143  bool valid_permutation(InIter first, InIter last) {
144  bool result = true;
145  using diff_type = typename std::iterator_traits<InIter>::difference_type;
146  const diff_type n = std::distance(first, last);
147  TA_ASSERT(n >= 0);
148  for (; first != last; ++first) {
149  const diff_type value = *first;
150  result = result && value >= 0 && (value < n) &&
151  (std::count(first, last, *first) == 1ul);
152  }
153  return result;
154  }
155 
156  // Used to select the correct constructor based on input template types
157  struct Enabler {};
158 
159  protected:
162 
163  public:
164  Permutation() = default; // constructs an invalid Permutation
165  Permutation(const Permutation&) = default;
166  Permutation(Permutation&&) = default;
167  ~Permutation() = default;
168  Permutation& operator=(const Permutation&) = default;
169  Permutation& operator=(Permutation&& other) = default;
170 
172 
179  template <typename InIter, typename std::enable_if<detail::is_input_iterator<
180  InIter>::value>::type* = nullptr>
181  Permutation(InIter first, InIter last) : p_(first, last) {
182  TA_ASSERT(valid_permutation(first, last));
183  }
184 
186 
189  template <typename Index,
190  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
191  explicit Permutation(const Index& a)
192  : Permutation(std::cbegin(a), std::cend(a)) {}
193 
195 
198  explicit Permutation(vector<index_type>&& a) : p_(std::move(a)) {
199  TA_ASSERT(valid_permutation(p_.begin(), p_.end()));
200  }
201 
203 
206  template <typename Integer,
207  std::enable_if_t<std::is_integral_v<Integer>>* = nullptr>
208  explicit Permutation(std::initializer_list<Integer> list)
209  : Permutation(list.begin(), list.end()) {}
210 
212 
214  index_type size() const { return p_.size(); }
215 
217 
219  [[deprecated("use Permutation::size()")]] index_type dim() const {
220  return p_.size();
221  }
222 
224 
226  const_iterator begin() const { return p_.begin(); }
227 
229 
231  const_iterator cbegin() const { return p_.cbegin(); }
232 
234 
236  const_iterator end() const { return p_.end(); }
237 
239 
241  const_iterator cend() const { return p_.cend(); }
242 
244 
247  index_type operator[](unsigned int i) const { return p_[i]; }
248 
250 
266 
267  vector<bool> placed_in_cycle(p_.size(), false);
268 
269  // 1. for each i compute its orbit
270  // 2. if the orbit is longer than 1, sort and add to the list of cycles
271  for (index_type i = 0; i != p_.size(); ++i) {
272  if (not placed_in_cycle[i]) {
273  vector<index_type> cycle(1, i);
274  placed_in_cycle[i] = true;
275 
276  index_type next_i = p_[i];
277  while (next_i != i) {
278  cycle.push_back(next_i);
279  placed_in_cycle[next_i] = true;
280  next_i = p_[next_i];
281  }
282 
283  if (cycle.size() != 1) {
284  std::sort(cycle.begin(), cycle.end());
285  result.emplace_back(cycle);
286  }
287 
288  } // this i already in a cycle
289  } // loop over i
290 
291  return result;
292  }
293 
295 
298  static Permutation identity(const unsigned int dim) {
299  Permutation result;
300  result.p_.reserve(dim);
301  for (unsigned int i = 0u; i < dim; ++i) result.p_.emplace_back(i);
302  return result;
303  }
304 
306 
308  Permutation identity() const { return identity(p_.size()); }
309 
311 
314  Permutation mult(const Permutation& other) const {
315  const unsigned int n = p_.size();
316  TA_ASSERT(n == other.p_.size());
317  Permutation result;
318  result.p_.reserve(n);
319 
320  for (unsigned int i = 0u; i < n; ++i) {
321  const index_type p_i = p_[i];
322  const index_type result_i = other.p_[p_i];
323  result.p_.emplace_back(result_i);
324  }
325 
326  return result;
327  }
328 
330 
334  Permutation inv() const {
335  const index_type n = p_.size();
336  Permutation result;
337  result.p_.resize(n, 0ul);
338  for (index_type i = 0ul; i < n; ++i) {
339  const index_type pi = p_[i];
340  result.p_[pi] = i;
341  }
342  return result;
343  }
344 
346 
351  Permutation pow(int n) const {
352  // Initialize the algorithm inputs
353  int power;
354  Permutation value;
355  if (n < 0) {
356  value = inv();
357  power = -n;
358  } else {
359  value = *this;
360  power = n;
361  }
362 
363  Permutation result = identity(p_.size());
364 
365  // Compute the power of value with the exponentiation by squaring.
366  while (power) {
367  if (power & 1) result = result.mult(value);
368  value = value.mult(value);
369  power >>= 1;
370  }
371 
372  return result;
373  }
374 
376 
378  explicit operator bool() const { return !p_.empty(); }
379 
381 
383  bool operator!() const { return p_.empty(); }
384 
386 
388  const auto& data() const { return p_; }
389 
391 
395  template <typename Archive>
396  void serialize(Archive& ar) {
397  ar& p_;
398  }
399 
400 }; // class Permutation
401 
403 
408 inline bool operator==(const Permutation& p1, const Permutation& p2) {
409  return (p1.size() == p2.size()) &&
410  std::equal(p1.data().begin(), p1.data().end(), p2.data().begin());
411 }
412 
414 
419 inline bool operator!=(const Permutation& p1, const Permutation& p2) {
420  return !operator==(p1, p2);
421 }
422 
424 
429 inline bool operator<(const Permutation& p1, const Permutation& p2) {
430  return std::lexicographical_compare(p1.data().begin(), p1.data().end(),
431  p2.data().begin(), p2.data().end());
432 }
433 
435 
439 inline std::ostream& operator<<(std::ostream& output, const Permutation& p) {
440  std::size_t n = p.size();
441  output << "{";
442  for (unsigned int dim = 0; dim < n - 1; ++dim)
443  output << dim << "->" << p.data()[dim] << ", ";
444  output << n - 1 << "->" << p.data()[n - 1] << "}";
445  return output;
446 }
447 
449 
452 inline Permutation operator-(const Permutation& perm) { return perm.inv(); }
453 
455 
460 inline Permutation operator*(const Permutation& p1, const Permutation& p2) {
461  return p1.mult(p2);
462 }
463 
466  return (p1 = p1 * p2);
467 }
468 
470 
476 inline Permutation operator^(const Permutation& perm, int n) {
477  return perm.pow(n);
478 }
479 
482 
491 template <typename T, std::size_t N>
492 inline std::array<T, N> operator*(const Permutation& perm,
493  const std::array<T, N>& a) {
494  TA_ASSERT(perm.size() == a.size());
495  std::array<T, N> result;
496  detail::permute_array(perm, a, result);
497  return result;
498 }
499 
501 
509 template <typename T, std::size_t N>
510 inline std::array<T, N>& operator*=(std::array<T, N>& a,
511  const Permutation& perm) {
512  TA_ASSERT(perm.size() == a.size());
513  const std::array<T, N> temp = a;
514  detail::permute_array(perm, temp, a);
515  return a;
516 }
517 
519 
527 template <typename T, typename A>
528 inline std::vector<T> operator*(const Permutation& perm,
529  const std::vector<T, A>& v) {
530  TA_ASSERT(perm.size() == v.size());
531  std::vector<T> result(perm.size());
532  detail::permute_array(perm, v, result);
533  return result;
534 }
535 
537 
545 template <typename T, typename A>
546 inline std::vector<T, A>& operator*=(std::vector<T, A>& v,
547  const Permutation& perm) {
548  const std::vector<T, A> temp = v;
549  detail::permute_array(perm, temp, v);
550  return v;
551 }
552 
554 
562 template <typename T, std::size_t N>
563 inline boost::container::small_vector<T, N> operator*(
564  const Permutation& perm, const boost::container::small_vector<T, N>& v) {
565  TA_ASSERT(perm.size() == v.size());
566  boost::container::small_vector<T, N> result(perm.size());
567  detail::permute_array(perm, v, result);
568  return result;
569 }
570 
572 
580 template <typename T, std::size_t N>
581 inline boost::container::small_vector<T, N>& operator*=(
582  boost::container::small_vector<T, N>& v, const Permutation& perm) {
583  const boost::container::small_vector<T, N> temp = v;
584  detail::permute_array(perm, temp, v);
585  return v;
586 }
587 
589 
594 template <typename T>
595 inline std::vector<T> operator*(const Permutation& perm,
596  const T* MADNESS_RESTRICT const ptr) {
597  const unsigned int n = perm.size();
598  std::vector<T> result(n);
599  for (unsigned int i = 0u; i < n; ++i) {
600  const typename Permutation::index_type perm_i = perm[i];
601  const T ptr_i = ptr[i];
602  result[perm_i] = ptr_i;
603  }
604  return result;
605 }
606 
608 
611  public:
613  template <typename T>
615 
616  BipartitePermutation() = default;
622 
624 
626  explicit operator bool() const { return static_cast<bool>(base_); }
627 
629 
631  auto size() const { return base_.size(); }
632 
634 
636  [[deprecated("use BipartitePermutation::size()")]] auto dim() const {
637  return base_.size();
638  }
639 
641 
643  auto begin() const { return base_.begin(); }
644 
646 
648  auto cbegin() const { return base_.cbegin(); }
649 
651 
653  auto end() const { return base_.end(); }
654 
656 
658  auto cend() const { return base_.cend(); }
659 
662  operator Permutation&() & {
663  TA_ASSERT(second_size_ == 0);
664  return base_;
665  }
668  operator Permutation&&() && {
669  TA_ASSERT(second_size_ == 0);
670  return std::move(base_);
671  }
674  operator const Permutation&() const& {
675  TA_ASSERT(second_size_ == 0);
676  return base_;
677  }
678 
680  index_type second_partition_size = 0)
681  : base_(p), second_size_(second_partition_size) {
682  init();
683  }
684 
686  : second_size_(second.size()) {
687  vector<index_type> base;
688  base.reserve(first.size() + second.size());
689  for (auto&& v : first) base.emplace_back(v);
690  for (auto&& v : second) base.emplace_back(v);
691  base_ = Permutation(base);
692  init();
693  }
694 
695  // clang-format off
697 
705  // clang-format on
706  template <typename InIter, typename std::enable_if<detail::is_input_iterator<
707  InIter>::value>::type* = nullptr>
708  BipartitePermutation(InIter first, InIter last,
709  index_type second_partition_size = 0)
710  : base_(first, last), second_size_(second_partition_size) {
711  init();
712  }
713 
714  // clang-format off
716 
720  // clang-format on
721  template <typename Index,
722  typename = std::enable_if_t<detail::is_integral_range_v<Index>>>
723  explicit BipartitePermutation(const Index& a,
724  index_type second_partition_size = 0)
725  : BipartitePermutation(std::cbegin(a), std::cend(a),
726  second_partition_size) {}
727 
728  // clang-format off
730 
734  // clang-format on
736  index_type second_partition_size = 0)
737  : base_(std::move(a)), second_size_(second_partition_size) {
738  init();
739  }
740 
742  const Permutation& first() const { return first_; }
744  const Permutation& second() const { return second_; }
745 
747  index_type first_size() const { return this->size() - second_size_; }
748 
750  index_type second_size() const { return second_size_; }
751 
753 
757  template <typename Archive>
758  void serialize(Archive& ar) {
759  ar& base_& second_size_;
761  first_ = {};
762  second_ = {};
763  }
764  }
765 
766  private:
768  Permutation base_;
770  index_type second_size_ = 0;
771 
772  Permutation first_;
773  Permutation second_;
774 
775  // initializes first_ and second_
776  void init() {
777  first_ = Permutation{this->begin(), this->begin() + first_size()};
778  const auto n_first = first_size();
779  vector<index_type> temp(second_size());
780  for (auto i = n_first; i < size(); ++i)
781  temp[i - n_first] = base_[i] - n_first;
782  second_ = Permutation(temp.begin(), temp.end());
783  }
784 
785  friend bool operator==(const BipartitePermutation& p1,
786  const BipartitePermutation& p2);
787 };
788 
790 
795 inline bool operator==(const BipartitePermutation& p1,
796  const BipartitePermutation& p2) {
797  return (p1.second_size() == p2.second_size()) && p1.base_ == p2.base_;
798 }
799 
801 
806 inline bool operator!=(const BipartitePermutation& p1,
807  const BipartitePermutation& p2) {
808  return !(p1 == p2);
809 }
810 
812 
813 inline auto inner(const Permutation& p) {
814  abort();
815  return Permutation{};
816 }
817 
818 // N.B. can't return ref here due to possible dangling ref when p is bound to
819 // temporary
820 inline auto outer(const Permutation& p) { return p; }
821 
822 inline auto inner_size(const Permutation& p) {
823  abort();
824  return 0;
825 }
826 
827 inline auto outer_size(const Permutation& p) { return p.size(); }
828 
829 inline auto inner(const BipartitePermutation& p) { return p.second(); }
830 
831 inline auto outer(const BipartitePermutation& p) { return p.first(); }
832 
833 inline auto inner_size(const BipartitePermutation& p) {
834  return p.second_size();
835 }
836 
837 inline auto outer_size(const BipartitePermutation& p) { return p.first_size(); }
838 
839 } // namespace TiledArray
840 
841 #endif // TILEDARRAY_PERMUTATION_H__INCLUED
auto dim() const
Domain size accessor.
Definition: permutation.h:636
index_type dim() const
Domain size accessor.
Definition: permutation.h:219
boost::container::small_vector< T, N > svector
Definition: vector.h:43
index_type operator[](unsigned int i) const
Element accessor.
Definition: permutation.h:247
index_type size() const
Domain size accessor.
Definition: permutation.h:214
Permutation pow(int n) const
Raise this permutation to the n-th power.
Definition: permutation.h:351
void serialize(Archive &ar)
Serialize permutation.
Definition: permutation.h:396
vector< index_type > p_
One-line representation of permutation.
Definition: permutation.h:161
BipartitePermutation(const Permutation &first, const Permutation &second)
Definition: permutation.h:685
void permute_array(const Perm &perm, const Arg &arg, Result &result)
Create a permuted copy of an array.
Definition: permutation.h:66
Permutation & operator=(Permutation &&other)=default
Permutation inv() const
Construct the inverse of this permutation.
Definition: permutation.h:334
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:130
bool operator==(const BlockRange &r1, const BlockRange &r2)
BlockRange equality comparison.
Definition: block_range.h:433
static Permutation identity(const unsigned int dim)
Identity permutation factory function.
Definition: permutation.h:298
BipartitePermutation(const Index &a, index_type second_partition_size=0)
Array constructor.
Definition: permutation.h:723
constexpr bool operator!=(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:382
auto cbegin() const
Begin element iterator factory function.
Definition: permutation.h:648
bool operator<(const Permutation &p1, const Permutation &p2)
Permutation less-than operator.
Definition: permutation.h:429
Permutation mult(const Permutation &other) const
Product of this permutation by other.
Definition: permutation.h:314
Permutation::index_type index_type
Definition: permutation.h:612
index_type second_size() const
Definition: permutation.h:750
auto begin() const
Begin element iterator factory function.
Definition: permutation.h:643
void serialize(Archive &ar)
Serialize permutation.
Definition: permutation.h:758
Permutation identity() const
Identity permutation factory function.
Definition: permutation.h:308
auto outer(const Permutation &p)
Definition: permutation.h:820
const_iterator end() const
End element iterator factory function.
Definition: permutation.h:236
std::array< T, N > operator*(const Permutation &, const std::array< T, N > &)
Permute a std::array.
Definition: permutation.h:492
const auto & data() const
Permutation data accessor.
Definition: permutation.h:388
const Permutation & first() const
Definition: permutation.h:742
const Permutation & second() const
Definition: permutation.h:744
unsigned int index_type
Definition: permutation.h:133
#define TA_ASSERT(EXPR,...)
Definition: error.h:39
auto inner_size(const Permutation &p)
Definition: permutation.h:822
BipartitePermutation(const BipartitePermutation &)=default
index_type first_size() const
Definition: permutation.h:747
BipartitePermutation(InIter first, InIter last, index_type second_partition_size=0)
Construct permutation from a range [first,last)
Definition: permutation.h:708
BipartitePermutation & operator=(BipartitePermutation &&other)=default
Permutation(Permutation &&)=default
const_iterator begin() const
Begin element iterator factory function.
Definition: permutation.h:226
Permutation operator-(const Permutation &perm)
Inverse permutation operator.
Definition: permutation.h:452
Permutation(InIter first, InIter last)
Construct permutation from a range [first,last)
Definition: permutation.h:181
Permutation Permutation_
Definition: permutation.h:132
container::svector< T > vector
Definition: permutation.h:135
Permutation::vector< T > vector
Definition: permutation.h:614
Permutation(const Permutation &)=default
const_iterator cbegin() const
Begin element iterator factory function.
Definition: permutation.h:231
BipartitePermutation(vector< index_type > &&a, index_type second_partition_size=0)
std::vector move constructor
Definition: permutation.h:735
Permutation operator^(const Permutation &perm, int n)
Raise perm to the n-th power.
Definition: permutation.h:476
std::ostream & operator<<(std::ostream &os, const DistArray< Tile, Policy > &a)
Add the tensor to an output stream.
Definition: dist_array.h:1602
friend bool operator==(const BipartitePermutation &p1, const BipartitePermutation &p2)
Permutation equality operator.
Definition: permutation.h:795
BipartitePermutation(BipartitePermutation &&)=default
BipartitePermutation & operator=(const BipartitePermutation &)=default
auto size() const
Domain size accessor.
Definition: permutation.h:631
vector< vector< index_type > > cycles() const
Cycles decomposition.
Definition: permutation.h:264
Permutation(std::initializer_list< Integer > list)
Construct permutation with an initializer list.
Definition: permutation.h:208
std::array< T, N > & operator*=(std::array< T, N > &, const Permutation &)
In-place permute a std::array.
Definition: permutation.h:510
const_iterator cend() const
End element iterator factory function.
Definition: permutation.h:241
Permutation & operator=(const Permutation &)=default
auto cend() const
End element iterator factory function.
Definition: permutation.h:658
Permutation(const Index &a)
Array constructor.
Definition: permutation.h:191
vector< index_type >::const_iterator const_iterator
Definition: permutation.h:136
Permutation of a bipartite set.
Definition: permutation.h:610
auto end() const
End element iterator factory function.
Definition: permutation.h:653
BipartitePermutation(const Permutation &p, index_type second_partition_size=0)
Definition: permutation.h:679
auto outer_size(const Permutation &p)
Definition: permutation.h:827
Permutation(vector< index_type > &&a)
std::vector move constructor
Definition: permutation.h:198
bool operator!() const
Not operator.
Definition: permutation.h:383
auto inner(const Permutation &p)
Definition: permutation.h:813