From 1ed284d6961505a1d57d94b4ab07fdb2b0eff2e5 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Thu, 18 May 2017 20:38:07 -0600 Subject: [PATCH 01/13] Added initial for apply_permutation --- example/apply_permutation_example.cpp | 68 ++++++++++ include/boost/algorithm/apply_permutation.hpp | 122 ++++++++++++++++++ 2 files changed, 190 insertions(+) create mode 100644 example/apply_permutation_example.cpp create mode 100644 include/boost/algorithm/apply_permutation.hpp diff --git a/example/apply_permutation_example.cpp b/example/apply_permutation_example.cpp new file mode 100644 index 000000000..feaa9f280 --- /dev/null +++ b/example/apply_permutation_example.cpp @@ -0,0 +1,68 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. +*/ + +#include +#include + +#include + + +namespace ba = boost::algorithm; + +int main ( int /*argc*/, char * /*argv*/ [] ) +{ + { + std::cout << "apply_permutation with iterators:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + { + std::cout << "apply_reverse_permutation with iterators:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + { + std::cout << "apply_reverse_permutation with ranges:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::apply_reverse_permutation(vec, order); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + { + std::cout << "apply_permutation with ranges:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::apply_permutation(vec, order); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + + return 0; +} + diff --git a/include/boost/algorithm/apply_permutation.hpp b/include/boost/algorithm/apply_permutation.hpp new file mode 100644 index 000000000..f14ba65c5 --- /dev/null +++ b/include/boost/algorithm/apply_permutation.hpp @@ -0,0 +1,122 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. + + + Based on https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115 +*/ + +/// \file apply_permutation.hpp +/// \brief Apply permutation to a sequence. +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_APPLY_PERMUTATION_HPP +#define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP + +#include +#include + +#include +#include + +namespace boost { namespace algorithm +{ + +/// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_begin The start of the item sequence +/// \param item_end One past the end of the item sequence +/// \param ind_begin The start of the index sequence. +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin) +{ + using Diff = typename std::iterator_traits::difference_type; + Diff size = std::distance(item_begin, item_end); + for (Diff i = 0; i < size; i++) + { + auto current = i; + while (i != ind_begin[current]) + { + auto next = ind_begin[current]; + std::swap(item_begin[current], item_begin[next]); + ind_begin[current] = current; + current = next; + } + ind_begin[current] = current; + } +} + +/// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_begin The start of the item sequence +/// \param item_end One past the end of the item sequence +/// \param ind_begin The start of the index sequence. +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_reverse_permutation( + RandomAccessIterator1 item_begin, + RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin) +{ + using Diff = typename std::iterator_traits::difference_type; + Diff length = std::distance(item_begin, item_end); + for (Diff i = 0; i < length; i++) + { + while (i != ind_begin[i]) + { + Diff next = ind_begin[i]; + std::swap(item_begin[i], item_begin[next]); + std::swap(ind_begin[i], ind_begin[next]); + } + } +} + +/// \fn apply_permutation ( Range1 item_range, Range2 ind_range ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_range The item sequence +/// \param ind_range The index sequence +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_permutation(Range1& item_range, Range2& ind_range) +{ + apply_permutation(boost::begin(item_range), boost::end(item_range), + boost::begin(ind_range)); +} + +/// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range ) +/// \brief Reorder item sequence with index sequence order +/// +/// \param item_range The item sequence +/// \param ind_range The index sequence +/// +/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void +apply_reverse_permutation(Range1& item_range, Range2& ind_range) +{ + apply_reverse_permutation(boost::begin(item_range), boost::end(item_range), + boost::begin(ind_range)); +} + +}} +#endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP From 1970454ecbe0a5964a3b21552fcae6ecc27436a6 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Thu, 18 May 2017 23:33:26 -0600 Subject: [PATCH 02/13] Added test --- test/apply_permutation_test.cpp | 122 ++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 test/apply_permutation_test.cpp diff --git a/test/apply_permutation_test.cpp b/test/apply_permutation_test.cpp new file mode 100644 index 000000000..471652037 --- /dev/null +++ b/test/apply_permutation_test.cpp @@ -0,0 +1,122 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. +*/ + +#include +#include +#include +#include +#include + +#include + +#define BOOST_TEST_MAIN + +#include + +namespace ba = boost::algorithm; + + +void test_apply_permutation() +{ + //Empty + { + std::vector vec, order, result; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //1 element + { + std::vector vec{1}, order{0}, result{1}; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //2 elements, no changes + { + std::vector vec{1, 2}, order{0, 1}, result{1, 2}; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //2 elements, changed + { + std::vector vec{1, 2}, order{1, 0}, result{2, 1}; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Multiple elements, no changes + { + std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Multiple elements, changed + { + std::vector vec{1, 2, 3, 4, 5}, order{4, 3, 2, 1, 0}, result{5, 4, 3, 2, 1}; + ba::apply_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Just test range interface + { + std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; + ba::apply_permutation(vec, order); + BOOST_CHECK(vec == result); + } +} + +void test_apply_reverse_permutation() +{ + //Empty + { + std::vector vec, order, result; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //1 element + { + std::vector vec{1}, order{0}, result{1}; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //2 elements, no changes + { + std::vector vec{1, 2}, order{0, 1}, result{1, 2}; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //2 elements, changed + { + std::vector vec{1, 2}, order{1, 0}, result{2, 1}; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Multiple elements, no changes + { + std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Multiple elements, changed + { + std::vector vec{1, 2, 3, 4, 5}, order{4, 3, 2, 1, 0}, result{5, 4, 3, 2, 1}; + ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); + BOOST_CHECK(vec == result); + } + //Just test range interface + { + std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; + ba::apply_reverse_permutation(vec, order); + BOOST_CHECK(vec == result); + } +} + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_apply_permutation(); + test_apply_reverse_permutation(); +} From ba7655eb3a7ac2cab16f6d573355fce4a497a933 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Fri, 19 May 2017 16:59:11 -0600 Subject: [PATCH 03/13] Add documentation --- doc/apply_permutation.qbk | 85 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 doc/apply_permutation.qbk diff --git a/doc/apply_permutation.qbk b/doc/apply_permutation.qbk new file mode 100644 index 000000000..952195dfc --- /dev/null +++ b/doc/apply_permutation.qbk @@ -0,0 +1,85 @@ +[/ File apply_permutation.qbk] + +[section:apply_permutation apply_permutation] + +[/license +Copyright (c) 2017 Alexander Zaitsev + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +The header file 'apply_permutation.hpp' contains two algorithms, apply_permutation and apply_reverse_permutation. Also there are range-based versions. +The algorithms transform the item sequence according to index sequence order. + +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. +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. + +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. + + +[heading interface] + +There are two versions of algorithms: +1) takes three iterators. +2) takes two ranges. +`` +template +void apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin); +template +void apply_permutation(Range1& item_range, Range2& ind_range); +template +void apply_reverse_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, + RandomAccessIterator2 ind_begin); +template +void apply_reverse_permutation(Range1& item_range, Range2& ind_range); +`` + + +[heading Examples] + +Given the containers: +std::vector emp_vec, emp_order, +std::vector one{1}, one_order{0}, +std::vector two{1,2}, two_order{1,0}, +std::vector vec{1, 2, 3, 4, 5}, +std::vector order{4, 2, 3, 1, 0}, then +`` + +apply_permutation(emp_vec, emp_order)) --> no changes +apply_reverse_permutation(emp_vec, emp_order)) --> no changes +apply_permutation(one, one_order) --> no changes +apply_reverse_permutation(one, one_order) --> no changes +apply_permutation(two, two_order) --> two:{2,1} +apply_reverse_permutation(two, two_order) --> two:{2,1} +apply_permutation(vec, order) --> vec:{5, 3, 4, 2, 1} +apply_reverse_permutation(vec, order) --> vec:{5, 4, 2, 3, 1} +`` + +[heading Iterator Requirements] + +`apply_permutation` and 'apply_reverse_permutation' work only on RandomAccess iterators. RandomAccess iterators required both for item and index sequences. + +[heading Complexity] + +All of the variants of `apply_permutation` and `apply_reverse_permutation` run in ['O(N)] (linear) time. + +[heading Exception Safety] + +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. + +[heading Notes] +* If ItemSequence and IndexSequence are not equal, behavior is undefined. + +* `apply_permutation` and `apply_reverse_permutation` work also on empty sequences. + +* Order sequence must be zero-indexed. + +[endsect] + +[/ File apply_permutation.qbk +Copyright 2017 Alexander Zaitsev +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). +] From e07e8e65c680026aa9859a0fdc13751b0d18a6ed Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Fri, 19 May 2017 18:50:03 -0600 Subject: [PATCH 04/13] Fixed references --- doc/algorithm.qbk | 1 + example/Jamfile.v2 | 2 +- test/Jamfile.v2 | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index becad4629..8ce668506 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -68,6 +68,7 @@ Thanks to all the people who have reviewed this library and made suggestions for [include hex.qbk] [include is_palindrome.qbk] [include is_partitioned_until.qbk] +[include apply_permutation.qbk] [endsect] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 4512a53bb..100878c30 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -22,4 +22,4 @@ exe clamp_example : clamp_example.cpp ; exe search_example : search_example.cpp ; exe is_palindrome_example : is_palindrome_example.cpp; exe is_partitioned_until_example : is_partitioned_until_example.cpp; - +exe apply_permutation_example : apply_permutation_example.cpp; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fad1578fa..0b5ae3578 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -73,6 +73,9 @@ alias unit_test_framework # Is_partitioned_until tests [ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ] + +# Apply_permutation tests + [ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ] ; } From 0dc003902b6699d0c04da2b0baa5911d456f88a4 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Thu, 13 Jul 2017 11:54:53 +0300 Subject: [PATCH 05/13] Added initial impl for shuffle_weighted --- doc/algorithm.qbk | 1 + doc/shuffle_weighted.qbk | 71 ++++++++++++++++ example/Jamfile.v2 | 1 + example/shuffle_weighted_example.cpp | 49 +++++++++++ include/boost/algorithm/shuffle_weighted.hpp | 87 ++++++++++++++++++++ test/Jamfile.v2 | 5 +- test/shuffle_weighted_test.cpp | 36 ++++++++ 7 files changed, 249 insertions(+), 1 deletion(-) create mode 100644 doc/shuffle_weighted.qbk create mode 100644 example/shuffle_weighted_example.cpp create mode 100644 include/boost/algorithm/shuffle_weighted.hpp create mode 100644 test/shuffle_weighted_test.cpp diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index 8ce668506..db040452c 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -69,6 +69,7 @@ Thanks to all the people who have reviewed this library and made suggestions for [include is_palindrome.qbk] [include is_partitioned_until.qbk] [include apply_permutation.qbk] +[include shuffle_weighted.qbk] [endsect] diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk new file mode 100644 index 000000000..2a598160f --- /dev/null +++ b/doc/shuffle_weighted.qbk @@ -0,0 +1,71 @@ +[/ File shuffle_weighted.qbk] + +[section:shuffle_weighted shuffle_weighted] + +[/license +Copyright (c) 2017 Alexander Zaitsev + +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +] + +The header file 'shuffle_weighted.hpp' contains shuffle_weighted algorithm. There is range-based version. +The algorithms rearrange the elements randomly with weights, using random number generator. Algorithm is implemented according to Weighted Random Sampling (2005; Efraimidis, Spirakis) paper. + +The routine `shuffle_weighted` takes a item sequence and a weight sequences. + +The routines come in 2 forms; the first one takes two iterators to define the item range, one iterator to define the beginning of weight range and random generator. The second form takes range to define the item sequence, range to define weight sequence and random generator. + + +[heading interface] + +There are two versions of algorithms: +1) takes three iterators and random generator. +2) takes two ranges and random generator. +`` +template +void shuffle_weighted(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 weight_begin, UniformRandomBitGenerator&& g); +template +void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g); +`` + + +[heading Examples] + +Given the containers: +std::vector emp_vec, emp_order, +std::vector one{1}, one_order{0}, +std::vector two{1,2}, two_order{1,0}, +std::vector vec{1, 2, 3, 4, 5}, +std::vector order{4, 2, 3, 1, 0}, then +`` + +shuffle_weighted(emp_vec, emp_order)) --> no changes +`` + +[heading Iterator Requirements] + +`shuffle_weighted` works only on RandomAccess iterators. RandomAccess iterators required both for item and weight sequences. + +[heading Complexity] + +All of the variants of `shuffle_weighted` runs in ['O(NlogN)] time. + +[heading Exception Safety] + +All of the variants of `shuffle_weighted` takes 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. + +[heading Notes] +* Algorithms based on Weighted Random Sampling (2005; Efraimidis, Spirakis) http://utopia.duth.gr/~pefraimi/research/data/2007EncOfAlg.pdf + +* If ItemSequence and WeightSequence sizes are not equal, behavior is undefined. + +* `shuffle_weighted` works also on empty sequences. + +[endsect] + +[/ File shuffle_weighted.qbk +Copyright 2017 Alexander Zaitsev +Distributed under the Boost Software License, Version 1.0. +(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). +] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 100878c30..6be034a19 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -23,3 +23,4 @@ exe search_example : search_example.cpp ; exe is_palindrome_example : is_palindrome_example.cpp; exe is_partitioned_until_example : is_partitioned_until_example.cpp; exe apply_permutation_example : apply_permutation_example.cpp; +exe shuffle_weighted_example : shuffle_weighted_example.cpp; diff --git a/example/shuffle_weighted_example.cpp b/example/shuffle_weighted_example.cpp new file mode 100644 index 000000000..1de11a82e --- /dev/null +++ b/example/shuffle_weighted_example.cpp @@ -0,0 +1,49 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. +*/ + +#include +#include +#include + +#include "shuffle_weighted.hpp" + + +namespace ba = boost::algorithm; + +int main ( int /*argc*/, char * /*argv*/ [] ) +{ + std::random_device rd; + std::mt19937 g(rd()); + { + std::cout << "shuffle_weighted with iterators:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::shuffle_weighted(vec.begin(), vec.end(), order.begin(), g); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + { + std::cout << "shuffle_weighted with ranges:\n"; + std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; + + ba::shuffle_weighted(vec, order, g); + for (const auto& x : vec) + { + std::cout << x << ", "; + } + std::cout << std::endl; + } + + return 0; +} + diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp new file mode 100644 index 000000000..b06474803 --- /dev/null +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -0,0 +1,87 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. + + + Based on: Weighted Random Sampling (2005; Efraimidis, Spirakis) + http://utopia.duth.gr/~pefraimi/research/data/2007EncOfAlg.pdf + +*/ + +/// \file shuffle_weighted.hpp +/// \brief Weighted shuffle. +/// \author Alexander Zaitsev + +#ifndef BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP +#define BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP + +#include +#include +#include +#include + +#include "/home/zamazan4ik/OpenSource/apply_permutation/apply_permutation.hpp" + +#include +#include + +namespace boost { namespace algorithm { + +/// \fn shuffle_weighted (RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 weight_begin, UniformRandomBitGenerator&& g) +/// \brief Rearranges the elements in the range [item_begin,item_end) randomly with weights from weight_begin range, using g as uniform random number generator. +/// +/// \param item_begin The start of the item sequence +/// \param item_end One past the end of the item sequence +/// \param weight_begin The start of the weight sequence. +/// \param g Uniform random number generator +/// +/// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void shuffle_weighted(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 weight_begin, UniformRandomBitGenerator&& g) +{ + using Diff = typename std::iterator_traits::difference_type; + std::vector> order + (std::distance(item_begin, item_end)); + std::uniform_real_distribution random(0, 1.0); + size_t index = 0; + for (auto& x : order) + { + x = std::pair(-std::pow(random(g), 1.0 / weight_begin[index]), index); + ++index; + } + //TODO: Is there reason use Boost.Sort here? + std::sort(order.begin(), order.end()); + std::vector res_order; + res_order.reserve(order.size()); + for (const auto& x : order) + { + res_order.push_back(x.second); + } + + boost::algorithm::apply_permutation(item_begin, item_end, res_order.begin()); +} + +/// \fn shuffle_weighted (Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g ) +/// \brief Rearranges the elements in the range [item_begin,item_end) randomly with weights from weight_begin range, using g as uniform random number generator. +/// +/// \param item_range The item sequence +/// \param weight_range The weight sequence +/// \param g Uniform random number generator +/// +/// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. +/// Complexity: O(N). +template +void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g) +{ + shuffle_weighted(boost::begin(item_range), boost::end(item_range), + boost::begin(weight_range), g); +} + +}} +#endif //BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0b5ae3578..ead7c3bad 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -75,7 +75,10 @@ alias unit_test_framework [ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ] # Apply_permutation tests - [ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ] + [ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ] + +# Shuffle_weighted tests + [ run shuffle_weighted.cpp unit_test_framework : : : : shuffle_weighted_test ] ; } diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp new file mode 100644 index 000000000..b9f8c175f --- /dev/null +++ b/test/shuffle_weighted_test.cpp @@ -0,0 +1,36 @@ +/* + Copyright (c) Alexander Zaitsev , 2017 + + Distributed under the Boost Software License, Version 1.0. (See + accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + See http://www.boost.org/ for latest version. +*/ + +#include +#include +#include +#include +#include + +#include "shuffle_weighted.hpp" + +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN + +#include + +namespace ba = boost::algorithm; + + +void test_shuffle_weighted() +{ + BOOST_CHECK(true); +} + + +BOOST_AUTO_TEST_CASE(test_main) +{ + test_shuffle_weighted(); +} From 39b787bc9eb93c5e30ba282a5631ff28c3ecde46 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Sun, 16 Jul 2017 20:18:42 +0300 Subject: [PATCH 06/13] New weighted shuffle algorithm --- doc/shuffle_weighted.qbk | 22 +++--- include/boost/algorithm/shuffle_weighted.hpp | 71 +++++++++++++------- test/shuffle_weighted_test.cpp | 34 +++++++++- 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk index 2a598160f..02423cdd5 100644 --- a/doc/shuffle_weighted.qbk +++ b/doc/shuffle_weighted.qbk @@ -10,7 +10,7 @@ Distributed under the Boost Software License, Version 1.0. ] The header file 'shuffle_weighted.hpp' contains shuffle_weighted algorithm. There is range-based version. -The algorithms rearrange the elements randomly with weights, using random number generator. Algorithm is implemented according to Weighted Random Sampling (2005; Efraimidis, Spirakis) paper. +The algorithms rearrange the elements randomly with weights, using random number generator. The routine `shuffle_weighted` takes a item sequence and a weight sequences. @@ -23,8 +23,8 @@ There are two versions of algorithms: 1) takes three iterators and random generator. 2) takes two ranges and random generator. `` -template -void shuffle_weighted(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 weight_begin, UniformRandomBitGenerator&& g); +template +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g); template void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g); `` @@ -34,31 +34,31 @@ void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBit Given the containers: std::vector emp_vec, emp_order, -std::vector one{1}, one_order{0}, -std::vector two{1,2}, two_order{1,0}, -std::vector vec{1, 2, 3, 4, 5}, -std::vector order{4, 2, 3, 1, 0}, then +std::vector one{1}, one_order{1}, +std::vector two{1, 2}, two_order{1, 2}, then `` shuffle_weighted(emp_vec, emp_order)) --> no changes +shuffle_weighted(one, one_order)) --> no changes +shuffle_weighted(two, two_order)) --> weighted-random result `` [heading Iterator Requirements] -`shuffle_weighted` works only on RandomAccess iterators. RandomAccess iterators required both for item and weight sequences. +`shuffle_weighted` works on Forawrd-compatible iterators (for item and weight sequences both). [heading Complexity] -All of the variants of `shuffle_weighted` runs in ['O(NlogN)] time. +All of the variants of `shuffle_weighted` runs in ['O(N^2)] time. [heading Exception Safety] All of the variants of `shuffle_weighted` takes 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. [heading Notes] -* Algorithms based on Weighted Random Sampling (2005; Efraimidis, Spirakis) http://utopia.duth.gr/~pefraimi/research/data/2007EncOfAlg.pdf +* Weights should be bigger than 0. -* If ItemSequence and WeightSequence sizes are not equal, behavior is undefined. +* If ItemSequence and WeightSequence sizes are different, behavior is undefined. * `shuffle_weighted` works also on empty sequences. diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index b06474803..70f4eb3fe 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -41,32 +41,56 @@ namespace boost { namespace algorithm { /// \param g Uniform random number generator /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void shuffle_weighted(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 weight_begin, UniformRandomBitGenerator&& g) +/// Complexity: O(N^2). +template +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, + ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g) { - using Diff = typename std::iterator_traits::difference_type; - std::vector> order - (std::distance(item_begin, item_end)); - std::uniform_real_distribution random(0, 1.0); - size_t index = 0; - for (auto& x : order) + using weight_t = typename std::iterator_traits::value_type; + + weight_t total_weight = 0; + auto weight_iter = weight_begin; + for(auto it = item_begin; it != item_end; + it = std::next(it), + weight_iter = std::next(weight_iter)) { - x = std::pair(-std::pow(random(g), 1.0 / weight_begin[index]), index); - ++index; + total_weight += *weight_iter; } - //TODO: Is there reason use Boost.Sort here? - std::sort(order.begin(), order.end()); - std::vector res_order; - res_order.reserve(order.size()); - for (const auto& x : order) + + using uniform_distr_t = std::conditional_t< + std::is_integral::value, + std::uniform_int_distribution, + std::uniform_real_distribution + >; + typedef typename uniform_distr_t::param_type param_type; + + uniform_distr_t distribution; + for (; item_begin != item_end; + item_begin = std::next(item_begin), + weight_begin = std::next(weight_begin)) { - res_order.push_back(x.second); - } + weight_t current_weights_sum = 0; + const weight_t random_value = distribution(g, param_type(0, total_weight)); - boost::algorithm::apply_permutation(item_begin, item_end, res_order.begin()); + auto weight_iter = weight_begin; + for (auto it = item_begin; it != item_end; + it = std::next(it), + weight_iter = std::next(weight_iter)) + { + const weight_t weight = *weight_iter; + current_weights_sum += weight; + if (current_weights_sum >= random_value) + { + std::iter_swap(item_begin, it); + std::iter_swap(weight_begin, weight_iter); + total_weight -= weight; + break; + } + } + } } + /// \fn shuffle_weighted (Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g ) /// \brief Rearranges the elements in the range [item_begin,item_end) randomly with weights from weight_begin range, using g as uniform random number generator. /// @@ -75,12 +99,11 @@ void shuffle_weighted(RandomAccessIterator1 item_begin, RandomAccessIterator1 it /// \param g Uniform random number generator /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g) +/// Complexity: O(N^2). +template +void shuffle_weighted(Range1 item_range, Range2 weight_range, UniformRandomBitGenerator&& g) { - shuffle_weighted(boost::begin(item_range), boost::end(item_range), - boost::begin(weight_range), g); + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), std::forward(g)); } }} diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp index b9f8c175f..c7aa90fe2 100644 --- a/test/shuffle_weighted_test.cpp +++ b/test/shuffle_weighted_test.cpp @@ -8,16 +8,19 @@ See http://www.boost.org/ for latest version. */ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MAIN + #include #include #include #include #include +#include #include "shuffle_weighted.hpp" -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MAIN + #include @@ -26,7 +29,32 @@ namespace ba = boost::algorithm; void test_shuffle_weighted() { - BOOST_CHECK(true); + { + // Empty case + + std::mt19937_64 d; + std::vector vec, weights; + ba::shuffle_weighted(vec, weights, d); + BOOST_CHECK(vec.empty () && weights.empty()); + } + { + // One element case + + std::mt19937_64 d; + std::vector vec({1}), weights({1}); + std::vector new_vec = vec, new_weights = weights; + ba::shuffle_weighted(new_vec, new_weights, d); + BOOST_CHECK(vec == new_vec && weights == new_weights); + } + { + // Two element case + + std::mt19937_64 d; + std::vector vec({1, 2}), rev_vec({2, 1}), weights({1, 2}); + std::vector new_vec = vec, new_weights = weights; + ba::shuffle_weighted(new_vec, new_weights, d); + BOOST_CHECK((vec == new_vec || rev_vec == new_vec) && weights == new_weights); + } } From 7648c926f47859b7b68bd6ee0e34776acba35ed6 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Sun, 16 Jul 2017 20:21:44 +0300 Subject: [PATCH 07/13] Small fixes --- doc/shuffle_weighted.qbk | 2 ++ example/shuffle_weighted_example.cpp | 2 +- include/boost/algorithm/shuffle_weighted.hpp | 2 -- test/shuffle_weighted_test.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk index 02423cdd5..aadd093da 100644 --- a/doc/shuffle_weighted.qbk +++ b/doc/shuffle_weighted.qbk @@ -62,6 +62,8 @@ All of the variants of `shuffle_weighted` takes their parameters by iterators or * `shuffle_weighted` works also on empty sequences. +* Require C++11 or higher compiler. + [endsect] [/ File shuffle_weighted.qbk diff --git a/example/shuffle_weighted_example.cpp b/example/shuffle_weighted_example.cpp index 1de11a82e..43b4f5a19 100644 --- a/example/shuffle_weighted_example.cpp +++ b/example/shuffle_weighted_example.cpp @@ -12,7 +12,7 @@ #include #include -#include "shuffle_weighted.hpp" +#include namespace ba = boost::algorithm; diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index 70f4eb3fe..b73e8f9ba 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -25,8 +25,6 @@ #include #include -#include "/home/zamazan4ik/OpenSource/apply_permutation/apply_permutation.hpp" - #include #include diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp index c7aa90fe2..d2c7987a4 100644 --- a/test/shuffle_weighted_test.cpp +++ b/test/shuffle_weighted_test.cpp @@ -18,7 +18,7 @@ #include #include -#include "shuffle_weighted.hpp" +#include From 06a537541fc2c26551591ef2e78dba18289d247d Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Sun, 16 Jul 2017 20:47:39 +0300 Subject: [PATCH 08/13] Remove apply_permutation --- doc/algorithm.qbk | 1 - doc/apply_permutation.qbk | 85 ------------ example/Jamfile.v2 | 1 - example/apply_permutation_example.cpp | 68 ---------- include/boost/algorithm/apply_permutation.hpp | 122 ------------------ test/Jamfile.v2 | 3 - test/apply_permutation_test.cpp | 122 ------------------ 7 files changed, 402 deletions(-) delete mode 100644 doc/apply_permutation.qbk delete mode 100644 example/apply_permutation_example.cpp delete mode 100644 include/boost/algorithm/apply_permutation.hpp delete mode 100644 test/apply_permutation_test.cpp diff --git a/doc/algorithm.qbk b/doc/algorithm.qbk index db040452c..6217cb4f8 100644 --- a/doc/algorithm.qbk +++ b/doc/algorithm.qbk @@ -68,7 +68,6 @@ Thanks to all the people who have reviewed this library and made suggestions for [include hex.qbk] [include is_palindrome.qbk] [include is_partitioned_until.qbk] -[include apply_permutation.qbk] [include shuffle_weighted.qbk] [endsect] diff --git a/doc/apply_permutation.qbk b/doc/apply_permutation.qbk deleted file mode 100644 index 952195dfc..000000000 --- a/doc/apply_permutation.qbk +++ /dev/null @@ -1,85 +0,0 @@ -[/ File apply_permutation.qbk] - -[section:apply_permutation apply_permutation] - -[/license -Copyright (c) 2017 Alexander Zaitsev - -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -] - -The header file 'apply_permutation.hpp' contains two algorithms, apply_permutation and apply_reverse_permutation. Also there are range-based versions. -The algorithms transform the item sequence according to index sequence order. - -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. -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. - -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. - - -[heading interface] - -There are two versions of algorithms: -1) takes three iterators. -2) takes two ranges. -`` -template -void apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, - RandomAccessIterator2 ind_begin); -template -void apply_permutation(Range1& item_range, Range2& ind_range); -template -void apply_reverse_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, - RandomAccessIterator2 ind_begin); -template -void apply_reverse_permutation(Range1& item_range, Range2& ind_range); -`` - - -[heading Examples] - -Given the containers: -std::vector emp_vec, emp_order, -std::vector one{1}, one_order{0}, -std::vector two{1,2}, two_order{1,0}, -std::vector vec{1, 2, 3, 4, 5}, -std::vector order{4, 2, 3, 1, 0}, then -`` - -apply_permutation(emp_vec, emp_order)) --> no changes -apply_reverse_permutation(emp_vec, emp_order)) --> no changes -apply_permutation(one, one_order) --> no changes -apply_reverse_permutation(one, one_order) --> no changes -apply_permutation(two, two_order) --> two:{2,1} -apply_reverse_permutation(two, two_order) --> two:{2,1} -apply_permutation(vec, order) --> vec:{5, 3, 4, 2, 1} -apply_reverse_permutation(vec, order) --> vec:{5, 4, 2, 3, 1} -`` - -[heading Iterator Requirements] - -`apply_permutation` and 'apply_reverse_permutation' work only on RandomAccess iterators. RandomAccess iterators required both for item and index sequences. - -[heading Complexity] - -All of the variants of `apply_permutation` and `apply_reverse_permutation` run in ['O(N)] (linear) time. - -[heading Exception Safety] - -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. - -[heading Notes] -* If ItemSequence and IndexSequence are not equal, behavior is undefined. - -* `apply_permutation` and `apply_reverse_permutation` work also on empty sequences. - -* Order sequence must be zero-indexed. - -[endsect] - -[/ File apply_permutation.qbk -Copyright 2017 Alexander Zaitsev -Distributed under the Boost Software License, Version 1.0. -(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt). -] diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 6be034a19..16f4e4179 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -22,5 +22,4 @@ exe clamp_example : clamp_example.cpp ; exe search_example : search_example.cpp ; exe is_palindrome_example : is_palindrome_example.cpp; exe is_partitioned_until_example : is_partitioned_until_example.cpp; -exe apply_permutation_example : apply_permutation_example.cpp; exe shuffle_weighted_example : shuffle_weighted_example.cpp; diff --git a/example/apply_permutation_example.cpp b/example/apply_permutation_example.cpp deleted file mode 100644 index feaa9f280..000000000 --- a/example/apply_permutation_example.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/* - Copyright (c) Alexander Zaitsev , 2017 - - Distributed under the Boost Software License, Version 1.0. (See - accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - - See http://www.boost.org/ for latest version. -*/ - -#include -#include - -#include - - -namespace ba = boost::algorithm; - -int main ( int /*argc*/, char * /*argv*/ [] ) -{ - { - std::cout << "apply_permutation with iterators:\n"; - std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; - - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - for (const auto& x : vec) - { - std::cout << x << ", "; - } - std::cout << std::endl; - } - { - std::cout << "apply_reverse_permutation with iterators:\n"; - std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; - - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - for (const auto& x : vec) - { - std::cout << x << ", "; - } - std::cout << std::endl; - } - { - std::cout << "apply_reverse_permutation with ranges:\n"; - std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; - - ba::apply_reverse_permutation(vec, order); - for (const auto& x : vec) - { - std::cout << x << ", "; - } - std::cout << std::endl; - } - { - std::cout << "apply_permutation with ranges:\n"; - std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; - - ba::apply_permutation(vec, order); - for (const auto& x : vec) - { - std::cout << x << ", "; - } - std::cout << std::endl; - } - - return 0; -} - diff --git a/include/boost/algorithm/apply_permutation.hpp b/include/boost/algorithm/apply_permutation.hpp deleted file mode 100644 index f14ba65c5..000000000 --- a/include/boost/algorithm/apply_permutation.hpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright (c) Alexander Zaitsev , 2017 - - Distributed under the Boost Software License, Version 1.0. (See - accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - - See http://www.boost.org/ for latest version. - - - Based on https://blogs.msdn.microsoft.com/oldnewthing/20170104-00/?p=95115 -*/ - -/// \file apply_permutation.hpp -/// \brief Apply permutation to a sequence. -/// \author Alexander Zaitsev - -#ifndef BOOST_ALGORITHM_APPLY_PERMUTATION_HPP -#define BOOST_ALGORITHM_APPLY_PERMUTATION_HPP - -#include -#include - -#include -#include - -namespace boost { namespace algorithm -{ - -/// \fn apply_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) -/// \brief Reorder item sequence with index sequence order -/// -/// \param item_begin The start of the item sequence -/// \param item_end One past the end of the item sequence -/// \param ind_begin The start of the index sequence. -/// -/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void -apply_permutation(RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, - RandomAccessIterator2 ind_begin) -{ - using Diff = typename std::iterator_traits::difference_type; - Diff size = std::distance(item_begin, item_end); - for (Diff i = 0; i < size; i++) - { - auto current = i; - while (i != ind_begin[current]) - { - auto next = ind_begin[current]; - std::swap(item_begin[current], item_begin[next]); - ind_begin[current] = current; - current = next; - } - ind_begin[current] = current; - } -} - -/// \fn apply_reverse_permutation ( RandomAccessIterator1 item_begin, RandomAccessIterator1 item_end, RandomAccessIterator2 ind_begin ) -/// \brief Reorder item sequence with index sequence order -/// -/// \param item_begin The start of the item sequence -/// \param item_end One past the end of the item sequence -/// \param ind_begin The start of the index sequence. -/// -/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void -apply_reverse_permutation( - RandomAccessIterator1 item_begin, - RandomAccessIterator1 item_end, - RandomAccessIterator2 ind_begin) -{ - using Diff = typename std::iterator_traits::difference_type; - Diff length = std::distance(item_begin, item_end); - for (Diff i = 0; i < length; i++) - { - while (i != ind_begin[i]) - { - Diff next = ind_begin[i]; - std::swap(item_begin[i], item_begin[next]); - std::swap(ind_begin[i], ind_begin[next]); - } - } -} - -/// \fn apply_permutation ( Range1 item_range, Range2 ind_range ) -/// \brief Reorder item sequence with index sequence order -/// -/// \param item_range The item sequence -/// \param ind_range The index sequence -/// -/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void -apply_permutation(Range1& item_range, Range2& ind_range) -{ - apply_permutation(boost::begin(item_range), boost::end(item_range), - boost::begin(ind_range)); -} - -/// \fn apply_reverse_permutation ( Range1 item_range, Range2 ind_range ) -/// \brief Reorder item sequence with index sequence order -/// -/// \param item_range The item sequence -/// \param ind_range The index sequence -/// -/// \note Item sequence size should be equal to index size. Otherwise behavior is undefined. -/// Complexity: O(N). -template -void -apply_reverse_permutation(Range1& item_range, Range2& ind_range) -{ - apply_reverse_permutation(boost::begin(item_range), boost::end(item_range), - boost::begin(ind_range)); -} - -}} -#endif //BOOST_ALGORITHM_APPLY_PERMUTATION_HPP diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ead7c3bad..f40c85d15 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -73,9 +73,6 @@ alias unit_test_framework # Is_partitioned_until tests [ run is_partitioned_until_test.cpp unit_test_framework : : : : is_partitioned_until_test ] - -# Apply_permutation tests - [ run apply_permutation_test.cpp unit_test_framework : : : : apply_permutation_test ] # Shuffle_weighted tests [ run shuffle_weighted.cpp unit_test_framework : : : : shuffle_weighted_test ] diff --git a/test/apply_permutation_test.cpp b/test/apply_permutation_test.cpp deleted file mode 100644 index 471652037..000000000 --- a/test/apply_permutation_test.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright (c) Alexander Zaitsev , 2017 - - Distributed under the Boost Software License, Version 1.0. (See - accompanying file LICENSE_1_0.txt or copy at - http://www.boost.org/LICENSE_1_0.txt) - - See http://www.boost.org/ for latest version. -*/ - -#include -#include -#include -#include -#include - -#include - -#define BOOST_TEST_MAIN - -#include - -namespace ba = boost::algorithm; - - -void test_apply_permutation() -{ - //Empty - { - std::vector vec, order, result; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //1 element - { - std::vector vec{1}, order{0}, result{1}; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //2 elements, no changes - { - std::vector vec{1, 2}, order{0, 1}, result{1, 2}; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //2 elements, changed - { - std::vector vec{1, 2}, order{1, 0}, result{2, 1}; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Multiple elements, no changes - { - std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Multiple elements, changed - { - std::vector vec{1, 2, 3, 4, 5}, order{4, 3, 2, 1, 0}, result{5, 4, 3, 2, 1}; - ba::apply_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Just test range interface - { - std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; - ba::apply_permutation(vec, order); - BOOST_CHECK(vec == result); - } -} - -void test_apply_reverse_permutation() -{ - //Empty - { - std::vector vec, order, result; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //1 element - { - std::vector vec{1}, order{0}, result{1}; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //2 elements, no changes - { - std::vector vec{1, 2}, order{0, 1}, result{1, 2}; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //2 elements, changed - { - std::vector vec{1, 2}, order{1, 0}, result{2, 1}; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Multiple elements, no changes - { - std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Multiple elements, changed - { - std::vector vec{1, 2, 3, 4, 5}, order{4, 3, 2, 1, 0}, result{5, 4, 3, 2, 1}; - ba::apply_reverse_permutation(vec.begin(), vec.end(), order.begin()); - BOOST_CHECK(vec == result); - } - //Just test range interface - { - std::vector vec{1, 2, 3, 4, 5}, order{0, 1, 2, 3, 4}, result{1, 2, 3, 4, 5}; - ba::apply_reverse_permutation(vec, order); - BOOST_CHECK(vec == result); - } -} - -BOOST_AUTO_TEST_CASE(test_main) -{ - test_apply_permutation(); - test_apply_reverse_permutation(); -} From f0261024f03ae4afe81b3646ed9042b81a365225 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Sun, 16 Jul 2017 20:49:47 +0300 Subject: [PATCH 09/13] Remove wrong link --- include/boost/algorithm/shuffle_weighted.hpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index b73e8f9ba..c8d1391bf 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -6,10 +6,6 @@ http://www.boost.org/LICENSE_1_0.txt) See http://www.boost.org/ for latest version. - - - Based on: Weighted Random Sampling (2005; Efraimidis, Spirakis) - http://utopia.duth.gr/~pefraimi/research/data/2007EncOfAlg.pdf */ From 339fc175f819bc20da2493a1d12b72c00807c102 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Mon, 17 Jul 2017 22:42:23 +0300 Subject: [PATCH 10/13] Fix compatibility issue with compilers < C++11 --- doc/shuffle_weighted.qbk | 2 - include/boost/algorithm/shuffle_weighted.hpp | 47 +++++++++++--------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk index aadd093da..02423cdd5 100644 --- a/doc/shuffle_weighted.qbk +++ b/doc/shuffle_weighted.qbk @@ -62,8 +62,6 @@ All of the variants of `shuffle_weighted` takes their parameters by iterators or * `shuffle_weighted` works also on empty sequences. -* Require C++11 or higher compiler. - [endsect] [/ File shuffle_weighted.qbk diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index c8d1391bf..7f3b3b81a 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -17,10 +17,15 @@ #define BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP #include -#include #include -#include +#include + +#include +#include +#include +#include +#include #include #include @@ -36,40 +41,40 @@ namespace boost { namespace algorithm { /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). -template +template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g) { - using weight_t = typename std::iterator_traits::value_type; + typedef typename std::iterator_traits::value_type weight_t; weight_t total_weight = 0; - auto weight_iter = weight_begin; - for(auto it = item_begin; it != item_end; - it = std::next(it), - weight_iter = std::next(weight_iter)) + ForwardIterator2 weight_iter = weight_begin; + for(ForwardIterator1 it = item_begin; it != item_end; + it = boost::next(it), + weight_iter = boost::next(weight_iter)) { total_weight += *weight_iter; } - using uniform_distr_t = std::conditional_t< - std::is_integral::value, - std::uniform_int_distribution, - std::uniform_real_distribution - >; + typedef typename boost::conditional< + boost::is_integral::value, + boost::random::uniform_int_distribution, + boost::random::uniform_real_distribution + >::type uniform_distr_t; typedef typename uniform_distr_t::param_type param_type; uniform_distr_t distribution; for (; item_begin != item_end; - item_begin = std::next(item_begin), - weight_begin = std::next(weight_begin)) + item_begin = boost::next(item_begin), + weight_begin = boost::next(weight_begin)) { weight_t current_weights_sum = 0; const weight_t random_value = distribution(g, param_type(0, total_weight)); - auto weight_iter = weight_begin; - for (auto it = item_begin; it != item_end; - it = std::next(it), - weight_iter = std::next(weight_iter)) + ForwardIterator2 weight_iter = weight_begin; + for (ForwardIterator1 it = item_begin; it != item_end; + it = boost::next(it), + weight_iter = boost::next(weight_iter)) { const weight_t weight = *weight_iter; current_weights_sum += weight; @@ -94,10 +99,10 @@ void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). -template +template void shuffle_weighted(Range1 item_range, Range2 weight_range, UniformRandomBitGenerator&& g) { - shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), std::forward(g)); + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), boost::forward(g)); } }} From b18634ea478c6a6018c8a0f471298ee9d0507be2 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Wed, 19 Jul 2017 02:12:04 +0300 Subject: [PATCH 11/13] Fixed compatibility with old compilers --- doc/shuffle_weighted.qbk | 13 +++++++++ example/shuffle_weighted_example.cpp | 1 + include/boost/algorithm/shuffle_weighted.hpp | 17 +++++++++-- test/shuffle_weighted_test.cpp | 30 +++++++++++--------- 4 files changed, 44 insertions(+), 17 deletions(-) diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk index 02423cdd5..efa5957c6 100644 --- a/doc/shuffle_weighted.qbk +++ b/doc/shuffle_weighted.qbk @@ -22,6 +22,11 @@ The routines come in 2 forms; the first one takes two iterators to define the it There are two versions of algorithms: 1) takes three iterators and random generator. 2) takes two ranges and random generator. + +Also there are two versions for old compilers (which doesn't support C++11 or higher standard). +Difference is only one: C++11 or higher version takes UniformRandomBitGenerator parameter as universal reference, version for old compiler takes UniformRandomBitGenerator as reference. + +For C++11 or higher compilers: `` template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g); @@ -29,6 +34,13 @@ template void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g); `` +For old compilers: +`` +template +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator& g); +template +void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator& g); +`` [heading Examples] @@ -62,6 +74,7 @@ All of the variants of `shuffle_weighted` takes their parameters by iterators or * `shuffle_weighted` works also on empty sequences. +* Be careful: weights can be changed inside the function. [endsect] [/ File shuffle_weighted.qbk diff --git a/example/shuffle_weighted_example.cpp b/example/shuffle_weighted_example.cpp index 43b4f5a19..1c54404cf 100644 --- a/example/shuffle_weighted_example.cpp +++ b/example/shuffle_weighted_example.cpp @@ -19,6 +19,7 @@ namespace ba = boost::algorithm; int main ( int /*argc*/, char * /*argv*/ [] ) { + // WARNING: Example require C++11 or newer compiler std::random_device rd; std::mt19937 g(rd()); { diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index 7f3b3b81a..1b85b114f 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -17,7 +17,6 @@ #define BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP #include -#include #include @@ -41,9 +40,15 @@ namespace boost { namespace algorithm { /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). +#if __cplusplus > 199711L template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g) +#else +template +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, + ForwardIterator2 weight_begin, UniformRandomBitGenerator& g) +#endif { typedef typename std::iterator_traits::value_type weight_t; @@ -100,10 +105,16 @@ void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). template -void shuffle_weighted(Range1 item_range, Range2 weight_range, UniformRandomBitGenerator&& g) +#if __cplusplus > 199711L +void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g) { shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), boost::forward(g)); } - +#else +void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator& g) +{ + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), g); +} +#endif }} #endif //BOOST_ALGORITHM_SHUFFLE_WEIGHTED_HPP diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp index d2c7987a4..f0963075a 100644 --- a/test/shuffle_weighted_test.cpp +++ b/test/shuffle_weighted_test.cpp @@ -12,48 +12,50 @@ #define BOOST_TEST_MAIN #include -#include -#include -#include -#include -#include #include - - +#include #include namespace ba = boost::algorithm; - +namespace br = boost::random; void test_shuffle_weighted() { { // Empty case - std::mt19937_64 d; + br::mt19937_64 d; std::vector vec, weights; + ba::shuffle_weighted(vec, weights, d); BOOST_CHECK(vec.empty () && weights.empty()); } { // One element case - std::mt19937_64 d; - std::vector vec({1}), weights({1}); + br::mt19937_64 d; + std::vector vec, weights; + vec.push_back(1); + weights.push_back(1); std::vector new_vec = vec, new_weights = weights; + ba::shuffle_weighted(new_vec, new_weights, d); BOOST_CHECK(vec == new_vec && weights == new_weights); } { // Two element case - std::mt19937_64 d; - std::vector vec({1, 2}), rev_vec({2, 1}), weights({1, 2}); + br::mt19937_64 d; + std::vector vec, rev_vec, weights; + vec.push_back(1); vec.push_back(2); + rev_vec.push_back(2); rev_vec.push_back(1); + weights = vec; std::vector new_vec = vec, new_weights = weights; + ba::shuffle_weighted(new_vec, new_weights, d); - BOOST_CHECK((vec == new_vec || rev_vec == new_vec) && weights == new_weights); + BOOST_CHECK(vec == new_vec || rev_vec == new_vec); } } From b1a99d8388ae11b788bee661a894a021bb398b17 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Wed, 19 Jul 2017 22:09:11 +0300 Subject: [PATCH 12/13] Replaced huge headers from Boost --- include/boost/algorithm/shuffle_weighted.hpp | 22 +++++++++----------- test/shuffle_weighted_test.cpp | 2 +- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index 1b85b114f..0712c4f9a 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -18,13 +18,14 @@ #include +#include + #include -#include +#include +#include #include #include -#include -#include #include #include @@ -40,7 +41,7 @@ namespace boost { namespace algorithm { /// /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). -#if __cplusplus > 199711L +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g) @@ -55,8 +56,7 @@ void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, weight_t total_weight = 0; ForwardIterator2 weight_iter = weight_begin; for(ForwardIterator1 it = item_begin; it != item_end; - it = boost::next(it), - weight_iter = boost::next(weight_iter)) + it++, weight_iter++) { total_weight += *weight_iter; } @@ -70,16 +70,14 @@ void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, uniform_distr_t distribution; for (; item_begin != item_end; - item_begin = boost::next(item_begin), - weight_begin = boost::next(weight_begin)) + item_begin++, weight_begin++) { weight_t current_weights_sum = 0; const weight_t random_value = distribution(g, param_type(0, total_weight)); ForwardIterator2 weight_iter = weight_begin; for (ForwardIterator1 it = item_begin; it != item_end; - it = boost::next(it), - weight_iter = boost::next(weight_iter)) + it++, weight_iter++) { const weight_t weight = *weight_iter; current_weights_sum += weight; @@ -105,10 +103,10 @@ void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, /// \note Weight sequence size should be equal to item size. Otherwise behavior is undefined. /// Complexity: O(N^2). template -#if __cplusplus > 199711L +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g) { - shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), boost::forward(g)); + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), static_cast(g)); } #else void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator& g) diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp index f0963075a..ef42b3ab3 100644 --- a/test/shuffle_weighted_test.cpp +++ b/test/shuffle_weighted_test.cpp @@ -15,7 +15,7 @@ #include -#include +#include #include namespace ba = boost::algorithm; From 5ccece26bba005878ec97abfd8cc5650be00746d Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Wed, 30 Aug 2017 20:38:16 +0300 Subject: [PATCH 13/13] Different fixes --- doc/shuffle_weighted.qbk | 6 +++--- example/shuffle_weighted_example.cpp | 2 +- include/boost/algorithm/shuffle_weighted.hpp | 10 ++++++---- test/shuffle_weighted_test.cpp | 13 +++++++++++++ 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/doc/shuffle_weighted.qbk b/doc/shuffle_weighted.qbk index efa5957c6..4c68feebd 100644 --- a/doc/shuffle_weighted.qbk +++ b/doc/shuffle_weighted.qbk @@ -20,7 +20,7 @@ The routines come in 2 forms; the first one takes two iterators to define the it [heading interface] There are two versions of algorithms: -1) takes three iterators and random generator. +1) takes four iterators and random generator. 2) takes two ranges and random generator. Also there are two versions for old compilers (which doesn't support C++11 or higher standard). @@ -29,7 +29,7 @@ Difference is only one: C++11 or higher version takes UniformRandomBitGenerator For C++11 or higher compilers: `` template -void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g); +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, ForwardIterator2 weight_end, UniformRandomBitGenerator&& g); template void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g); `` @@ -37,7 +37,7 @@ void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBit For old compilers: `` template -void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, UniformRandomBitGenerator& g); +void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, ForwardIterator2 weight_begin, ForwardIterator2 weight_end, UniformRandomBitGenerator& g); template void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator& g); `` diff --git a/example/shuffle_weighted_example.cpp b/example/shuffle_weighted_example.cpp index 1c54404cf..3f1360999 100644 --- a/example/shuffle_weighted_example.cpp +++ b/example/shuffle_weighted_example.cpp @@ -26,7 +26,7 @@ int main ( int /*argc*/, char * /*argv*/ [] ) std::cout << "shuffle_weighted with iterators:\n"; std::vector vec{1, 2, 3, 4, 5}, order{4, 2, 3, 1, 0}; - ba::shuffle_weighted(vec.begin(), vec.end(), order.begin(), g); + ba::shuffle_weighted(vec.begin(), vec.end(), order.begin(), order.end(), g); for (const auto& x : vec) { std::cout << x << ", "; diff --git a/include/boost/algorithm/shuffle_weighted.hpp b/include/boost/algorithm/shuffle_weighted.hpp index 0712c4f9a..1a2ae67c3 100644 --- a/include/boost/algorithm/shuffle_weighted.hpp +++ b/include/boost/algorithm/shuffle_weighted.hpp @@ -44,11 +44,13 @@ namespace boost { namespace algorithm { #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, - ForwardIterator2 weight_begin, UniformRandomBitGenerator&& g) + ForwardIterator2 weight_begin, ForwardIterator2 weight_end, + UniformRandomBitGenerator&& g) #else template void shuffle_weighted(ForwardIterator1 item_begin, ForwardIterator1 item_end, - ForwardIterator2 weight_begin, UniformRandomBitGenerator& g) + ForwardIterator2 weight_begin, ForwardIterator2 weight_end, + UniformRandomBitGenerator& g) #endif { typedef typename std::iterator_traits::value_type weight_t; @@ -106,12 +108,12 @@ template #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator&& g) { - shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), static_cast(g)); + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), boost::end(weight_range), static_cast(g)); } #else void shuffle_weighted(Range1& item_range, Range2& weight_range, UniformRandomBitGenerator& g) { - shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), g); + shuffle_weighted(boost::begin(item_range), boost::end(item_range), boost::begin(weight_range), boost::end(weight_range), g); } #endif }} diff --git a/test/shuffle_weighted_test.cpp b/test/shuffle_weighted_test.cpp index ef42b3ab3..e6146fcfe 100644 --- a/test/shuffle_weighted_test.cpp +++ b/test/shuffle_weighted_test.cpp @@ -57,6 +57,19 @@ void test_shuffle_weighted() ba::shuffle_weighted(new_vec, new_weights, d); BOOST_CHECK(vec == new_vec || rev_vec == new_vec); } + { + // Two element case, iterator interface + + br::mt19937_64 d; + std::vector vec, rev_vec, weights; + vec.push_back(1); vec.push_back(2); + rev_vec.push_back(2); rev_vec.push_back(1); + weights = vec; + std::vector new_vec = vec, new_weights = weights; + + ba::shuffle_weighted(new_vec.begin(), new_vec.end(), new_weights.begin(), new_weights.end(), d); + BOOST_CHECK(vec == new_vec || rev_vec == new_vec); + } }