niederreiter_base2.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /* boost random/nierderreiter_base2.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_NIEDERREITER_BASE2_HPP
  9. #define BOOST_RANDOM_NIEDERREITER_BASE2_HPP
  10. #include <boost/random/detail/niederreiter_base2_table.hpp>
  11. #include <boost/random/detail/gray_coded_qrng.hpp>
  12. #include <boost/dynamic_bitset.hpp>
  13. namespace boost {
  14. namespace random {
  15. /** @cond */
  16. namespace qrng_detail {
  17. namespace nb2 {
  18. // Return the base 2 logarithm for a given bitset v
  19. template <typename DynamicBitset>
  20. inline typename DynamicBitset::size_type
  21. bitset_log2(const DynamicBitset& v)
  22. {
  23. if (v.none())
  24. boost::throw_exception( std::invalid_argument("bitset_log2") );
  25. typename DynamicBitset::size_type hibit = v.size() - 1;
  26. while (!v.test(hibit))
  27. --hibit;
  28. return hibit;
  29. }
  30. // Multiply polynomials over Z_2.
  31. template <typename PolynomialT, typename DynamicBitset>
  32. inline void modulo2_multiply(PolynomialT P, DynamicBitset& v, DynamicBitset& pt)
  33. {
  34. pt.reset(); // pt == 0
  35. for (; P; P >>= 1, v <<= 1)
  36. if (P & 1) pt ^= v;
  37. pt.swap(v);
  38. }
  39. // Calculate the values of the constants V(J,R) as
  40. // described in BFN section 3.3.
  41. //
  42. // pb = polynomial defined in section 2.3 of BFN.
  43. template <typename DynamicBitset>
  44. inline void calculate_v(const DynamicBitset& pb,
  45. typename DynamicBitset::size_type kj,
  46. typename DynamicBitset::size_type pb_degree,
  47. DynamicBitset& v)
  48. {
  49. typedef typename DynamicBitset::size_type size_type;
  50. // Now choose values of V in accordance with
  51. // the conditions in section 3.3.
  52. size_type r = 0;
  53. for ( ; r != kj; ++r)
  54. v.reset(r);
  55. // Quoting from BFN: "Our program currently sets each K_q
  56. // equal to eq. This has the effect of setting all unrestricted
  57. // values of v to 1."
  58. for ( ; r < pb_degree; ++r)
  59. v.set(r);
  60. // Calculate the remaining V's using the recursion of section 2.3,
  61. // remembering that the B's have the opposite sign.
  62. for ( ; r != v.size(); ++r)
  63. {
  64. bool term = false;
  65. for (typename DynamicBitset::size_type k = 0; k < pb_degree; ++k)
  66. {
  67. term ^= pb.test(k) & v[r + k - pb_degree];
  68. }
  69. v[r] = term;
  70. }
  71. }
  72. } // namespace nb2
  73. template<typename UIntType, unsigned w, typename Nb2Table>
  74. struct niederreiter_base2_lattice
  75. {
  76. typedef UIntType value_type;
  77. BOOST_STATIC_ASSERT(w > 0u);
  78. BOOST_STATIC_CONSTANT(unsigned, bit_count = w);
  79. private:
  80. typedef std::vector<value_type> container_type;
  81. public:
  82. explicit niederreiter_base2_lattice(std::size_t dimension)
  83. {
  84. resize(dimension);
  85. }
  86. void resize(std::size_t dimension)
  87. {
  88. typedef boost::dynamic_bitset<> bitset_type;
  89. dimension_assert("Niederreiter base 2", dimension, Nb2Table::max_dimension);
  90. // Initialize the bit array
  91. container_type cj(bit_count * dimension);
  92. // Reserve temporary space for lattice computation
  93. bitset_type v, pb, tmp;
  94. // Compute Niedderreiter base 2 lattice
  95. for (std::size_t dim = 0; dim != dimension; ++dim)
  96. {
  97. const typename Nb2Table::value_type poly = Nb2Table::polynomial(dim);
  98. if (poly > (std::numeric_limits<value_type>::max)()) {
  99. boost::throw_exception( std::range_error("niederreiter_base2: polynomial value outside the given value type range") );
  100. }
  101. const unsigned degree = qrng_detail::msb(poly); // integer log2(poly)
  102. const unsigned space_required = degree * ((bit_count / degree) + 1); // ~ degree + bit_count
  103. v.resize(degree + bit_count - 1);
  104. // For each dimension, we need to calculate powers of an
  105. // appropriate irreducible polynomial, see Niederreiter
  106. // page 65, just below equation (19).
  107. // Copy the appropriate irreducible polynomial into PX,
  108. // and its degree into E. Set polynomial B = PX ** 0 = 1.
  109. // M is the degree of B. Subsequently B will hold higher
  110. // powers of PX.
  111. pb.resize(space_required); tmp.resize(space_required);
  112. typename bitset_type::size_type kj, pb_degree = 0;
  113. pb.reset(); // pb == 0
  114. pb.set(pb_degree); // set the proper bit for the pb_degree
  115. value_type j = high_bit_mask_t<bit_count - 1>::high_bit;
  116. do
  117. {
  118. // Now choose a value of Kj as defined in section 3.3.
  119. // We must have 0 <= Kj < E*J = M.
  120. // The limit condition on Kj does not seem to be very relevant
  121. // in this program.
  122. kj = pb_degree;
  123. // Now multiply B by PX so B becomes PX**J.
  124. // In section 2.3, the values of Bi are defined with a minus sign :
  125. // don't forget this if you use them later!
  126. nb2::modulo2_multiply(poly, pb, tmp);
  127. pb_degree += degree;
  128. if (pb_degree >= pb.size()) {
  129. // Note that it is quite possible for kj to become bigger than
  130. // the new computed value of pb_degree.
  131. pb_degree = nb2::bitset_log2(pb);
  132. }
  133. // If U = 0, we need to set B to the next power of PX
  134. // and recalculate V.
  135. nb2::calculate_v(pb, kj, pb_degree, v);
  136. // Niederreiter (page 56, after equation (7), defines two
  137. // variables Q and U. We do not need Q explicitly, but we
  138. // do need U.
  139. // Advance Niederreiter's state variables.
  140. for (unsigned u = 0; j && u != degree; ++u, j >>= 1)
  141. {
  142. // Now C is obtained from V. Niederreiter
  143. // obtains A from V (page 65, near the bottom), and then gets
  144. // C from A (page 56, equation (7)). However this can be done
  145. // in one step. Here CI(J,R) corresponds to
  146. // Niederreiter's C(I,J,R), whose values we pack into array
  147. // CJ so that CJ(I,R) holds all the values of C(I,J,R) for J from 1 to NBITS.
  148. for (unsigned r = 0; r != bit_count; ++r) {
  149. value_type& num = cj[dimension * r + dim];
  150. // set the jth bit in num
  151. num = (num & ~j) | (-v[r + u] & j);
  152. }
  153. }
  154. } while (j != 0);
  155. }
  156. bits.swap(cj);
  157. }
  158. typename container_type::const_iterator iter_at(std::size_t n) const
  159. {
  160. BOOST_ASSERT(!(n > bits.size()));
  161. return bits.begin() + n;
  162. }
  163. private:
  164. container_type bits;
  165. };
  166. } // namespace qrng_detail
  167. typedef detail::qrng_tables::niederreiter_base2 default_niederreiter_base2_table;
  168. /** @endcond */
  169. //!Instantiations of class template niederreiter_base2_engine model a \quasi_random_number_generator.
  170. //!The niederreiter_base2_engine uses the algorithm described in
  171. //! \blockquote
  172. //!Bratley, Fox, Niederreiter, ACM Trans. Model. Comp. Sim. 2, 195 (1992).
  173. //! \endblockquote
  174. //!
  175. //!\attention niederreiter_base2_engine skips trivial zeroes at the start of the sequence. For example,
  176. //!the beginning of the 2-dimensional Niederreiter base 2 sequence in @c uniform_01 distribution will look
  177. //!like this:
  178. //!\code{.cpp}
  179. //!0.5, 0.5,
  180. //!0.75, 0.25,
  181. //!0.25, 0.75,
  182. //!0.375, 0.375,
  183. //!0.875, 0.875,
  184. //!...
  185. //!\endcode
  186. //!
  187. //!In the following documentation @c X denotes the concrete class of the template
  188. //!niederreiter_base2_engine returning objects of type @c UIntType, u and v are the values of @c X.
  189. //!
  190. //!Some member functions may throw exceptions of type std::range_error. This
  191. //!happens when the quasi-random domain is exhausted and the generator cannot produce
  192. //!any more values. The length of the low discrepancy sequence is given by
  193. //! \f$L=Dimension \times (2^{w} - 1)\f$.
  194. template<typename UIntType, unsigned w, typename Nb2Table = default_niederreiter_base2_table>
  195. class niederreiter_base2_engine
  196. : public qrng_detail::gray_coded_qrng<
  197. qrng_detail::niederreiter_base2_lattice<UIntType, w, Nb2Table>
  198. >
  199. {
  200. typedef qrng_detail::niederreiter_base2_lattice<UIntType, w, Nb2Table> lattice_t;
  201. typedef qrng_detail::gray_coded_qrng<lattice_t> base_t;
  202. public:
  203. //!Effects: Constructs the default `s`-dimensional Niederreiter base 2 quasi-random number generator.
  204. //!
  205. //!Throws: bad_alloc, invalid_argument, range_error.
  206. explicit niederreiter_base2_engine(std::size_t s)
  207. : base_t(s) // initialize lattice here
  208. {}
  209. #ifdef BOOST_RANDOM_DOXYGEN
  210. //=========================Doxygen needs this!==============================
  211. typedef UIntType result_type;
  212. //!Returns: Tight lower bound on the set of values returned by operator().
  213. //!
  214. //!Throws: nothing.
  215. static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
  216. { return (base_t::min)(); }
  217. //!Returns: Tight upper bound on the set of values returned by operator().
  218. //!
  219. //!Throws: nothing.
  220. static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
  221. { return (base_t::max)(); }
  222. //!Returns: The dimension of of the quasi-random domain.
  223. //!
  224. //!Throws: nothing.
  225. std::size_t dimension() const { return base_t::dimension(); }
  226. //!Effects: Resets the quasi-random number generator state to
  227. //!the one given by the default construction. Equivalent to u.seed(0).
  228. //!
  229. //!\brief Throws: nothing.
  230. void seed()
  231. {
  232. base_t::seed();
  233. }
  234. //!Effects: Effectively sets the quasi-random number generator state to the `init`-th
  235. //!vector in the `s`-dimensional quasi-random domain, where `s` == X::dimension().
  236. //!\code
  237. //!X u, v;
  238. //!for(int i = 0; i < N; ++i)
  239. //! for( std::size_t j = 0; j < u.dimension(); ++j )
  240. //! u();
  241. //!v.seed(N);
  242. //!assert(u() == v());
  243. //!\endcode
  244. //!
  245. //!\brief Throws: range_error.
  246. void seed(UIntType init)
  247. {
  248. base_t::seed(init);
  249. }
  250. //!Returns: Returns a successive element of an `s`-dimensional
  251. //!(s = X::dimension()) vector at each invocation. When all elements are
  252. //!exhausted, X::operator() begins anew with the starting element of a
  253. //!subsequent `s`-dimensional vector.
  254. //!
  255. //!Throws: range_error.
  256. result_type operator()()
  257. {
  258. return base_t::operator()();
  259. }
  260. //!Effects: Advances *this state as if `z` consecutive
  261. //!X::operator() invocations were executed.
  262. //!\code
  263. //!X u = v;
  264. //!for(int i = 0; i < N; ++i)
  265. //! u();
  266. //!v.discard(N);
  267. //!assert(u() == v());
  268. //!\endcode
  269. //!
  270. //!Throws: range_error.
  271. void discard(boost::uintmax_t z)
  272. {
  273. base_t::discard(z);
  274. }
  275. //!Returns true if the two generators will produce identical sequences of outputs.
  276. BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(niederreiter_base2_engine, x, y)
  277. { return static_cast<const base_t&>(x) == y; }
  278. //!Returns true if the two generators will produce different sequences of outputs.
  279. BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(niederreiter_base2_engine)
  280. //!Writes the textual representation of the generator to a @c std::ostream.
  281. BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, niederreiter_base2_engine, s)
  282. { return os << static_cast<const base_t&>(s); }
  283. //!Reads the textual representation of the generator from a @c std::istream.
  284. BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, niederreiter_base2_engine, s)
  285. { return is >> static_cast<base_t&>(s); }
  286. #endif // BOOST_RANDOM_DOXYGEN
  287. };
  288. /**
  289. * @attention This specialization of \niederreiter_base2_engine supports up to 4720 dimensions.
  290. *
  291. * Binary irreducible polynomials (primes in the ring `GF(2)[X]`, evaluated at `X=2`) were generated
  292. * while condition `max(prime)` < 2<sup>16</sup> was satisfied.
  293. *
  294. * There are exactly 4720 such primes, which yields a Niederreiter base 2 table for 4720 dimensions.
  295. *
  296. * However, it is possible to provide your own table to \niederreiter_base2_engine should the default one be insufficient.
  297. */
  298. typedef niederreiter_base2_engine<boost::uint_least64_t, 64u, default_niederreiter_base2_table> niederreiter_base2;
  299. } // namespace random
  300. } // namespace boost
  301. #endif // BOOST_RANDOM_NIEDERREITER_BASE2_HPP