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) 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 <TiledArray/error.h>
24 #include <TiledArray/type_traits.h>
25 #include <TiledArray/utility.h>
26 #include <array>
27 #include <numeric>
28 
29 namespace TiledArray {
30 
31  // Forward declarations
32  class Permutation;
33  bool operator==(const Permutation&, const Permutation&);
34  std::ostream& operator<<(std::ostream&, const Permutation&);
35  template <typename T, std::size_t N>
36  inline std::array<T,N> operator*(const Permutation&, const std::array<T, N>&);
37  template <typename T, std::size_t N>
38  inline std::array<T,N>& operator*=(std::array<T,N>&, const Permutation&);
39  template <typename T, typename A>
40  inline std::vector<T> operator*(const Permutation&, const std::vector<T, A>&);
41  template <typename T, typename A>
42  inline std::vector<T, A>& operator*=(std::vector<T, A>&, const Permutation&);
43  template <typename T>
44  inline std::vector<T> operator*(const Permutation&, const T* MADNESS_RESTRICT const);
45 
46  namespace detail {
47 
49 
56  template <typename Perm, typename Arg, typename Result>
57  inline void permute_array(const Perm& perm, const Arg& arg, Result& result) {
58  TA_ASSERT(size(result) == size(arg));
59  const unsigned int n = size(arg);
60  for(unsigned int i = 0u; i < n; ++i) {
61  const typename Perm::index_type pi = perm[i];
62  TA_ASSERT(i < size(arg));
63  TA_ASSERT(pi < size(result));
64  result[pi] = arg[i];
65  }
66  }
67  } // namespace detail
68 
69 
75 
119  class Permutation {
120  public:
122  typedef unsigned int index_type;
123  typedef std::vector<index_type>::const_iterator const_iterator;
124 
125  private:
126 
128  std::vector<index_type> p_;
129 
132  template <typename InIter>
133  bool valid_permutation(InIter first, InIter last) {
134  bool result = true;
135  using diff_type = typename std::iterator_traits<InIter>::difference_type;
136  const diff_type n = std::distance(first, last);
137  TA_ASSERT(n >= 0);
138  for(; first != last; ++first) {
139  const diff_type value = *first;
140  result = result && value >= 0 && (value < n) && (std::count(first, last, *first) == 1ul);
141  }
142  return result;
143  }
144 
145  // Used to select the correct constructor based on input template types
146  struct Enabler { };
147 
148  public:
149 
150  Permutation() = default; // constructs an invalid Permutation
151  Permutation(const Permutation&) = default;
152  Permutation(Permutation&&) = default;
153  ~Permutation() = default;
154  Permutation& operator=(const Permutation&) = default;
155  Permutation& operator=(Permutation&& other) = default;
156 
158 
165  template <typename InIter,
166  typename std::enable_if<detail::is_input_iterator<InIter>::value>::type* = nullptr>
167  Permutation(InIter first, InIter last) :
168  p_(first, last)
169  {
170  TA_ASSERT( valid_permutation(first, last) );
171  }
172 
174 
177  template <typename Integer>
178  explicit Permutation(const std::vector<Integer>& a) :
179  Permutation(a.begin(), a.end())
180  {
181  }
182 
184 
187  explicit Permutation(std::vector<index_type>&& a) :
188  p_(std::move(a))
189  {
190  TA_ASSERT( valid_permutation(p_.begin(), p_.end()) );
191  }
192 
194 
197  template <typename Integer,
198  typename std::enable_if<std::is_integral<Integer>::value>::type* = nullptr>
199  explicit Permutation(std::initializer_list<Integer> list) :
200  Permutation(list.begin(), list.end())
201  { }
202 
204 
206  index_type dim() const { return p_.size(); }
207 
209 
211  const_iterator begin() const { return p_.begin(); }
212 
214 
216  const_iterator cbegin() const { return p_.cbegin(); }
217 
219 
221  const_iterator end() const { return p_.end(); }
222 
224 
226  const_iterator cend() const { return p_.cend(); }
227 
229 
232  index_type operator[](unsigned int i) const { return p_[i]; }
233 
235 
248  std::vector<std::vector<index_type> > cycles() const {
249 
250  std::vector<std::vector<index_type>> result;
251 
252  std::vector<bool> placed_in_cycle(p_.size(), false);
253 
254  // 1. for each i compute its orbit
255  // 2. if the orbit is longer than 1, sort and add to the list of cycles
256  for(index_type i=0; i!= p_.size(); ++i) {
257  if (not placed_in_cycle[i]) {
258  std::vector<index_type> cycle(1,i);
259  placed_in_cycle[i] = true;
260 
261  index_type next_i = p_[i];
262  while (next_i != i) {
263  cycle.push_back(next_i);
264  placed_in_cycle[next_i] = true;
265  next_i = p_[next_i];
266  }
267 
268  if (cycle.size() != 1) {
269  std::sort(cycle.begin(), cycle.end());
270  result.emplace_back(cycle);
271  }
272 
273  } // this i already in a cycle
274  } // loop over i
275 
276  return result;
277  }
278 
280 
283  static Permutation identity(const unsigned int dim) {
284  Permutation result;
285  result.p_.reserve(dim);
286  for(unsigned int i = 0u; i < dim; ++i)
287  result.p_.emplace_back(i);
288  return result;
289  }
290 
292 
294  Permutation identity() const { return identity(p_.size()); }
295 
297 
300  Permutation mult(const Permutation& other) const {
301  const unsigned int n = p_.size();
302  TA_ASSERT(n == other.p_.size());
303  Permutation result;
304  result.p_.reserve(n);
305 
306  for(unsigned int i = 0u; i < n; ++i) {
307  const index_type p_i = p_[i];
308  const index_type result_i = other.p_[p_i];
309  result.p_.emplace_back(result_i);
310  }
311 
312  return result;
313  }
314 
316 
320  Permutation inv() const {
321  const index_type n = p_.size();
322  Permutation result;
323  result.p_.resize(n, 0ul);
324  for(index_type i = 0ul; i < n; ++i) {
325  const index_type pi = p_[i];
326  result.p_[pi] = i;
327  }
328  return result;
329  }
330 
332 
337  Permutation pow(int n) const {
338  // Initialize the algorithm inputs
339  int power;
340  Permutation value;
341  if(n < 0) {
342  value = inv();
343  power = -n;
344  } else {
345  value = *this;
346  power = n;
347  }
348 
349  Permutation result = identity(p_.size());
350 
351  // Compute the power of value with the exponentiation by squaring.
352  while(power) {
353  if(power & 1)
354  result = result.mult(value);
355  value = value.mult(value);
356  power >>= 1;
357  }
358 
359  return result;
360  }
361 
363 
365  operator bool() const { return ! p_.empty(); }
366 
368 
370  bool operator!() const { return p_.empty(); }
371 
373 
375  const std::vector<index_type>& data() const { return p_; }
376 
378 
382  template <typename Archive>
383  void serialize(Archive& ar) {
384  ar & p_;
385  }
386 
387  }; // class Permutation
388 
390 
395  inline bool operator==(const Permutation& p1, const Permutation& p2) {
396  return (p1.dim() == p2.dim())
397  && std::equal(p1.data().begin(), p1.data().end(), p2.data().begin());
398  }
399 
401 
406  inline bool operator!=(const Permutation& p1, const Permutation& p2) {
407  return ! operator==(p1, p2);
408  }
409 
411 
416  inline bool operator<(const Permutation& p1, const Permutation& p2) {
417  return std::lexicographical_compare(p1.data().begin(), p1.data().end(),
418  p2.data().begin(), p2.data().end());
419  }
420 
422 
426  inline std::ostream& operator<<(std::ostream& output, const Permutation& p) {
427  std::size_t n = p.dim();
428  output << "{";
429  for (unsigned int dim = 0; dim < n - 1; ++dim)
430  output << dim << "->" << p.data()[dim] << ", ";
431  output << n - 1 << "->" << p.data()[n - 1] << "}";
432  return output;
433  }
434 
435 
437 
440  inline Permutation operator -(const Permutation& perm) {
441  return perm.inv();
442  }
443 
445 
450  inline Permutation operator*(const Permutation& p1, const Permutation& p2) {
451  return p1.mult(p2);
452  }
453 
454 
456  inline Permutation& operator*=(Permutation& p1, const Permutation& p2) {
457  return (p1 = p1 * p2);
458  }
459 
461 
467  inline Permutation operator^(const Permutation& perm, int n) {
468  return perm.pow(n);
469  }
470 
474 
483  template <typename T, std::size_t N>
484  inline std::array<T,N> operator*(const Permutation& perm, const std::array<T, N>& a) {
485  TA_ASSERT(perm.dim() == a.size());
486  std::array<T,N> result;
487  detail::permute_array(perm, a, result);
488  return result;
489  }
490 
492 
500  template <typename T, std::size_t N>
501  inline std::array<T,N>& operator*=(std::array<T,N>& a, const Permutation& perm) {
502  TA_ASSERT(perm.dim() == a.size());
503  const std::array<T,N> temp = a;
504  detail::permute_array(perm, temp, a);
505  return a;
506  }
507 
509 
517  template <typename T, typename A>
518  inline std::vector<T> operator*(const Permutation& perm, const std::vector<T, A>& v) {
519  TA_ASSERT(perm.dim() == v.size());
520  std::vector<T> result(perm.dim());
521  detail::permute_array(perm, v, result);
522  return result;
523  }
524 
526 
534  template <typename T, typename A>
535  inline std::vector<T, A>& operator*=(std::vector<T, A>& v, const Permutation& perm) {
536  const std::vector<T, A> temp = v;
537  detail::permute_array(perm, temp, v);
538  return v;
539  }
540 
542 
547  template <typename T>
548  inline std::vector<T> operator*(const Permutation& perm, const T* MADNESS_RESTRICT const ptr) {
549  const unsigned int n = perm.dim();
550  std::vector<T> result(n);
551  for(unsigned int i = 0u; i < n; ++i) {
552  const typename Permutation::index_type perm_i = perm[i];
553  const T ptr_i = ptr[i];
554  result[perm_i] = ptr_i;
555  }
556  return result;
557  }
558 
559 } // namespace TiledArray
560 
561 #endif // TILEDARRAY_PERMUTATION_H__INCLUED
constexpr bool operator==(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:178
void permute_array(const Perm &perm, const Arg &arg, Result &result)
Create a permuted copy of an array.
Definition: permutation.h:57
Permutation & operator=(const Permutation &)=default
unsigned int index_type
Definition: permutation.h:122
const_iterator end() const
End element iterator factory function.
Definition: permutation.h:221
bool operator<(const Permutation &p1, const Permutation &p2)
Permutation less-than operator.
Definition: permutation.h:416
const_iterator cend() const
End element iterator factory function.
Definition: permutation.h:226
STL namespace.
std::vector< std::vector< index_type > > cycles() const
Cycles decomposition.
Definition: permutation.h:248
constexpr bool operator!=(const DenseShape &a, const DenseShape &b)
Definition: dense_shape.h:179
bool operator!() const
Not operator.
Definition: permutation.h:370
std::array< T, N > operator*(const Permutation &, const std::array< T, N > &)
Permute a std::array.
Definition: permutation.h:484
Permutation inv() const
Construct the inverse of this permutation.
Definition: permutation.h:320
Permutation Permutation_
Definition: permutation.h:121
Permutation(const std::vector< Integer > &a)
Array constructor.
Definition: permutation.h:178
std::vector< index_type >::const_iterator const_iterator
Definition: permutation.h:123
index_type dim() const
Domain size accessor.
Definition: permutation.h:206
const std::vector< index_type > & data() const
Permutation data accessor.
Definition: permutation.h:375
constexpr std::size_t size(T(&)[N])
Array size accessor.
Definition: utility.h:47
index_type operator[](unsigned int i) const
Element accessor.
Definition: permutation.h:232
Permutation operator-(const Permutation &perm)
Inverse permutation operator.
Definition: permutation.h:440
#define TA_ASSERT(a)
Definition: error.h:107
Permutation(std::initializer_list< Integer > list)
Construct permutation with an initializer list.
Definition: permutation.h:199
Permutation identity() const
Identity permutation factory function.
Definition: permutation.h:294
std::array< T, N > & operator*=(std::array< T, N > &, const Permutation &)
In-place permute a std::array.
Definition: permutation.h:501
Permutation operator^(const Permutation &perm, int n)
Raise perm to the n-th power.
Definition: permutation.h:467
Permutation(std::vector< index_type > &&a)
std::vector move constructor
Definition: permutation.h:187
std::ostream & operator<<(std::ostream &os, const DistArray< Tile, Policy > &a)
Add the tensor to an output stream.
Definition: dist_array.h:853
void serialize(Archive &ar)
Serialize permutation.
Definition: permutation.h:383
Permutation of a sequence of objects indexed by base-0 indices.
Definition: permutation.h:119
const_iterator cbegin() const
Begin element iterator factory function.
Definition: permutation.h:216
const_iterator begin() const
Begin element iterator factory function.
Definition: permutation.h:211
Permutation(InIter first, InIter last)
Construct permutation from a range [first,last)
Definition: permutation.h:167
Permutation mult(const Permutation &other) const
Product of this permutation by other.
Definition: permutation.h:300
Permutation pow(int n) const
Raise this permutation to the n-th power.
Definition: permutation.h:337
static Permutation identity(const unsigned int dim)
Identity permutation factory function.
Definition: permutation.h:283