From 1ed284d6961505a1d57d94b4ab07fdb2b0eff2e5 Mon Sep 17 00:00:00 2001 From: Alexander Zaitsev Date: Thu, 18 May 2017 20:38:07 -0600 Subject: [PATCH] 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 0000000..feaa9f2 --- /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 0000000..f14ba65 --- /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