permutation.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // (C) Copyright Jeremy Siek 2001.
  2. // Distributed under the Boost Software License, Version 1.0. (See
  3. // accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_PERMUTATION_HPP
  6. #define BOOST_PERMUTATION_HPP
  7. #include <vector>
  8. #include <memory>
  9. #include <functional>
  10. #include <algorithm>
  11. #include <boost/graph/detail/shadow_iterator.hpp>
  12. namespace boost {
  13. template <class Iter1, class Iter2>
  14. void permute_serial(Iter1 permuter, Iter1 last, Iter2 result)
  15. {
  16. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  17. typedef std::ptrdiff_t D:
  18. #else
  19. typedef typename std::iterator_traits<Iter1>::difference_type D;
  20. #endif
  21. D n = 0;
  22. while (permuter != last) {
  23. std::swap(result[n], result[*permuter]);
  24. ++n;
  25. ++permuter;
  26. }
  27. }
  28. template <class InIter, class RandIterP, class RandIterR>
  29. void permute_copy(InIter first, InIter last, RandIterP p, RandIterR result)
  30. {
  31. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  32. typedef std::ptrdiff_t i = 0;
  33. #else
  34. typename std::iterator_traits<RandIterP>::difference_type i = 0;
  35. #endif
  36. for (; first != last; ++first, ++i)
  37. result[p[i]] = *first;
  38. }
  39. namespace detail {
  40. template <class RandIter, class RandIterPerm, class D, class T>
  41. void permute_helper(RandIter first, RandIter last, RandIterPerm p, D, T)
  42. {
  43. D i = 0, pi, n = last - first, cycle_start;
  44. T tmp;
  45. std::vector<int> visited(n, false);
  46. while (i != n) { // continue until all elements have been processed
  47. cycle_start = i;
  48. tmp = first[i];
  49. do { // walk around a cycle
  50. pi = p[i];
  51. visited[pi] = true;
  52. std::swap(tmp, first[pi]);
  53. i = pi;
  54. } while (i != cycle_start);
  55. // find the next cycle
  56. for (i = 0; i < n; ++i)
  57. if (visited[i] == false)
  58. break;
  59. }
  60. }
  61. } // namespace detail
  62. template <class RandIter, class RandIterPerm>
  63. void permute(RandIter first, RandIter last, RandIterPerm p)
  64. {
  65. detail::permute_helper(first, last, p, last - first, *first);
  66. }
  67. // Knuth 1.3.3, Vol. 1 p 176
  68. // modified for zero-based arrays
  69. // time complexity?
  70. //
  71. // WARNING: T must be a signed integer!
  72. template <class PermIter>
  73. void invert_permutation(PermIter X, PermIter Xend)
  74. {
  75. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  76. typedef std::ptrdiff_t T:
  77. #else
  78. typedef typename std::iterator_traits<PermIter>::value_type T;
  79. #endif
  80. T n = Xend - X;
  81. T m = n;
  82. T j = -1;
  83. while (m > 0) {
  84. T i = X[m-1] + 1;
  85. if (i > 0) {
  86. do {
  87. X[m-1] = j - 1;
  88. j = -m;
  89. m = i;
  90. i = X[m-1] + 1;
  91. } while (i > 0);
  92. i = j;
  93. }
  94. X[m-1] = -i - 1;
  95. --m;
  96. }
  97. }
  98. // Takes a "normal" permutation array (and its inverse), and turns it
  99. // into a BLAS-style permutation array (which can be thought of as a
  100. // serialized permutation).
  101. template <class Iter1, class Iter2, class Iter3>
  102. inline void serialize_permutation(Iter1 q, Iter1 q_end, Iter2 q_inv, Iter3 p)
  103. {
  104. #ifdef BOOST_NO_STD_ITERATOR_TRAITS
  105. typedef std::ptrdiff_t P1;
  106. typedef std::ptrdiff_t P2;
  107. typedef std::ptrdiff_t D;
  108. #else
  109. typedef typename std::iterator_traits<Iter1>::value_type P1;
  110. typedef typename std::iterator_traits<Iter2>::value_type P2;
  111. typedef typename std::iterator_traits<Iter1>::difference_type D;
  112. #endif
  113. D n = q_end - q;
  114. for (D i = 0; i < n; ++i) {
  115. P1 qi = q[i];
  116. P2 qii = q_inv[i];
  117. *p++ = qii;
  118. std::swap(q[i], q[qii]);
  119. std::swap(q_inv[i], q_inv[qi]);
  120. }
  121. }
  122. // Not used anymore, leaving it here for future reference.
  123. template <typename Iter, typename Compare>
  124. void merge_sort(Iter first, Iter last, Compare cmp)
  125. {
  126. if (first + 1 < last) {
  127. Iter mid = first + (last - first)/2;
  128. merge_sort(first, mid, cmp);
  129. merge_sort(mid, last, cmp);
  130. std::inplace_merge(first, mid, last, cmp);
  131. }
  132. }
  133. // time: N log N + 3N + ?
  134. // space: 2N
  135. template <class Iter, class IterP, class Cmp, class Alloc>
  136. inline void sortp(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc)
  137. {
  138. typedef typename std::iterator_traits<IterP>::value_type P;
  139. typedef typename std::iterator_traits<IterP>::difference_type D;
  140. D n = last - first;
  141. std::vector<P, Alloc> q(n);
  142. for (D i = 0; i < n; ++i)
  143. q[i] = i;
  144. std::sort(make_shadow_iter(first, q.begin()),
  145. make_shadow_iter(last, q.end()),
  146. shadow_cmp<Cmp>(cmp));
  147. invert_permutation(q.begin(), q.end());
  148. std::copy(q.begin(), q.end(), p);
  149. }
  150. template <class Iter, class IterP, class Cmp>
  151. inline void sortp(Iter first, Iter last, IterP p, Cmp cmp)
  152. {
  153. typedef typename std::iterator_traits<IterP>::value_type P;
  154. sortp(first, last, p, cmp, std::allocator<P>());
  155. }
  156. template <class Iter, class IterP>
  157. inline void sortp(Iter first, Iter last, IterP p)
  158. {
  159. typedef typename std::iterator_traits<Iter>::value_type T;
  160. typedef typename std::iterator_traits<IterP>::value_type P;
  161. sortp(first, last, p, std::less<T>(), std::allocator<P>());
  162. }
  163. template <class Iter, class IterP, class Cmp, class Alloc>
  164. inline void sortv(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc)
  165. {
  166. typedef typename std::iterator_traits<IterP>::value_type P;
  167. typedef typename std::iterator_traits<IterP>::difference_type D;
  168. D n = last - first;
  169. std::vector<P, Alloc> q(n), q_inv(n);
  170. for (D i = 0; i < n; ++i)
  171. q_inv[i] = i;
  172. std::sort(make_shadow_iter(first, q_inv.begin()),
  173. make_shadow_iter(last, q_inv.end()),
  174. shadow_cmp<Cmp>(cmp));
  175. std::copy(q_inv, q_inv.end(), q.begin());
  176. invert_permutation(q.begin(), q.end());
  177. serialize_permutation(q.begin(), q.end(), q_inv.end(), p);
  178. }
  179. } // namespace boost
  180. #endif // BOOST_PERMUTATION_HPP