gray_coded_qrng.hpp 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* boost random/detail/gray_coded_qrng.hpp header file
  2. *
  3. * Copyright Justinas Vygintas Daugmaudis 2010-2018
  4. * Distributed under the Boost Software License, Version 1.0. (See
  5. * accompanying file LICENSE_1_0.txt or copy at
  6. * http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. #ifndef BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP
  9. #define BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP
  10. #include <boost/random/detail/qrng_base.hpp>
  11. #include <boost/multiprecision/integer.hpp> // lsb
  12. #include <functional> // bit_xor
  13. #include <boost/mpl/if.hpp>
  14. #include <boost/integer/integer_mask.hpp>
  15. //!\file
  16. //!Describes the gray-coded quasi-random number generator base class template.
  17. namespace boost {
  18. namespace random {
  19. namespace qrng_detail {
  20. template<typename LatticeT>
  21. class gray_coded_qrng
  22. : public qrng_base<
  23. gray_coded_qrng<LatticeT>
  24. , LatticeT
  25. , typename LatticeT::value_type
  26. >
  27. {
  28. public:
  29. typedef typename LatticeT::value_type result_type;
  30. typedef result_type size_type;
  31. private:
  32. typedef gray_coded_qrng<LatticeT> self_t;
  33. typedef qrng_base<self_t, LatticeT, size_type> base_t;
  34. // The base needs to access modifying member f-ns, and we
  35. // don't want these functions to be available for the public use
  36. friend class qrng_base<self_t, LatticeT, size_type>;
  37. // Respect lattice bit_count here
  38. struct check_nothing {
  39. inline static void bit_pos(unsigned) {}
  40. inline static void code_size(size_type) {}
  41. };
  42. struct check_bit_range {
  43. static void raise_bit_count() {
  44. boost::throw_exception( std::range_error("gray_coded_qrng: bit_count") );
  45. }
  46. inline static void bit_pos(unsigned bit_pos) {
  47. if (bit_pos >= LatticeT::bit_count)
  48. raise_bit_count();
  49. }
  50. inline static void code_size(size_type code) {
  51. if (code > (self_t::max)())
  52. raise_bit_count();
  53. }
  54. };
  55. // We only want to check whether bit pos is outside the range if given bit_count
  56. // is narrower than the size_type, otherwise checks compile to nothing.
  57. BOOST_STATIC_ASSERT(LatticeT::bit_count <= std::numeric_limits<size_type>::digits);
  58. typedef typename mpl::if_c<
  59. ((LatticeT::bit_count) < std::numeric_limits<size_type>::digits)
  60. , check_bit_range
  61. , check_nothing
  62. >::type check_bit_range_t;
  63. public:
  64. //!Returns: Tight lower bound on the set of values returned by operator().
  65. //!
  66. //!Throws: nothing.
  67. static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
  68. { return 0; }
  69. //!Returns: Tight upper bound on the set of values returned by operator().
  70. //!
  71. //!Throws: nothing.
  72. static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  73. { return low_bits_mask_t<LatticeT::bit_count>::sig_bits; }
  74. explicit gray_coded_qrng(std::size_t dimension)
  75. : base_t(dimension)
  76. {}
  77. // default copy c-tor is fine
  78. // default assignment operator is fine
  79. void seed()
  80. {
  81. set_zero_state();
  82. update_quasi(0);
  83. base_t::reset_seq(0);
  84. }
  85. void seed(const size_type init)
  86. {
  87. if (init != this->curr_seq())
  88. {
  89. // We don't want negative seeds.
  90. check_seed_sign(init);
  91. size_type seq_code = boost::next(init);
  92. if (BOOST_UNLIKELY(!(init < seq_code)))
  93. boost::throw_exception( std::range_error("gray_coded_qrng: seed") );
  94. seq_code ^= (seq_code >> 1);
  95. // Fail if we see that seq_code is outside bit range.
  96. // We do that before we even touch engine state.
  97. check_bit_range_t::code_size(seq_code);
  98. set_zero_state();
  99. for (unsigned r = 0; seq_code != 0; ++r, seq_code >>= 1)
  100. {
  101. if (seq_code & static_cast<size_type>(1))
  102. update_quasi(r);
  103. }
  104. }
  105. // Everything went well, set the new seq count
  106. base_t::reset_seq(init);
  107. }
  108. private:
  109. void compute_seq(size_type seq)
  110. {
  111. // Find the position of the least-significant zero in sequence count.
  112. // This is the bit that changes in the Gray-code representation as
  113. // the count is advanced.
  114. // Xor'ing with max() has the effect of flipping all the bits in seq,
  115. // except for the sign bit.
  116. unsigned r = multiprecision::lsb(seq ^ (self_t::max)());
  117. check_bit_range_t::bit_pos(r);
  118. update_quasi(r);
  119. }
  120. void update_quasi(unsigned r)
  121. {
  122. // Calculate the next state.
  123. std::transform(this->state_begin(), this->state_end(),
  124. this->lattice.iter_at(r * this->dimension()), this->state_begin(),
  125. std::bit_xor<result_type>());
  126. }
  127. void set_zero_state()
  128. {
  129. std::fill(this->state_begin(), this->state_end(), result_type /*zero*/ ());
  130. }
  131. };
  132. } // namespace qrng_detail
  133. } // namespace random
  134. } // namespace boost
  135. #endif // BOOST_RANDOM_DETAIL_GRAY_CODED_QRNG_HPP