Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:51:12

0001 /* boost random/nierderreiter_base2.hpp header file
0002  *
0003  * Copyright Justinas Vygintas Daugmaudis 2010-2018
0004  * Distributed under the Boost Software License, Version 1.0. (See
0005  * accompanying file LICENSE_1_0.txt or copy at
0006  * http://www.boost.org/LICENSE_1_0.txt)
0007  */
0008 
0009 #ifndef BOOST_RANDOM_NIEDERREITER_BASE2_HPP
0010 #define BOOST_RANDOM_NIEDERREITER_BASE2_HPP
0011 
0012 #include <boost/random/detail/niederreiter_base2_table.hpp>
0013 #include <boost/random/detail/gray_coded_qrng.hpp>
0014 
0015 #include <boost/dynamic_bitset.hpp>
0016 
0017 namespace boost {
0018 namespace random {
0019 
0020 /** @cond */
0021 namespace qrng_detail {
0022 namespace nb2 {
0023 
0024 // Return the base 2 logarithm for a given bitset v
0025 template <typename DynamicBitset>
0026 inline typename DynamicBitset::size_type
0027 bitset_log2(const DynamicBitset& v)
0028 {
0029   if (v.none())
0030     boost::throw_exception( std::invalid_argument("bitset_log2") );
0031 
0032   typename DynamicBitset::size_type hibit = v.size() - 1;
0033   while (!v.test(hibit))
0034     --hibit;
0035   return hibit;
0036 }
0037 
0038 
0039 // Multiply polynomials over Z_2.
0040 template <typename PolynomialT, typename DynamicBitset>
0041 inline void modulo2_multiply(PolynomialT P, DynamicBitset& v, DynamicBitset& pt)
0042 {
0043   pt.reset(); // pt == 0
0044   for (; P; P >>= 1, v <<= 1)
0045     if (P & 1) pt ^= v;
0046   pt.swap(v);
0047 }
0048 
0049 
0050 // Calculate the values of the constants V(J,R) as
0051 // described in BFN section 3.3.
0052 //
0053 // pb = polynomial defined in section 2.3 of BFN.
0054 template <typename DynamicBitset>
0055 inline void calculate_v(const DynamicBitset& pb,
0056   typename DynamicBitset::size_type kj,
0057   typename DynamicBitset::size_type pb_degree,
0058   DynamicBitset& v)
0059 {
0060   typedef typename DynamicBitset::size_type size_type;
0061 
0062   // Now choose values of V in accordance with
0063   // the conditions in section 3.3.
0064   size_type r = 0;
0065   for ( ; r != kj; ++r)
0066     v.reset(r);
0067 
0068   // Quoting from BFN: "Our program currently sets each K_q
0069   // equal to eq. This has the effect of setting all unrestricted
0070   // values of v to 1."
0071   for ( ; r < pb_degree; ++r)
0072     v.set(r);
0073 
0074   // Calculate the remaining V's using the recursion of section 2.3,
0075   // remembering that the B's have the opposite sign.
0076   for ( ; r != v.size(); ++r)
0077   {
0078     bool term = false;
0079     for (typename DynamicBitset::size_type k = 0; k < pb_degree; ++k)
0080     {
0081       term ^= pb.test(k) & v[r + k - pb_degree];
0082     }
0083     v[r] = term;
0084   }
0085 }
0086 
0087 } // namespace nb2
0088 
0089 template<typename UIntType, unsigned w, typename Nb2Table>
0090 struct niederreiter_base2_lattice
0091 {
0092   typedef UIntType value_type;
0093 
0094   BOOST_STATIC_ASSERT(w > 0u);
0095   BOOST_STATIC_CONSTANT(unsigned, bit_count = w);
0096 
0097 private:
0098   typedef std::vector<value_type> container_type;
0099 
0100 public:
0101   explicit niederreiter_base2_lattice(std::size_t dimension)
0102   {
0103     resize(dimension);
0104   }
0105 
0106   void resize(std::size_t dimension)
0107   {
0108     typedef boost::dynamic_bitset<> bitset_type;
0109 
0110     dimension_assert("Niederreiter base 2", dimension, Nb2Table::max_dimension);
0111 
0112     // Initialize the bit array
0113     container_type cj(bit_count * dimension);
0114 
0115     // Reserve temporary space for lattice computation
0116     bitset_type v, pb, tmp;
0117 
0118     // Compute Niedderreiter base 2 lattice
0119     for (std::size_t dim = 0; dim != dimension; ++dim)
0120     {
0121       const typename Nb2Table::value_type poly = Nb2Table::polynomial(dim);
0122       if (poly > (std::numeric_limits<value_type>::max)()) {
0123         boost::throw_exception( std::range_error("niederreiter_base2: polynomial value outside the given value type range") );
0124       }
0125 
0126       const unsigned degree = qrng_detail::msb(poly); // integer log2(poly)
0127       const unsigned space_required = degree * ((bit_count / degree) + 1); // ~ degree + bit_count
0128 
0129       v.resize(degree + bit_count - 1);
0130 
0131       // For each dimension, we need to calculate powers of an
0132       // appropriate irreducible polynomial, see Niederreiter
0133       // page 65, just below equation (19).
0134       // Copy the appropriate irreducible polynomial into PX,
0135       // and its degree into E. Set polynomial B = PX ** 0 = 1.
0136       // M is the degree of B. Subsequently B will hold higher
0137       // powers of PX.
0138       pb.resize(space_required); tmp.resize(space_required);
0139 
0140       typename bitset_type::size_type kj, pb_degree = 0;
0141       pb.reset(); // pb == 0
0142       pb.set(pb_degree); // set the proper bit for the pb_degree
0143 
0144       value_type j = high_bit_mask_t<bit_count - 1>::high_bit;
0145       do
0146       {
0147         // Now choose a value of Kj as defined in section 3.3.
0148         // We must have 0 <= Kj < E*J = M.
0149         // The limit condition on Kj does not seem to be very relevant
0150         // in this program.
0151         kj = pb_degree;
0152 
0153         // Now multiply B by PX so B becomes PX**J.
0154         // In section 2.3, the values of Bi are defined with a minus sign :
0155         // don't forget this if you use them later!
0156         nb2::modulo2_multiply(poly, pb, tmp);
0157         pb_degree += degree;
0158         if (pb_degree >= pb.size()) {
0159           // Note that it is quite possible for kj to become bigger than
0160           // the new computed value of pb_degree.
0161           pb_degree = nb2::bitset_log2(pb);
0162         }
0163 
0164         // If U = 0, we need to set B to the next power of PX
0165         // and recalculate V.
0166         nb2::calculate_v(pb, kj, pb_degree, v);
0167 
0168         // Niederreiter (page 56, after equation (7), defines two
0169         // variables Q and U.  We do not need Q explicitly, but we
0170         // do need U.
0171 
0172         // Advance Niederreiter's state variables.
0173         for (unsigned u = 0; j && u != degree; ++u, j >>= 1)
0174         {
0175           // Now C is obtained from V. Niederreiter
0176           // obtains A from V (page 65, near the bottom), and then gets
0177           // C from A (page 56, equation (7)).  However this can be done
0178           // in one step.  Here CI(J,R) corresponds to
0179           // Niederreiter's C(I,J,R), whose values we pack into array
0180           // CJ so that CJ(I,R) holds all the values of C(I,J,R) for J from 1 to NBITS.
0181           for (unsigned r = 0; r != bit_count; ++r) {
0182             value_type& num = cj[dimension * r + dim];
0183             // set the jth bit in num
0184             num = (num & ~j) | (-v[r + u] & j);
0185           }
0186         }
0187       } while (j != 0);
0188     }
0189 
0190     bits.swap(cj);
0191   }
0192 
0193   typename container_type::const_iterator iter_at(std::size_t n) const
0194   {
0195     BOOST_ASSERT(!(n > bits.size()));
0196     return bits.begin() + n;
0197   }
0198 
0199 private:
0200   container_type bits;
0201 };
0202 
0203 } // namespace qrng_detail
0204 
0205 typedef detail::qrng_tables::niederreiter_base2 default_niederreiter_base2_table;
0206 
0207 /** @endcond */
0208 
0209 //!Instantiations of class template niederreiter_base2_engine model a \quasi_random_number_generator.
0210 //!The niederreiter_base2_engine uses the algorithm described in
0211 //! \blockquote
0212 //!Bratley, Fox, Niederreiter, ACM Trans. Model. Comp. Sim. 2, 195 (1992).
0213 //! \endblockquote
0214 //!
0215 //!\attention niederreiter_base2_engine skips trivial zeroes at the start of the sequence. For example,
0216 //!the beginning of the 2-dimensional Niederreiter base 2 sequence in @c uniform_01 distribution will look
0217 //!like this:
0218 //!\code{.cpp}
0219 //!0.5, 0.5,
0220 //!0.75, 0.25,
0221 //!0.25, 0.75,
0222 //!0.375, 0.375,
0223 //!0.875, 0.875,
0224 //!...
0225 //!\endcode
0226 //!
0227 //!In the following documentation @c X denotes the concrete class of the template
0228 //!niederreiter_base2_engine returning objects of type @c UIntType, u and v are the values of @c X.
0229 //!
0230 //!Some member functions may throw exceptions of type std::range_error. This
0231 //!happens when the quasi-random domain is exhausted and the generator cannot produce
0232 //!any more values. The length of the low discrepancy sequence is given by
0233 //! \f$L=Dimension \times (2^{w} - 1)\f$.
0234 template<typename UIntType, unsigned w, typename Nb2Table = default_niederreiter_base2_table>
0235 class niederreiter_base2_engine
0236   : public qrng_detail::gray_coded_qrng<
0237       qrng_detail::niederreiter_base2_lattice<UIntType, w, Nb2Table>
0238     >
0239 {
0240   typedef qrng_detail::niederreiter_base2_lattice<UIntType, w, Nb2Table> lattice_t;
0241   typedef qrng_detail::gray_coded_qrng<lattice_t> base_t;
0242 
0243 public:
0244   //!Effects: Constructs the default `s`-dimensional Niederreiter base 2 quasi-random number generator.
0245   //!
0246   //!Throws: bad_alloc, invalid_argument, range_error.
0247   explicit niederreiter_base2_engine(std::size_t s)
0248     : base_t(s) // initialize lattice here
0249   {}
0250 
0251 #ifdef BOOST_RANDOM_DOXYGEN
0252   //=========================Doxygen needs this!==============================
0253   typedef UIntType result_type;
0254 
0255   //!Returns: Tight lower bound on the set of values returned by operator().
0256   //!
0257   //!Throws: nothing.
0258   static BOOST_CONSTEXPR result_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
0259   { return (base_t::min)(); }
0260 
0261   //!Returns: Tight upper bound on the set of values returned by operator().
0262   //!
0263   //!Throws: nothing.
0264   static BOOST_CONSTEXPR result_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
0265   { return (base_t::max)(); }
0266 
0267   //!Returns: The dimension of of the quasi-random domain.
0268   //!
0269   //!Throws: nothing.
0270   std::size_t dimension() const { return base_t::dimension(); }
0271 
0272   //!Effects: Resets the quasi-random number generator state to
0273   //!the one given by the default construction. Equivalent to u.seed(0).
0274   //!
0275   //!\brief Throws: nothing.
0276   void seed()
0277   {
0278     base_t::seed();
0279   }
0280 
0281   //!Effects: Effectively sets the quasi-random number generator state to the `init`-th
0282   //!vector in the `s`-dimensional quasi-random domain, where `s` == X::dimension().
0283   //!\code
0284   //!X u, v;
0285   //!for(int i = 0; i < N; ++i)
0286   //!    for( std::size_t j = 0; j < u.dimension(); ++j )
0287   //!        u();
0288   //!v.seed(N);
0289   //!assert(u() == v());
0290   //!\endcode
0291   //!
0292   //!\brief Throws: range_error.
0293   void seed(UIntType init)
0294   {
0295     base_t::seed(init);
0296   }
0297 
0298   //!Returns: Returns a successive element of an `s`-dimensional
0299   //!(s = X::dimension()) vector at each invocation. When all elements are
0300   //!exhausted, X::operator() begins anew with the starting element of a
0301   //!subsequent `s`-dimensional vector.
0302   //!
0303   //!Throws: range_error.
0304   result_type operator()()
0305   {
0306     return base_t::operator()();
0307   }
0308 
0309   //!Effects: Advances *this state as if `z` consecutive
0310   //!X::operator() invocations were executed.
0311   //!\code
0312   //!X u = v;
0313   //!for(int i = 0; i < N; ++i)
0314   //!    u();
0315   //!v.discard(N);
0316   //!assert(u() == v());
0317   //!\endcode
0318   //!
0319   //!Throws: range_error.
0320   void discard(boost::uintmax_t z)
0321   {
0322     base_t::discard(z);
0323   }
0324 
0325   //!Returns true if the two generators will produce identical sequences of outputs.
0326   BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(niederreiter_base2_engine, x, y)
0327   { return static_cast<const base_t&>(x) == y; }
0328 
0329   //!Returns true if the two generators will produce different sequences of outputs.
0330   BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(niederreiter_base2_engine)
0331 
0332   //!Writes the textual representation of the generator to a @c std::ostream.
0333   BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, niederreiter_base2_engine, s)
0334   { return os << static_cast<const base_t&>(s); }
0335 
0336   //!Reads the textual representation of the generator from a @c std::istream.
0337   BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, niederreiter_base2_engine, s)
0338   { return is >> static_cast<base_t&>(s); }
0339 
0340 #endif // BOOST_RANDOM_DOXYGEN
0341 };
0342 
0343 
0344 /**
0345  * @attention This specialization of \niederreiter_base2_engine supports up to 4720 dimensions.
0346  *
0347  * Binary irreducible polynomials (primes in the ring `GF(2)[X]`, evaluated at `X=2`) were generated
0348  * while condition `max(prime)` < 2<sup>16</sup> was satisfied.
0349  *
0350  * There are exactly 4720 such primes, which yields a Niederreiter base 2 table for 4720 dimensions.
0351  *
0352  * However, it is possible to provide your own table to \niederreiter_base2_engine should the default one be insufficient.
0353  */
0354 typedef niederreiter_base2_engine<boost::uint_least64_t, 64u, default_niederreiter_base2_table> niederreiter_base2;
0355 
0356 } // namespace random
0357 
0358 } // namespace boost
0359 
0360 #endif // BOOST_RANDOM_NIEDERREITER_BASE2_HPP