#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 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_; }; } // namespace detail // // shuffle_order_engine // template class shuffle_order_engine : private sprout::random::detail::shuffle_order_engine_member { static_assert( std::numeric_limits::is_integer, "std::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_constructor_tag {}; 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< sizeof...(Args) == k, member_type >::type init_member_1(Random const& rnd, Args const&... args) { return member_type{ rnd.engine(), sprout::array{{args...}}, rnd.result() }; } template static SPROUT_CONSTEXPR typename std::enable_if< sizeof...(Args) < k, member_type >::type init_member_1(Random const& rnd, Args const&... args) { return init_member_1(rnd(), args..., rnd.result()); } static SPROUT_CONSTEXPR member_type init_member(base_type const& rng) { return init_member_1(rng()); } 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 const& y, private_constructor_tag ) : member_type{rng, v, y} {} template SPROUT_CONSTEXPR sprout::random::random_result generate_1(Random const& rnd, BaseUnsigned j) const { return sprout::random::random_result( v_[j], shuffle_order_engine( rnd.engine(), sprout::fixed::set(v_, j, rnd.result()), v_[j], private_constructor_tag() ) ); } template SPROUT_CONSTEXPR sprout::random::random_result generate(BaseUnsigned brange, BaseUnsigned off) const { return generate_1( rng_(), k == 1 ? BaseUnsigned(0) : brange < std::numeric_limits::max() / k ? BaseUnsigned(k * off / (brange + 1)) : brange < std::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)) // ??? : throw std::domain_error("shuffle_order_engine<>: Sorry, not implemented.") ); } public: SPROUT_CONSTEXPR shuffle_order_engine() : member_type(init_member(base_type())) {} explicit SPROUT_CONSTEXPR shuffle_order_engine(result_type const& s) : member_type(init_member(base_type(s))) {} explicit SPROUT_CONSTEXPR shuffle_order_engine(base_type const& rng) : member_type(init_member(rng)) {} SPROUT_CONSTEXPR result_type min() const SPROUT_NOEXCEPT { return rng_.min(); } SPROUT_CONSTEXPR result_type max() const SPROUT_NOEXCEPT { return rng_.max(); } SPROUT_CONSTEXPR sprout::random::random_result 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 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 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 // typedef sprout::random::shuffle_order_engine knuth_b; // // kreutzer1986 // 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