/*============================================================================= Copyright (c) 2011-2015 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_RANDOM_SHUFFLE_ORDER_HPP #define SPROUT_RANDOM_SHUFFLE_ORDER_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace sprout { namespace random { namespace detail { template class shuffle_order_engine_member { protected: typedef UniformRandomNumberGenerator base_type; typedef typename base_type::result_type result_type; public: base_type rng_; sprout::array v_; result_type y_; public: SPROUT_CXX14_CONSTEXPR shuffle_order_engine_member& operator=(shuffle_order_engine_member const& rhs) { rng_ = rhs.rng_; v_ = rhs.v_; y_ = rhs.y_; return *this; } }; } // namespace detail // // shuffle_order_engine // template class shuffle_order_engine : private sprout::random::detail::shuffle_order_engine_member { static_assert( sprout::numeric_limits::is_integer, "sprout::numeric_limits::is_integer" ); static_assert(k > 0, "k > 0"); private: typedef sprout::random::detail::shuffle_order_engine_member member_type; public: typedef UniformRandomNumberGenerator base_type; typedef typename base_type::result_type result_type; private: struct private_construct_t {}; public: SPROUT_STATIC_CONSTEXPR std::size_t buffer_size = k; SPROUT_STATIC_CONSTEXPR std::size_t table_size = k; public: static SPROUT_CONSTEXPR result_type static_min() SPROUT_NOEXCEPT { return base_type::static_min(); } static SPROUT_CONSTEXPR result_type static_max() SPROUT_NOEXCEPT { return base_type::static_max(); } private: template static SPROUT_CONSTEXPR typename std::enable_if< (M + sizeof...(Args) == k), member_type >::type init_member_4(sprout::index_tuple, sprout::array const& a, EngineResult const& rnd, Args const&... args) { return member_type{ sprout::random::next(rnd), sprout::array{{a[Indexes]..., args...}}, sprout::random::result(rnd) }; } template static SPROUT_CONSTEXPR typename std::enable_if< (M + sizeof...(Args) == k), member_type >::type init_member_3(sprout::array const& a, EngineResult const& rnd, Args const&... args) { return init_member_4(sprout::make_index_tuple::make(), a, rnd, args...); } template static SPROUT_CONSTEXPR typename std::enable_if< (M + sizeof...(Args) < k), member_type >::type init_member_3(sprout::array const& a, EngineResult const& rnd, Args const&... args) { return init_member_3(a, sprout::random::next(rnd)(), args..., sprout::random::result(rnd)); } template static SPROUT_CONSTEXPR member_type init_member_2(Pair const& p) { return init_member_3(p.first, p.second()); } template static SPROUT_CONSTEXPR typename std::enable_if< (sizeof...(Args) == k), member_type >::type init_member_1(EngineResult const& rnd, Args const&... args) { return member_type{ sprout::random::next(rnd), sprout::array{{args...}}, sprout::random::result(rnd) }; } template static SPROUT_CONSTEXPR typename std::enable_if< (sizeof...(Args) < k), member_type >::type init_member_1(EngineResult const& rnd, Args const&... args) { return init_member_1(sprout::random::next(rnd)(), args..., sprout::random::result(rnd)); } static SPROUT_CONSTEXPR member_type init_member_0(base_type const& rng, std::true_type) { return init_member_2(sprout::random::generate_array(rng)); } static SPROUT_CONSTEXPR member_type init_member_0(base_type const& rng, std::false_type) { return init_member_1(rng()); } static SPROUT_CONSTEXPR member_type init_member(base_type const& rng) { return init_member_0(rng, std::integral_constant= SPROUT_RECURSIVE_FUNCTION_TEMPLATE_INSTANTIATION_LIMIT)>()); } private: using member_type::rng_; using member_type::v_; using member_type::y_; private: SPROUT_CONSTEXPR shuffle_order_engine( base_type const& rng, sprout::array const& v, result_type y, private_construct_t ) : member_type{rng, v, y} {} template SPROUT_CONSTEXPR sprout::random::random_result generate_1(EngineResult const& rnd, BaseUnsigned j) const { return sprout::random::random_result( v_[j], shuffle_order_engine( sprout::random::next(rnd), sprout::fixed::set(v_, j, sprout::random::result(rnd)), v_[j], private_construct_t() ) ); } template SPROUT_CONSTEXPR sprout::random::random_result generate(BaseUnsigned brange, BaseUnsigned off) const { return generate_1( rng_(), k == 1 ? BaseUnsigned(0) : sprout::math::less(brange, sprout::numeric_limits::max() / k) ? BaseUnsigned(k * off / (brange + 1)) : sprout::math::less(brange, sprout::numeric_limits::max() / k) ? static_cast(static_cast(off) * k / (static_cast(brange) + 1)) // : static_cast(sprout::random::detail::muldiv(off, k, static_cast(brange) + 1)) // ??? : (SPROUT_ASSERT_MSG(0, "Sorry, not implemented."), sprout::random::random_result()) ); } public: SPROUT_CONSTEXPR shuffle_order_engine() : member_type(init_member(base_type())) {} shuffle_order_engine(shuffle_order_engine const&) = default; explicit SPROUT_CONSTEXPR shuffle_order_engine(result_type seed) : member_type(init_member(base_type(seed))) {} template::value>::type = sprout::enabler> explicit SPROUT_CXX14_CONSTEXPR shuffle_order_engine(Sseq& seq) : member_type(init_member(base_type(seq))) {} template::value>::type = sprout::enabler> explicit SPROUT_CONSTEXPR shuffle_order_engine(Sseq const& seq) : member_type(init_member(base_type(seq))) {} template SPROUT_CONSTEXPR shuffle_order_engine(InputIterator first, InputIterator last) : member_type(init_member(base_type(first, last))) {} explicit SPROUT_CONSTEXPR shuffle_order_engine(base_type const& rng) : member_type(init_member(rng)) {} SPROUT_CXX14_CONSTEXPR void seed() { member_type::operator=(init_member(base_type())); } SPROUT_CXX14_CONSTEXPR void seed(result_type seed) { member_type::operator=(init_member(base_type(seed))); } template::value>::type = sprout::enabler> SPROUT_CXX14_CONSTEXPR void seed(Sseq& seq) { member_type::operator=(init_member(base_type(seq))); } template::value>::type = sprout::enabler> SPROUT_CXX14_CONSTEXPR void seed(Sseq const& seq) { member_type::operator=(init_member(base_type(seq))); } template SPROUT_CXX14_CONSTEXPR void seed(InputIterator first, InputIterator last) { member_type::operator=(init_member(base_type(first, last))); } SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return rng_.min(); } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return rng_.max(); } SPROUT_CXX14_CONSTEXPR result_type operator()() { typedef typename std::make_unsigned::type base_unsigned; base_unsigned const brange = sprout::random::detail::subtract()(max(), min()); base_unsigned const off = sprout::random::detail::subtract()(y_, min()); base_unsigned j = k == 1 ? base_unsigned(0) : sprout::math::less(brange, sprout::numeric_limits::max() / k) ? base_unsigned(k * off / (brange + 1)) : sprout::math::less(brange, sprout::numeric_limits::max() / k) ? static_cast(static_cast(off) * k / (static_cast(brange) + 1)) // : static_cast(sprout::random::detail::muldiv(off, k, static_cast(brange) + 1)) // ??? : (SPROUT_ASSERT_MSG(0, "Sorry, not implemented."), base_unsigned(0)) ; y_ = v_[j]; v_[j] = static_cast(rng_()); return y_; } SPROUT_CONSTEXPR sprout::random::random_result const operator()() const { typedef typename std::make_unsigned::type base_unsigned; return generate( base_unsigned(sprout::random::detail::subtract()(max(), min())), base_unsigned(sprout::random::detail::subtract()(y_, min())) ); } SPROUT_CONSTEXPR base_type const& base() const SPROUT_NOEXCEPT { return rng_; } friend SPROUT_CONSTEXPR bool operator==(shuffle_order_engine const& lhs, shuffle_order_engine const& rhs) SPROUT_NOEXCEPT { return lhs.rng_ == rhs.rng_ && lhs.y_ == rhs.y_ && lhs.v_ == rhs.v_; } friend SPROUT_CONSTEXPR bool operator!=(shuffle_order_engine const& lhs, shuffle_order_engine const& rhs) SPROUT_NOEXCEPT { return !(lhs == rhs); } template friend SPROUT_NON_CONSTEXPR std::basic_istream& operator>>( std::basic_istream& lhs, shuffle_order_engine& rhs ) { lhs >> rhs.rng_; for (std::size_t i = 0; i < k; ++i) { lhs >> std::ws >> rhs.v_[i]; } lhs >> std::ws >> rhs.y_; return lhs; } template friend SPROUT_NON_CONSTEXPR std::basic_ostream& operator<<( std::basic_ostream& lhs, shuffle_order_engine const& rhs ) { lhs << rhs.rng_; for (std::size_t i = 0; i < k; ++i) { lhs << ' ' << rhs.v_[i]; } lhs << ' ' << rhs.y_; return lhs; } }; template SPROUT_CONSTEXPR_OR_CONST std::size_t sprout::random::shuffle_order_engine::buffer_size; template SPROUT_CONSTEXPR_OR_CONST std::size_t sprout::random::shuffle_order_engine::table_size; // // knuth_b // kreutzer1986 // typedef sprout::random::shuffle_order_engine knuth_b; typedef sprout::random::shuffle_order_engine, 97> kreutzer1986; } // namespace random using sprout::random::shuffle_order_engine; using sprout::random::knuth_b; using sprout::random::kreutzer1986; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_SHUFFLE_ORDER_HPP