permutation.hpp 5.9 KB

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