From 6e962b0cccf5e65267d00b8507efbc9ff03aab6f Mon Sep 17 00:00:00 2001 From: bolero-MURAKAMI Date: Tue, 10 Oct 2017 18:54:31 +0900 Subject: [PATCH] add transform_reduce algorithm --- sprout/numeric/non_modifying.hpp | 1 + sprout/numeric/transform_reduce.hpp | 243 ++++++++++++++++++++++ sprout/range/numeric/non_modifying.hpp | 1 + sprout/range/numeric/transform_reduce.hpp | 43 ++++ 4 files changed, 288 insertions(+) create mode 100644 sprout/numeric/transform_reduce.hpp create mode 100644 sprout/range/numeric/transform_reduce.hpp diff --git a/sprout/numeric/non_modifying.hpp b/sprout/numeric/non_modifying.hpp index 1dff6adc..1048b1f2 100644 --- a/sprout/numeric/non_modifying.hpp +++ b/sprout/numeric/non_modifying.hpp @@ -12,5 +12,6 @@ #include #include #include +#include #endif // #ifndef SPROUT_NUMERIC_NON_MODIFYIING_HPP diff --git a/sprout/numeric/transform_reduce.hpp b/sprout/numeric/transform_reduce.hpp new file mode 100644 index 00000000..e0494e1f --- /dev/null +++ b/sprout/numeric/transform_reduce.hpp @@ -0,0 +1,243 @@ +/*============================================================================= + Copyright (c) 2011-2017 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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) +=============================================================================*/ +#ifndef SPROUT_NUMERIC_TRANSFORM_REDUCE_HPP +#define SPROUT_NUMERIC_TRANSFORM_REDUCE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace sprout { + namespace detail { + template + inline SPROUT_CONSTEXPR T + transform_reduce_ra( + RandomAccessIterator1 const& first1, RandomAccessIterator1 const& last1, RandomAccessIterator2 const& first2, + BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, + typename std::iterator_traits::difference_type pivot, T const& init + ) + { + return pivot == 0 ? binary_op1(init, binary_op2(*first1, *first2)) + : sprout::detail::transform_reduce_ra( + sprout::next(first1, pivot), last1, sprout::next(first2, pivot), binary_op1, binary_op2, + (sprout::distance(first1, last1) - pivot) / 2, + sprout::detail::transform_reduce_ra( + first1, sprout::next(first1, pivot), first2, binary_op1, binary_op2, + pivot / 2, + init + ) + ) + ; + } + template + inline SPROUT_CONSTEXPR typename std::enable_if< + sprout::is_constant_distance_iterator::value, + T + >::type + transform_reduce( + RandomAccessIterator1 const& first1, RandomAccessIterator1 const& last1, RandomAccessIterator2 const& first2, + T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, + std::random_access_iterator_tag* + ) + { + return first1 == last1 ? init + : sprout::detail::transform_reduce_ra( + first1, last1, first2, binary_op1, binary_op2, + sprout::distance(first1, last1) / 2, + init + ) + ; + } + + template + inline SPROUT_CONSTEXPR sprout::tuple + transform_reduce_impl_1( + sprout::tuple const& current, + InputIterator1 const& last1, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, + typename std::iterator_traits::difference_type n + ) + { + typedef sprout::tuple type; + return sprout::get<0>(current) == last1 ? current + : n == 1 ? type( + sprout::next(sprout::get<0>(current)), sprout::next(sprout::get<1>(current)), + binary_op1(sprout::get<2>(current), binary_op2(*sprout::get<0>(current), *sprout::get<1>(current))) + ) + : sprout::detail::transform_reduce_impl_1( + sprout::detail::transform_reduce_impl_1( + current, + last1, binary_op1, binary_op2, n / 2 + ), + last1, binary_op1, binary_op2, n - n / 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::tuple + transform_reduce_impl( + sprout::tuple const& current, + InputIterator1 const& last1, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, + typename std::iterator_traits::difference_type n + ) + { + return sprout::get<0>(current) == last1 ? current + : sprout::detail::transform_reduce_impl( + sprout::detail::transform_reduce_impl_1( + current, + last1, binary_op1, binary_op2, n + ), + last1, binary_op1, binary_op2, n * 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR T + transform_reduce( + InputIterator1 const& first1, InputIterator1 const& last1, InputIterator2 const& first2, + T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2, + std::input_iterator_tag* + ) + { + typedef sprout::tuple type; + return sprout::get<2>(sprout::detail::transform_reduce_impl(type(first1, first2, init), last1, binary_op1, binary_op2, 1)); + } + } // namespace detail + + // + // transform_reduce + // + // recursion depth: + // O(log N) + // + template + inline SPROUT_CONSTEXPR T + transform_reduce( + InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, + T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2 + ) + { + typedef typename sprout::common_iterator_category::type* category; + return sprout::detail::transform_reduce(first1, last1, first2, init, binary_op1, binary_op2, category()); + } + + template + inline SPROUT_CONSTEXPR T + transform_reduce(InputIterator1 first1, InputIterator1 last1, InputIterator2 first2, T init) { + typedef typename sprout::common_iterator_category::type* category; + return sprout::detail::transform_reduce(first1, last1, first2, init, sprout::plus<>(), sprout::multiplies<>(), category()); + } + + namespace detail { + template + inline SPROUT_CONSTEXPR T + transform_reduce_ra( + RandomAccessIterator const& first, RandomAccessIterator const& last, BinaryOperation binary_op, UnaryOperation unary_op, + typename std::iterator_traits::difference_type pivot, T const& init + ) + { + return pivot == 0 ? binary_op(init, unary_op(*first)) + : sprout::detail::transform_reduce_ra( + sprout::next(first, pivot), last, binary_op, unary_op, + (sprout::distance(first, last) - pivot) / 2, + sprout::detail::transform_reduce_ra( + first, sprout::next(first, pivot), binary_op, unary_op, + pivot / 2, + init + ) + ) + ; + } + template + inline SPROUT_CONSTEXPR typename std::enable_if< + sprout::is_constant_distance_iterator::value, + T + >::type + transform_reduce( + RandomAccessIterator const& first, RandomAccessIterator const& last, T init, BinaryOperation binary_op, UnaryOperation unary_op, + std::random_access_iterator_tag* + ) + { + return first == last ? init + : sprout::detail::transform_reduce_ra( + first, last, binary_op, unary_op, + sprout::distance(first, last) / 2, + init + ) + ; + } + + template + inline SPROUT_CONSTEXPR sprout::pair + transform_reduce_impl_1( + sprout::pair const& current, + InputIterator const& last, BinaryOperation binary_op, UnaryOperation unary_op, + typename std::iterator_traits::difference_type n + ) + { + typedef sprout::pair type; + return current.first == last ? current + : n == 1 ? type(sprout::next(current.first), binary_op(current.second, unary_op(*current.first))) + : sprout::detail::transform_reduce_impl_1( + sprout::detail::transform_reduce_impl_1( + current, + last, binary_op, unary_op, n / 2 + ), + last, binary_op, unary_op, n - n / 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR sprout::pair + transform_reduce_impl( + sprout::pair const& current, + InputIterator const& last, BinaryOperation binary_op, UnaryOperation unary_op, + typename std::iterator_traits::difference_type n + ) + { + return current.first == last ? current + : sprout::detail::transform_reduce_impl( + sprout::detail::transform_reduce_impl_1( + current, + last, binary_op, unary_op, n + ), + last, binary_op, unary_op, n * 2 + ) + ; + } + template + inline SPROUT_CONSTEXPR T + transform_reduce( + InputIterator const& first, InputIterator const& last, T init, BinaryOperation binary_op, UnaryOperation unary_op, + std::input_iterator_tag* + ) + { + typedef sprout::pair type; + return sprout::detail::transform_reduce_impl(type(first, init), last, binary_op, unary_op, 1).second; + } + } // namespace detail + + // + // transform_reduce + // + // recursion depth: + // O(log N) + // + template + inline SPROUT_CONSTEXPR T + transform_reduce(InputIterator first, InputIterator last, T init, BinaryOperation binary_op, UnaryOperation unary_op) { + typedef typename std::iterator_traits::iterator_category* category; + return sprout::detail::transform_reduce(first, last, init, binary_op, unary_op, category()); + } +} // namespace sprout + +#endif // #ifndef SPROUT_NUMERIC_TRANSFORM_REDUCE_HPP diff --git a/sprout/range/numeric/non_modifying.hpp b/sprout/range/numeric/non_modifying.hpp index ee3f5bda..839defc3 100644 --- a/sprout/range/numeric/non_modifying.hpp +++ b/sprout/range/numeric/non_modifying.hpp @@ -12,5 +12,6 @@ #include #include #include +#include #endif // #ifndef SPROUT_RANGE_NUMERIC_NON_MODIFYIING_HPP diff --git a/sprout/range/numeric/transform_reduce.hpp b/sprout/range/numeric/transform_reduce.hpp new file mode 100644 index 00000000..c6c97867 --- /dev/null +++ b/sprout/range/numeric/transform_reduce.hpp @@ -0,0 +1,43 @@ +/*============================================================================= + Copyright (c) 2011-2017 Bolero MURAKAMI + https://github.com/bolero-MURAKAMI/Sprout + + 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) +=============================================================================*/ +#ifndef SPROUT_RANGE_NUMERIC_TRANSFORM_REDUCE_HPP +#define SPROUT_RANGE_NUMERIC_TRANSFORM_REDUCE_HPP + +#include +#include +#include + +namespace sprout { + namespace range { + + // 29.8.5 Transform reduce + template + inline SPROUT_CONSTEXPR T + transform_reduce( + InputRange1 const& range1, InputRange2 const& range2, + T init, BinaryOperation1 binary_op1, BinaryOperation2 binary_op2 + ) + { + return sprout::transform_reduce(sprout::begin(range1), sprout::end(range1), sprout::begin(range2), init, binary_op1, binary_op2); + } + + template + inline SPROUT_CONSTEXPR T + transform_reduce(InputRange1 const& range1, InputRange2 const& range2, T init) { + return sprout::transform_reduce(sprout::begin(range1), sprout::end(range1), sprout::begin(range2), init); + } + + template + inline SPROUT_CONSTEXPR T + transform_reduce(InputRange const& range, T init, BinaryOperation binary_op, UnaryOperation unary_op) { + return sprout::transform_reduce(sprout::begin(range), sprout::end(range), init, binary_op, unary_op); + } + } // namespace range +} // namespace sprout + +#endif // #ifndef SPROUT_RANGE_NUMERIC_TRANSFORM_REDUCE_HPP