diff options
Diffstat (limited to 'src/third_party/boost-1.69.0/boost/random/detail/gray_coded_qrng.hpp')
-rw-r--r-- | src/third_party/boost-1.69.0/boost/random/detail/gray_coded_qrng.hpp | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/src/third_party/boost-1.69.0/boost/random/detail/gray_coded_qrng.hpp b/src/third_party/boost-1.69.0/boost/random/detail/gray_coded_qrng.hpp new file mode 100644 index 00000000000..643ec38d9dc --- /dev/null +++ b/src/third_party/boost-1.69.0/boost/random/detail/gray_coded_qrng.hpp @@ -0,0 +1,166 @@ +/* boost random/detail/gray_coded_qrng.hpp header file + * + * Copyright Justinas Vygintas Daugmaudis 2010-2018 + * 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 BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP +#define BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP + +#include <boost/random/detail/qrng_base.hpp> + +#include <boost/multiprecision/integer.hpp> // lsb + +#include <functional> // bit_xor + +#include <boost/mpl/if.hpp> + +#include <boost/integer/integer_mask.hpp> + +//!\file +//!Describes the gray-coded quasi-random number generator base class template. + +namespace boost { +namespace random { + +namespace qrng_detail { + +template<typename LatticeT> +class gray_coded_qrng + : public qrng_base< + gray_coded_qrng<LatticeT> + , LatticeT + , typename LatticeT::value_type + > +{ +public: + typedef typename LatticeT::value_type result_type; + typedef result_type size_type; + +private: + typedef gray_coded_qrng<LatticeT> self_t; + typedef qrng_base<self_t, LatticeT, size_type> base_t; + + // The base needs to access modifying member f-ns, and we + // don't want these functions to be available for the public use + friend class qrng_base<self_t, LatticeT, size_type>; + + // Respect lattice bit_count here + struct check_nothing { + inline static void bit_pos(unsigned) {} + inline static void code_size(size_type) {} + }; + struct check_bit_range { + static void raise_bit_count() { + boost::throw_exception( std::range_error("gray_coded_qrng: bit_count") ); + } + inline static void bit_pos(unsigned bit_pos) { + if (bit_pos >= LatticeT::bit_count) + raise_bit_count(); + } + inline static void code_size(size_type code) { + if (code > (self_t::max)()) + raise_bit_count(); + } + }; + + // We only want to check whether bit pos is outside the range if given bit_count + // is narrower than the size_type, otherwise checks compile to nothing. + BOOST_STATIC_ASSERT(LatticeT::bit_count <= std::numeric_limits<size_type>::digits); + + typedef typename mpl::if_c< + ((LatticeT::bit_count) < std::numeric_limits<size_type>::digits) + , check_bit_range + , check_nothing + >::type check_bit_range_t; + +public: + //!Returns: Tight lower bound on the set of values returned by operator(). + //! + //!Throws: nothing. + static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () + { return 0; } + + //!Returns: Tight upper bound on the set of values returned by operator(). + //! + //!Throws: nothing. + static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () + { return low_bits_mask_t<LatticeT::bit_count>::sig_bits; } + + explicit gray_coded_qrng(std::size_t dimension) + : base_t(dimension) + {} + + // default copy c-tor is fine + + // default assignment operator is fine + + void seed() + { + set_zero_state(); + update_quasi(0); + base_t::reset_seq(0); + } + + void seed(const size_type init) + { + if (init != this->curr_seq()) + { + // We don't want negative seeds. + check_seed_sign(init); + + size_type seq_code = boost::next(init); + if (BOOST_UNLIKELY(!(init < seq_code))) + boost::throw_exception( std::range_error("gray_coded_qrng: seed") ); + + seq_code ^= (seq_code >> 1); + // Fail if we see that seq_code is outside bit range. + // We do that before we even touch engine state. + check_bit_range_t::code_size(seq_code); + + set_zero_state(); + for (unsigned r = 0; seq_code != 0; ++r, seq_code >>= 1) + { + if (seq_code & static_cast<size_type>(1)) + update_quasi(r); + } + } + // Everything went well, set the new seq count + base_t::reset_seq(init); + } + +private: + void compute_seq(size_type seq) + { + // Find the position of the least-significant zero in sequence count. + // This is the bit that changes in the Gray-code representation as + // the count is advanced. + // Xor'ing with max() has the effect of flipping all the bits in seq, + // except for the sign bit. + unsigned r = multiprecision::lsb(seq ^ (self_t::max)()); + check_bit_range_t::bit_pos(r); + update_quasi(r); + } + + void update_quasi(unsigned r) + { + // Calculate the next state. + std::transform(this->state_begin(), this->state_end(), + this->lattice.iter_at(r * this->dimension()), this->state_begin(), + std::bit_xor<result_type>()); + } + + void set_zero_state() + { + std::fill(this->state_begin(), this->state_end(), result_type /*zero*/ ()); + } +}; + +} // namespace qrng_detail + +} // namespace random +} // namespace boost + +#endif // BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP |