Skip to content

Commit 6d0126d

Browse files
committed
Catch up with the changes; apply_permutation; constexpr, etc
2 parents daef6d4 + 3af7aca commit 6d0126d

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1240
-286
lines changed

doc/algorithm.qbk

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ Thanks to all the people who have reviewed this library and made suggestions for
6868
[include hex.qbk]
6969
[include is_palindrome.qbk]
7070
[include is_partitioned_until.qbk]
71+
[include apply_permutation.qbk]
7172
[endsect]
7273

7374

doc/apply_permutation.qbk

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
[/ File apply_permutation.qbk]
2+
3+
[section:apply_permutation apply_permutation]
4+
5+
[/license
6+
Copyright (c) 2017 Alexander Zaitsev
7+
8+
Distributed under the Boost Software License, Version 1.0.
9+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10+
]
11+
12+
The header file 'apply_permutation.hpp' contains two algorithms, apply_permutation and apply_reverse_permutation. Also there are range-based versions.
13+
The algorithms transform the item sequence according to index sequence order.
14+
15+
The routine `apply_permutation` takes a item sequence and a order sequence. It reshuffles item sequence according to order sequence. Every value in order sequence means where the item comes from. Order sequence needs to be exactly a permutation of the sequence [0, 1, ... , N], where N is the biggest index in the item sequence (zero-indexed).
16+
The routine `apply_reverse_permutation` takes a item sequence and a order sequence. It will reshuffle item sequence according to order sequence. Every value in order sequence means where the item goes to. Order sequence needs to be exactly a permutation of the sequence [0, 1, ... , N], where N is the biggest index in the item sequence (zero-indexed).
17+
18+
Implementations are based on these articles:
19+
https://blogs.msdn.microsoft.com/oldnewthing/20170102-00/?p=95095
20+
https://blogs.msdn.microsoft.com/oldnewthing/20170103-00/?p=95105
21+
https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115
22+
https://blogs.msdn.microsoft.com/oldnewthing/20170109-00/?p=95145
23+
https://blogs.msdn.microsoft.com/oldnewthing/20170110-00/?p=95155
24+
https://blogs.msdn.microsoft.com/oldnewthing/20170111-00/?p=95165
25+
26+
The routines come in 2 forms; the first one takes two iterators to define the item range and one iterator to define the beginning of index range. The second form takes range to define the item sequence and range to define index sequence.
27+
28+
29+
[heading interface]
30+
31+
There are two versions of algorithms:
32+
1) takes four iterators.
33+
2) takes two ranges.
34+
``
35+
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
36+
void apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
37+
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end);
38+
template<typename Range1, typename Range2>
39+
void apply_permutation(Range1& item_range, Range2& ind_range);
40+
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
41+
void apply_reverse_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
42+
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end);
43+
template<typename Range1, typename Range2>
44+
void apply_reverse_permutation(Range1& item_range, Range2& ind_range);
45+
``
46+
47+
48+
[heading Examples]
49+
50+
Given the containers:
51+
std::vector<int> emp_vec, emp_order,
52+
std::vector<int> one{1}, one_order{0},
53+
std::vector<int> two{1,2}, two_order{1,0},
54+
std::vector<int> vec{1, 2, 3, 4, 5},
55+
std::vector<int> order{4, 2, 3, 1, 0}, then
56+
``
57+
58+
apply_permutation(emp_vec, emp_order)) --> no changes
59+
apply_reverse_permutation(emp_vec, emp_order)) --> no changes
60+
apply_permutation(one, one_order) --> no changes
61+
apply_reverse_permutation(one, one_order) --> no changes
62+
apply_permutation(two, two_order) --> two:{2,1}
63+
apply_reverse_permutation(two, two_order) --> two:{2,1}
64+
apply_permutation(vec, order) --> vec:{5, 3, 4, 2, 1}
65+
apply_reverse_permutation(vec, order) --> vec:{5, 4, 2, 3, 1}
66+
``
67+
68+
[heading Iterator Requirements]
69+
70+
`apply_permutation` and 'apply_reverse_permutation' work only on RandomAccess iterators. RandomAccess iterators required both for item and index sequences.
71+
72+
[heading Complexity]
73+
74+
All of the variants of `apply_permutation` and `apply_reverse_permutation` run in ['O(N)] (linear) time.
75+
More
76+
77+
[heading Exception Safety]
78+
79+
All of the variants of `apply_permutation` and `apply_reverse_permutation` take their parameters by iterators or reference, and do not depend upon any global state. Therefore, all the routines in this file provide the strong exception guarantee.
80+
81+
[heading Notes]
82+
* If ItemSequence and IndexSequence are not equal, behavior is undefined.
83+
84+
* `apply_permutation` and `apply_reverse_permutation` work also on empty sequences.
85+
86+
* Order sequence must be zero-indexed.
87+
88+
* Order sequence gets permuted.
89+
90+
[endsect]
91+
92+
[/ File apply_permutation.qbk
93+
Copyright 2017 Alexander Zaitsev
94+
Distributed under the Boost Software License, Version 1.0.
95+
(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt).
96+
]

example/Jamfile.v2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ exe clamp_example : clamp_example.cpp ;
2222
exe search_example : search_example.cpp ;
2323
exe is_palindrome_example : is_palindrome_example.cpp;
2424
exe is_partitioned_until_example : is_partitioned_until_example.cpp;
25-
25+
exe apply_permutation_example : apply_permutation_example.cpp;

example/apply_permutation_example.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/*
2+
Copyright (c) Alexander Zaitsev <[email protected]>, 2017
3+
4+
Distributed under the Boost Software License, Version 1.0. (See
5+
accompanying file LICENSE_1_0.txt or copy at
6+
http://www.boost.org/LICENSE_1_0.txt)
7+
8+
See http://www.boost.org/ for latest version.
9+
*/
10+
11+
#include <vector>
12+
#include <iostream>
13+
14+
#include <boost/algorithm/apply_permutation.hpp>
15+
16+
17+
namespace ba = boost::algorithm;
18+
19+
int main ( int /*argc*/, char * /*argv*/ [] )
20+
{
21+
// WARNING: Example require C++11 or newer compiler
22+
{
23+
std::cout << "apply_permutation with iterators:\n";
24+
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
25+
26+
ba::apply_permutation(vec.begin(), vec.end(), order.begin(), order.end());
27+
for (const auto& x : vec)
28+
{
29+
std::cout << x << ", ";
30+
}
31+
std::cout << std::endl;
32+
}
33+
{
34+
std::cout << "apply_reverse_permutation with iterators:\n";
35+
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
36+
37+
ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin(), order.end());
38+
for (const auto& x : vec)
39+
{
40+
std::cout << x << ", ";
41+
}
42+
std::cout << std::endl;
43+
}
44+
{
45+
std::cout << "apply_reverse_permutation with ranges:\n";
46+
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
47+
48+
ba::apply_reverse_permutation(vec, order);
49+
for (const auto& x : vec)
50+
{
51+
std::cout << x << ", ";
52+
}
53+
std::cout << std::endl;
54+
}
55+
{
56+
std::cout << "apply_permutation with ranges:\n";
57+
std::vector<int> vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0};
58+
59+
ba::apply_permutation(vec, order);
60+
for (const auto& x : vec)
61+
{
62+
std::cout << x << ", ";
63+
}
64+
std::cout << std::endl;
65+
}
66+
67+
return 0;
68+
}
69+

