sobol.hpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. /* boost random/sobol.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_SOBOL_HPP
  9. #define BOOST_RANDOM_SOBOL_HPP
  10. #include <boost/random/detail/sobol_table.hpp>
  11. #include <boost/random/detail/gray_coded_qrng.hpp>
  12. #include <boost/assert.hpp>
  13. namespace boost {
  14. namespace random {
  15. /** @cond */
  16. namespace qrng_detail {
  17. // sobol_lattice sets up the random-number generator to produce a Sobol
  18. // sequence of at most max dims-dimensional quasi-random vectors.
  19. // Adapted from ACM TOMS algorithm 659, see
  20. // http://doi.acm.org/10.1145/42288.214372
  21. template<typename UIntType, unsigned w, typename SobolTables>
  22. struct sobol_lattice
  23. {
  24. typedef UIntType value_type;
  25. BOOST_STATIC_ASSERT(w > 0u);
  26. BOOST_STATIC_CONSTANT(unsigned, bit_count = w);
  27. private:
  28. typedef std::vector<value_type> container_type;
  29. public:
  30. explicit sobol_lattice(std::size_t dimension)
  31. {
  32. resize(dimension);
  33. }
  34. // default copy c-tor is fine
  35. void resize(std::size_t dimension)
  36. {
  37. dimension_assert("Sobol", dimension, SobolTables::max_dimension);
  38. // Initialize the bit array
  39. container_type cj(bit_count * dimension);
  40. // Initialize direction table in dimension 0
  41. for (unsigned k = 0; k != bit_count; ++k)
  42. cj[dimension*k] = static_cast<value_type>(1);
  43. // Initialize in remaining dimensions.
  44. for (std::size_t dim = 1; dim < dimension; ++dim)
  45. {
  46. const typename SobolTables::value_type poly = SobolTables::polynomial(dim-1);
  47. if (poly > (std::numeric_limits<value_type>::max)()) {
  48. boost::throw_exception( std::range_error("sobol: polynomial value outside the given value type range") );
  49. }
  50. const unsigned degree = qrng_detail::msb(poly); // integer log2(poly)
  51. // set initial values of m from table
  52. for (unsigned k = 0; k != degree; ++k)
  53. cj[dimension*k + dim] = SobolTables::minit(dim-1, k);
  54. // Calculate remaining elements for this dimension,
  55. // as explained in Bratley+Fox, section 2.
  56. for (unsigned j = degree; j < bit_count; ++j)
  57. {
  58. typename SobolTables::value_type p_i = poly;
  59. const std::size_t bit_offset = dimension*j + dim;
  60. cj[bit_offset] = cj[dimension*(j-degree) + dim];
  61. for (unsigned k = 0; k != degree; ++k, p_i >>= 1)
  62. {
  63. int rem = degree - k;
  64. cj[bit_offset] ^= ((p_i & 1) * cj[dimension*(j-rem) + dim]) << rem;
  65. }
  66. }
  67. }
  68. // Shift columns by appropriate power of 2.
  69. unsigned p = 1u;
  70. for (int j = bit_count-1-1; j >= 0; --j, ++p)
  71. {
  72. const std::size_t bit_offset = dimension * j;
  73. for (std::size_t dim = 0; dim != dimension; ++dim)
  74. cj[bit_offset + dim] <<= p;
  75. }
  76. bits.swap(cj);
  77. }
  78. typename container_type::const_iterator iter_at(std::size_t n) const
  79. {
  80. BOOST_ASSERT(!(n > bits.size()));
  81. return bits.begin() + n;
  82. }
  83. private:
  84. container_type bits;
  85. };
  86. } // namespace qrng_detail
  87. typedef detail::qrng_tables::sobol default_sobol_table;
  88. /** @endcond */
  89. //!Instantiations of class template sobol_engine model a \quasi_random_number_generator.
  90. //!The sobol_engine uses the algorithm described in
  91. //! \blockquote
  92. //![Bratley+Fox, TOMS 14, 88 (1988)]
  93. //!and [Antonov+Saleev, USSR Comput. Maths. Math. Phys. 19, 252 (1980)]
  94. //! \endblockquote
  95. //!
  96. //!\attention sobol_engine skips trivial zeroes at the start of the sequence. For example, the beginning
  97. //!of the 2-dimensional Sobol sequence in @c uniform_01 distribution will look like this:
  98. //!\code{.cpp}
  99. //!0.5, 0.5,
  100. //!0.75, 0.25,
  101. //!0.25, 0.75,
  102. //!0.375, 0.375,
  103. //!0.875, 0.875,
  104. //!...
  105. //!\endcode
  106. //!
  107. //!In the following documentation @c X denotes the concrete class of the template
  108. //!sobol_engine returning objects of type @c UIntType, u and v are the values of @c X.
  109. //!
  110. //!Some member functions may throw exceptions of type @c std::range_error. This
  111. //!happens when the quasi-random domain is exhausted and the generator cannot produce
  112. //!any more values. The length of the low discrepancy sequence is given by \f$L=Dimension \times (2^{w} - 1)\f$.
  113. template<typename UIntType, unsigned w, typename SobolTables = default_sobol_table>
  114. class sobol_engine
  115. : public qrng_detail::gray_coded_qrng<
  116. qrng_detail::sobol_lattice<UIntType, w, SobolTables>
  117. >
  118. {
  119. typedef qrng_detail::sobol_lattice<UIntType, w, SobolTables> lattice_t;
  120. typedef qrng_detail::gray_coded_qrng<lattice_t> base_t;
  121. public:
  122. //!Effects: Constructs the default `s`-dimensional Sobol quasi-random number generator.
  123. //!
  124. //!Throws: bad_alloc, invalid_argument, range_error.
  125. explicit sobol_engine(std::size_t s)
  126. : base_t(s)
  127. {}
  128. // default copy c-tor is fine
  129. #ifdef BOOST_RANDOM_DOXYGEN
  130. //=========================Doxygen needs this!==============================
  131. typedef UIntType result_type;
  132. /** @copydoc boost::random::niederreiter_base2_engine::min() */
  133. static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
  134. { return (base_t::min)(); }
  135. /** @copydoc boost::random::niederreiter_base2_engine::max() */
  136. static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  137. { return (base_t::max)(); }
  138. /** @copydoc boost::random::niederreiter_base2_engine::dimension() */
  139. std::size_t dimension() const { return base_t::dimension(); }
  140. /** @copydoc boost::random::niederreiter_base2_engine::seed() */
  141. void seed()
  142. {
  143. base_t::seed();
  144. }
  145. /** @copydoc boost::random::niederreiter_base2_engine::seed(UIntType) */
  146. void seed(UIntType init)
  147. {
  148. base_t::seed(init);
  149. }
  150. /** @copydoc boost::random::niederreiter_base2_engine::operator()() */
  151. result_type operator()()
  152. {
  153. return base_t::operator()();
  154. }
  155. /** @copydoc boost::random::niederreiter_base2_engine::discard(boost::uintmax_t) */
  156. void discard(boost::uintmax_t z)
  157. {
  158. base_t::discard(z);
  159. }
  160. /** Returns true if the two generators will produce identical sequences of outputs. */
  161. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(sobol_engine, x, y)
  162. { return static_cast<const base_t&>(x) == y; }
  163. /** Returns true if the two generators will produce different sequences of outputs. */
  164. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(sobol_engine)
  165. /** Writes the textual representation of the generator to a @c std::ostream. */
  166. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, sobol_engine, s)
  167. { return os << static_cast<const base_t&>(s); }
  168. /** Reads the textual representation of the generator from a @c std::istream. */
  169. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, sobol_engine, s)
  170. { return is >> static_cast<base_t&>(s); }
  171. #endif // BOOST_RANDOM_DOXYGEN
  172. };
  173. /**
  174. * @attention This specialization of \sobol_engine supports up to 3667 dimensions.
  175. *
  176. * Data on the primitive binary polynomials `a` and the corresponding starting values `m`
  177. * for Sobol sequences in up to 21201 dimensions was taken from
  178. *
  179. * @blockquote
  180. * S. Joe and F. Y. Kuo, Constructing Sobol sequences with better two-dimensional projections,
  181. * SIAM J. Sci. Comput. 30, 2635-2654 (2008).
  182. * @endblockquote
  183. *
  184. * See the original tables up to dimension 21201: https://web.archive.org/web/20170802022909/http://web.maths.unsw.edu.au/~fkuo/sobol/new-joe-kuo-6.21201
  185. *
  186. * For practical reasons the default table uses only the subset of binary polynomials `a` < 2<sup>16</sup>.
  187. *
  188. * However, it is possible to provide your own table to \sobol_engine should the default one be insufficient.
  189. */
  190. typedef sobol_engine<boost::uint_least64_t, 64u, default_sobol_table> sobol;
  191. } // namespace random
  192. } // namespace boost
  193. #endif // BOOST_RANDOM_SOBOL_HPP