/*============================================================================= Copyright (c) 2011-2013 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_SEED_ARRAY_HPP #define SPROUT_RANDOM_SEED_ARRAY_HPP #include #include #include #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 seed_array_init { public: template SPROUT_CONSTEXPR UIntType operator()(IntType const& x) const { return static_cast(x % (std::uint_least64_t(2) << 32)); } }; template class seed_array_impl { public: typedef std::uint_least32_t result_type; protected: typedef sprout::array array_type; protected: array_type v; public: SPROUT_CONSTEXPR seed_array_impl() SPROUT_NOEXCEPT : v{{}} {} template SPROUT_CONSTEXPR seed_array_impl(InputIterator begin, InputIterator end) : v(sprout::fixed::transform(begin, end, sprout::random::detail::seed_array_init())) {} }; } // namespace detail // // seed_array // template class seed_array : public sprout::random::detail::seed_array_impl { private: typedef sprout::random::detail::seed_array_impl impl_type; public: typedef typename impl_type::result_type result_type; typedef result_type value_type; typedef std::size_t size_type; private: using impl_type::v; private: static SPROUT_CONSTEXPR result_type tp(result_type x) { return x ^ (x >> 27); } static SPROUT_CONSTEXPR size_type tval(size_type n) { return (n >= 623) ? 11 : (n >= 68) ? 7 : (n >= 39) ? 5 : (n >= 7) ? 3 : (n - 1) / 2 ; } template static SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type set2_impl( Result const& result, size_type kpn, size_type kqn, size_type kn, typename sprout::container_traits::value_type r3, typename sprout::container_traits::value_type r4, sprout::index_tuple ) { return sprout::remake( result, sprout::size(result), (Indexes == kn ? r4 : (result[Indexes] ^ (Indexes == kpn ? r3 : typename sprout::container_traits::value_type()) ^ (Indexes == kqn ? r4 : typename sprout::container_traits::value_type()) ) )... ); } template static SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type set2( Result const& result, size_type kpn, size_type kqn, size_type kn, typename sprout::container_traits::value_type r3, typename sprout::container_traits::value_type r4_3 ) { return set2_impl(result, kpn, kqn, kn, r3, r3 - r4_3, sprout::container_indexes::make()); } template static SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type set1_impl( Result const& result, size_type kpn, size_type kqn, size_type kn, typename sprout::container_traits::value_type r1, typename sprout::container_traits::value_type r2, sprout::index_tuple ) { return sprout::remake( result, sprout::size(result), (Indexes == kn ? r2 : (result[Indexes] + (Indexes == kpn ? r1 : typename sprout::container_traits::value_type()) + (Indexes == kqn ? r2 : typename sprout::container_traits::value_type()) ) )... ); } template static SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type set1( Result const& result, size_type kpn, size_type kqn, size_type kn, typename sprout::container_traits::value_type r1, typename sprout::container_traits::value_type r2_1 ) { return set1_impl(result, kpn, kqn, kn, r1, r1 + r2_1, sprout::container_indexes::make()); } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen2( Result const& result, size_type n, size_type s, size_type m, size_type t, size_type p, size_type q, size_type k ) const { return k < m + n ? gen2( set2( result, (k + p) % n, (k + q) % n, k % n, 1566083941 * tp(result[k % n] + result[(k + p) % n] + result[(k + n - 1) % n]), k % n ), n, s, m, t, p, q, k + 1 ) : sprout::deep_copy(result) ; } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen1_2( Result const& result, size_type n, size_type s, size_type m, size_type t, size_type p, size_type q, size_type k ) const { return k < m ? gen1_2( set1( result, (k + p) % n, (k + q) % n, k % n, 1664525 * tp(result[k % n] ^ result[(k + p) % n] ^ result[(k - 1) % n]), k % n ), n, s, m, t, p, q, k + 1 ) : sprout::deep_copy(result) ; } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen1_1( Result const& result, size_type n, size_type s, size_type m, size_type t, size_type p, size_type q, size_type k ) const { return k <= s ? gen1_1( set1( result, (k + p) % n, (k + q) % n, k % n, 1664525 * tp(result[k % n] ^ result[(k + p) % n] ^ result[(k - 1) % n]), k % n + v[k - 1] ), n, s, m, t, p, q, k + 1 ) : sprout::deep_copy(result) ; } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen1_0( Result const& result, size_type n, size_type s, size_type m, size_type t, size_type p, size_type q ) const { return set1( result, p, q, size_type(0), 1664525 * tp(result[0] ^ result[p] ^ result[n - 1]), s ); } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen_impl( Result const& result, size_type n, size_type s, size_type m, size_type t, size_type p, size_type q ) const { return gen2( gen1_2( gen1_1( gen1_0( result, n, s, m, t, p, q ), n, s, m, t, p, q, 1 ), n, s, m, t, p, q, s + 1 ), n, s, m, t, p, q, m ); } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type gen( Result const& result, TempResult const& temp_result, size_type n, size_type s, size_type m, size_type t ) const { return sprout::range::fixed::copy( gen_impl(temp_result, n, s, m, t, (n - t) / 2, (n - t) / 2 + t), result ); } public: SPROUT_CONSTEXPR seed_array() SPROUT_NOEXCEPT : impl_type() {} seed_array(seed_array const&) = default; template SPROUT_INITIALIZER_LIST_CONSTEXPR seed_array(std::initializer_list il) : impl_type(il.begin(), il.end()) {} template SPROUT_CONSTEXPR seed_array(InputIterator begin, InputIterator end) : impl_type(begin, end) {} template explicit SPROUT_CONSTEXPR seed_array(InputRange const& rng) : impl_type(sprout::begin(rng), sprout::end(rng)) {} template SPROUT_CXX14_CONSTEXPR void generate(RandomAccessIterator begin, RandomAccessIterator end) const { typedef typename std::iterator_traits::value_type value_type; if (begin == end) { return; } sprout::fill(begin, end, static_cast(0x8b8b8b8bu)); size_type n = end - begin; size_type s = size(); size_type m = sprout::max(s + 1, n); size_type t = tval(n); size_type p = (n - t) / 2; size_type q = p + t; for (size_type k = 0; k < m; ++k) { size_type kn = k % n; size_type kpn = (k + p) % n; size_type kqn = (k + q) % n; size_type k1n = (k + n - 1) % n; value_type r1 = 1664525 * tp(begin[kn] ^ begin[kpn] ^ begin[k1n]); value_type r2 = r1 + ( k == 0 ? s : k <= s ? (kn + v[k - 1]) : kn ); begin[kpn] += r1; begin[kqn] += r2; begin[kn] = r2; } for (size_type k = m; k < m + n; ++k) { size_type kn = k % n; size_type kpn = (k + p) % n; size_type kqn = (k + q) % n; size_type k1n = (k + n - 1) % n; value_type r3 = 1566083941 * tp(begin[kn] + begin[kpn] + begin[k1n]); value_type r4 = r3 - kn; begin[kpn] ^= r3; begin[kqn] ^= r4; begin[kn] = r4; } } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type generate(Result const& result) const { typedef typename sprout::container_traits::value_type value_type; typedef sprout::array::static_size> temp_type; return !sprout::empty(result) ? gen( result, sprout::pit(static_cast(0x8b8b8b8bu)), sprout::size(result), size(), sprout::max(size() + 1, sprout::size(result)), tval(sprout::size(result)) ) : sprout::detail::container_complate(result) ; } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type generate() const { return generate(sprout::pit()); } SPROUT_CONSTEXPR size_type size() const SPROUT_NOEXCEPT { return v.size(); } template< typename OutputIterator, typename sprout::enabler_if::value>::type = sprout::enabler > SPROUT_CXX14_CONSTEXPR void param(OutputIterator dest) const { sprout::copy(v.begin(), v.end(), dest); } SPROUT_CONSTEXPR sprout::array const& param() const { return v; } template< typename Result, typename sprout::enabler_if::value>::type = sprout::enabler > SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type param(Result const& result) const { return sprout::fixed::copy(v.begin(), v.end(), result); } template SPROUT_CONSTEXPR typename sprout::fixed::result_of::algorithm::type param() const { return sprout::fixed::copy(v.begin(), v.end()); } }; // // make_seed_array // template inline SPROUT_CONSTEXPR sprout::random::seed_array make_seed_array(Args&&... args) { return sprout::random::seed_array( sprout::make_common_array(sprout::forward(args)...) ); } } // namespace random using sprout::random::seed_array; using sprout::random::make_seed_array; } // namespace sprout #endif // #ifndef SPROUT_RANDOM_SEED_ARRAY_HPP