include/boost/algorithm/algorithm.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,10 @@
2525
namespace boost { namespace algorithm {
2626

2727
template <typename T>
28-
T identity_operation ( std::multiplies<T> ) { return T(1); }
28+
BOOST_CXX14_CONSTEXPR T identity_operation ( std::multiplies<T> ) { return T(1); }
2929

3030
template <typename T>
31-
T identity_operation ( std::plus<T> ) { return T(0); }
31+
BOOST_CXX14_CONSTEXPR T identity_operation ( std::plus<T> ) { return T(0); }
3232

3333

3434
/// \fn power ( T x, Integer n )
@@ -40,7 +40,7 @@ T identity_operation ( std::plus<T> ) { return T(0); }
4040
// \remark Taken from Knuth, The Art of Computer Programming, Volume 2:
4141
// Seminumerical Algorithms, Section 4.6.3
4242
template <typename T, typename Integer>
43-
typename boost::enable_if<boost::is_integral<Integer>, T>::type
43+
BOOST_CXX14_CONSTEXPR typename boost::enable_if<boost::is_integral<Integer>, T>::type
4444
power (T x, Integer n) {
4545
T y = 1; // Should be "T y{1};"
4646
if (n == 0) return y;
@@ -67,7 +67,7 @@ power (T x, Integer n) {
6767
// \remark Taken from Knuth, The Art of Computer Programming, Volume 2:
6868
// Seminumerical Algorithms, Section 4.6.3
6969
template <typename T, typename Integer, typename Operation>
70-
typename boost::enable_if<boost::is_integral<Integer>, T>::type
70+
BOOST_CXX14_CONSTEXPR typename boost::enable_if<boost::is_integral<Integer>, T>::type
7171
power (T x, Integer n, Operation op) {
7272
T y = identity_operation(op);
7373
if (n == 0) return y;
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
Copyright (c) Alexander Zaitsev <[email protected]>, 2017
3+
4+
Distributed under the Boost Software License, Version 1.0. (See
5+
accompanying file LICENSE_1_0.txt or copy at
6+
http://www.boost.org/LICENSE_1_0.txt)
7+
8+
See http://www.boost.org/ for latest version.
9+
10+
11+
Based on https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115
12+
*/
13+
14+
/// \file apply_permutation.hpp
15+
/// \brief Apply permutation to a sequence.
16+
/// \author Alexander Zaitsev
17+
18+
#ifndef BOOST_ALGORITHM_APPLY_PERMUTATION_HPP
19+
#define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP
20+
21+
#include <algorithm>
22+
#include <type_traits>
23+
24+
#include <boost/range/begin.hpp>
25+
#include <boost/range/end.hpp>
26+
27+
namespace boost { namespace algorithm
28+
{
29+
30+
/// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
31+
/// \brief Reorder item sequence with index sequence order
32+
///
33+
/// \param item_begin The start of the item sequence
34+
/// \param item_end One past the end of the item sequence
35+
/// \param ind_begin The start of the index sequence.
36+
///
37+
/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
38+
/// Complexity: O(N).
39+
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
40+
void
41+
apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end,
42+
RandomAccessIterator2 ind_begin, RandomAccessIterator2 ind_end)
43+
{
44+
using Diff = typename std::iterator_traits<RandomAccessIterator1>::difference_type;
45+
using std::swap;
46+
Diff size = std::distance(item_begin, item_end);
47+
for (Diff i = 0; i < size; i++)
48+
{
49+
auto current = i;
50+
while (i != ind_begin[current])
51+
{
52+
auto next = ind_begin[current];
53+
swap(item_begin[current], item_begin[next]);
54+
ind_begin[current] = current;
55+
current = next;
56+
}
57+
ind_begin[current] = current;
58+
}
59+
}
60+
61+
/// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin )
62+
/// \brief Reorder item sequence with index sequence order
63+
///
64+
/// \param item_begin The start of the item sequence
65+
/// \param item_end One past the end of the item sequence
66+
/// \param ind_begin The start of the index sequence.
67+
///
68+
/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
69+
/// Complexity: O(N).
70+
template<typename RandomAccessIterator1, typename RandomAccessIterator2>
71+
void
72+
apply_reverse_permutation(
73+
RandomAccessIterator1 item_begin,
74+
RandomAccessIterator1 item_end,
75+
RandomAccessIterator2 ind_begin,
76+
RandomAccessIterator2 ind_end)
77+
{
78+
using Diff = typename std::iterator_traits<RandomAccessIterator2>::difference_type;
79+
using std::swap;
80+
Diff length = std::distance(item_begin, item_end);
81+
for (Diff i = 0; i < length; i++)
82+
{
83+
while (i != ind_begin[i])
84+
{
85+
Diff next = ind_begin[i];
86+
swap(item_begin[i], item_begin[next]);
87+
swap(ind_begin[i], ind_begin[next]);
88+
}
89+
}
90+
}
91+
92+
/// \fn apply_permutation ( Range1 item_range, Range2 ind_range )
93+
/// \brief Reorder item sequence with index sequence order
94+
///
95+
/// \param item_range The item sequence
96+
/// \param ind_range The index sequence
97+
///
98+
/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
99+
/// Complexity: O(N).
100+
template<typename Range1, typename Range2>
101+
void
102+
apply_permutation(Range1& item_range, Range2& ind_range)
103+
{
104+
apply_permutation(boost::begin(item_range), boost::end(item_range),
105+
boost::begin(ind_range), boost::end(ind_range));
106+
}
107+
108+
/// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range )
109+
/// \brief Reorder item sequence with index sequence order
110+
///
111+
/// \param item_range The item sequence
112+
/// \param ind_range The index sequence
113+
///
114+
/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined.
115+
/// Complexity: O(N).
116+
template<typename Range1, typename Range2>
117+
void
118+
apply_reverse_permutation(Range1& item_range, Range2& ind_range)
119+
{
120+
apply_reverse_permutation(boost::begin(item_range), boost::end(item_range),
121+
boost::begin(ind_range), boost::end(ind_range));
122+
}
123+
124+
}}
125+
#endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP

0 commit comments

Comments
 (0)