sl@0: // (C) Copyright Jeremy Siek 2001. sl@0: // Distributed under the Boost Software License, Version 1.0. (See sl@0: // accompanying file LICENSE_1_0.txt or copy at sl@0: // http://www.boost.org/LICENSE_1_0.txt) sl@0: sl@0: #ifndef BOOST_PERMUTATION_HPP sl@0: #define BOOST_PERMUTATION_HPP sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: namespace boost { sl@0: sl@0: template sl@0: void permute_serial(Iter1 permuter, Iter1 last, Iter2 result) sl@0: { sl@0: #ifdef BOOST_NO_STD_ITERATOR_TRAITS sl@0: typedef std::ptrdiff_t D: sl@0: #else sl@0: typedef typename std::iterator_traits::difference_type D; sl@0: #endif sl@0: sl@0: D n = 0; sl@0: while (permuter != last) { sl@0: std::swap(result[n], result[*permuter]); sl@0: ++n; sl@0: ++permuter; sl@0: } sl@0: } sl@0: sl@0: template sl@0: void permute_copy(InIter first, InIter last, RandIterP p, RandIterR result) sl@0: { sl@0: #ifdef BOOST_NO_STD_ITERATOR_TRAITS sl@0: typedef std::ptrdiff_t i = 0; sl@0: #else sl@0: typename std::iterator_traits::difference_type i = 0; sl@0: #endif sl@0: for (; first != last; ++first, ++i) sl@0: result[p[i]] = *first; sl@0: } sl@0: sl@0: namespace detail { sl@0: sl@0: template sl@0: void permute_helper(RandIter first, RandIter last, RandIterPerm p, D, T) sl@0: { sl@0: D i = 0, pi, n = last - first, cycle_start; sl@0: T tmp; sl@0: std::vector visited(n, false); sl@0: sl@0: while (i != n) { // continue until all elements have been processed sl@0: cycle_start = i; sl@0: tmp = first[i]; sl@0: do { // walk around a cycle sl@0: pi = p[i]; sl@0: visited[pi] = true; sl@0: std::swap(tmp, first[pi]); sl@0: i = pi; sl@0: } while (i != cycle_start); sl@0: sl@0: // find the next cycle sl@0: for (i = 0; i < n; ++i) sl@0: if (visited[i] == false) sl@0: break; sl@0: } sl@0: } sl@0: sl@0: } // namespace detail sl@0: sl@0: template sl@0: void permute(RandIter first, RandIter last, RandIterPerm p) sl@0: { sl@0: detail::permute_helper(first, last, p, last - first, *first); sl@0: } sl@0: sl@0: sl@0: // Knuth 1.3.3, Vol. 1 p 176 sl@0: // modified for zero-based arrays sl@0: // time complexity? sl@0: // sl@0: // WARNING: T must be a signed integer! sl@0: template sl@0: void invert_permutation(PermIter X, PermIter Xend) sl@0: { sl@0: #ifdef BOOST_NO_STD_ITERATOR_TRAITS sl@0: typedef std::ptrdiff_t T: sl@0: #else sl@0: typedef typename std::iterator_traits::value_type T; sl@0: #endif sl@0: T n = Xend - X; sl@0: T m = n; sl@0: T j = -1; sl@0: sl@0: while (m > 0) { sl@0: T i = X[m-1] + 1; sl@0: if (i > 0) { sl@0: do { sl@0: X[m-1] = j - 1; sl@0: j = -m; sl@0: m = i; sl@0: i = X[m-1] + 1; sl@0: } while (i > 0); sl@0: i = j; sl@0: } sl@0: X[m-1] = -i - 1; sl@0: --m; sl@0: } sl@0: } sl@0: sl@0: // Takes a "normal" permutation array (and its inverse), and turns it sl@0: // into a BLAS-style permutation array (which can be thought of as a sl@0: // serialized permutation). sl@0: template sl@0: inline void serialize_permutation(Iter1 q, Iter1 q_end, Iter2 q_inv, Iter3 p) sl@0: { sl@0: #ifdef BOOST_NO_STD_ITERATOR_TRAITS sl@0: typedef std::ptrdiff_t P1; sl@0: typedef std::ptrdiff_t P2; sl@0: typedef std::ptrdiff_t D; sl@0: #else sl@0: typedef typename std::iterator_traits::value_type P1; sl@0: typedef typename std::iterator_traits::value_type P2; sl@0: typedef typename std::iterator_traits::difference_type D; sl@0: #endif sl@0: D n = q_end - q; sl@0: for (D i = 0; i < n; ++i) { sl@0: P1 qi = q[i]; sl@0: P2 qii = q_inv[i]; sl@0: *p++ = qii; sl@0: std::swap(q[i], q[qii]); sl@0: std::swap(q_inv[i], q_inv[qi]); sl@0: } sl@0: } sl@0: sl@0: // Not used anymore, leaving it here for future reference. sl@0: template sl@0: void merge_sort(Iter first, Iter last, Compare cmp) sl@0: { sl@0: if (first + 1 < last) { sl@0: Iter mid = first + (last - first)/2; sl@0: merge_sort(first, mid, cmp); sl@0: merge_sort(mid, last, cmp); sl@0: std::inplace_merge(first, mid, last, cmp); sl@0: } sl@0: } sl@0: sl@0: sl@0: // time: N log N + 3N + ? sl@0: // space: 2N sl@0: template sl@0: inline void sortp(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc) sl@0: { sl@0: typedef typename std::iterator_traits::value_type P; sl@0: typedef typename std::iterator_traits::difference_type D; sl@0: D n = last - first; sl@0: std::vector q(n); sl@0: for (D i = 0; i < n; ++i) sl@0: q[i] = i; sl@0: std::sort(make_shadow_iter(first, q.begin()), sl@0: make_shadow_iter(last, q.end()), sl@0: shadow_cmp(cmp)); sl@0: invert_permutation(q.begin(), q.end()); sl@0: std::copy(q.begin(), q.end(), p); sl@0: } sl@0: sl@0: template sl@0: inline void sortp(Iter first, Iter last, IterP p, Cmp cmp) sl@0: { sl@0: typedef typename std::iterator_traits::value_type P; sl@0: sortp(first, last, p, cmp, std::allocator

()); sl@0: } sl@0: sl@0: template sl@0: inline void sortp(Iter first, Iter last, IterP p) sl@0: { sl@0: typedef typename std::iterator_traits::value_type T; sl@0: typedef typename std::iterator_traits::value_type P; sl@0: sortp(first, last, p, std::less(), std::allocator

()); sl@0: } sl@0: sl@0: template sl@0: inline void sortv(Iter first, Iter last, IterP p, Cmp cmp, Alloc alloc) sl@0: { sl@0: typedef typename std::iterator_traits::value_type P; sl@0: typedef typename std::iterator_traits::difference_type D; sl@0: D n = last - first; sl@0: std::vector q(n), q_inv(n); sl@0: for (D i = 0; i < n; ++i) sl@0: q_inv[i] = i; sl@0: std::sort(make_shadow_iter(first, q_inv.begin()), sl@0: make_shadow_iter(last, q_inv.end()), sl@0: shadow_cmp(cmp)); sl@0: std::copy(q_inv, q_inv.end(), q.begin()); sl@0: invert_permutation(q.begin(), q.end()); sl@0: serialize_permutation(q.begin(), q.end(), q_inv.end(), p); sl@0: } sl@0: sl@0: sl@0: } // namespace boost sl@0: sl@0: #endif // BOOST_PERMUTATION_HPP