File indexing completed on 2025-01-18 09:51:09
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_RANDOM_DETAIL_QRNG_BASE_HPP
0010 #define BOOST_RANDOM_DETAIL_QRNG_BASE_HPP
0011
0012 #include <stdexcept>
0013 #include <vector>
0014 #include <limits>
0015
0016 #include <istream>
0017 #include <ostream>
0018 #include <sstream>
0019
0020 #include <boost/cstdint.hpp>
0021 #include <boost/random/detail/operators.hpp>
0022
0023 #include <boost/throw_exception.hpp>
0024
0025 #include <boost/type_traits/integral_constant.hpp>
0026
0027 #include <boost/random/detail/disable_warnings.hpp>
0028
0029
0030
0031
0032 namespace boost {
0033 namespace random {
0034
0035 namespace qrng_detail {
0036
0037
0038
0039 template <typename Integer>
0040 inline void check_seed_sign(const Integer& v, const boost::true_type)
0041 {
0042 if (v < 0)
0043 {
0044 boost::throw_exception( std::range_error("seed must be a positive integer") );
0045 }
0046 }
0047 template <typename Integer>
0048 inline void check_seed_sign(const Integer&, const boost::false_type) {}
0049
0050 template <typename Integer>
0051 inline void check_seed_sign(const Integer& v)
0052 {
0053 check_seed_sign(v, integral_constant<bool, std::numeric_limits<Integer>::is_signed>());
0054 }
0055
0056
0057 template<typename DerivedT, typename LatticeT, typename SizeT>
0058 class qrng_base
0059 {
0060 public:
0061 typedef SizeT size_type;
0062 typedef typename LatticeT::value_type result_type;
0063
0064 explicit qrng_base(std::size_t dimension)
0065
0066 : lattice(prevent_zero_dimension(dimension))
0067 , quasi_state(dimension)
0068 {
0069 derived().seed();
0070 }
0071
0072
0073
0074
0075
0076
0077
0078
0079 std::size_t dimension() const { return quasi_state.size(); }
0080
0081
0082
0083
0084
0085
0086
0087 result_type operator()()
0088 {
0089 return curr_elem != dimension() ? load_cached(): next_state();
0090 }
0091
0092
0093 template<typename Iter> void generate(Iter first, Iter last)
0094 {
0095 for (; first != last; ++first)
0096 *first = this->operator()();
0097 }
0098
0099
0100
0101
0102
0103 void discard(boost::uintmax_t z)
0104 {
0105 const std::size_t dimension_value = dimension();
0106
0107
0108
0109
0110
0111 boost::uintmax_t vec_n = z / dimension_value;
0112 std::size_t carry = curr_elem + (z % dimension_value);
0113
0114 vec_n += carry / dimension_value;
0115 carry = carry % dimension_value;
0116
0117
0118
0119 const bool corr = (!carry) & static_cast<bool>(vec_n);
0120
0121
0122 discard_vector(vec_n - static_cast<boost::uintmax_t>(corr));
0123
0124 #ifdef BOOST_MSVC
0125 #pragma warning(push)
0126
0127
0128 #pragma warning(disable:4146)
0129 #endif
0130
0131
0132
0133 curr_elem = carry ^ (-static_cast<std::size_t>(corr) & dimension_value);
0134
0135 #ifdef BOOST_MSVC
0136 #pragma warning(pop)
0137 #endif
0138 }
0139
0140
0141 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, qrng_base, s)
0142 {
0143 os << s.dimension() << " " << s.seq_count << " " << s.curr_elem;
0144 return os;
0145 }
0146
0147
0148 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, qrng_base, s)
0149 {
0150 std::size_t dim;
0151 size_type seed;
0152 boost::uintmax_t z;
0153 if (is >> dim >> std::ws >> seed >> std::ws >> z)
0154 {
0155
0156 check_seed_sign(seed);
0157
0158 if (s.dimension() != prevent_zero_dimension(dim))
0159 {
0160 s.lattice.resize(dim);
0161 s.quasi_state.resize(dim);
0162 }
0163
0164 s.derived().seed(seed);
0165 if (z != 0) s.discard(z);
0166 }
0167 return is;
0168 }
0169
0170
0171 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(qrng_base, x, y)
0172 {
0173 const std::size_t dimension_value = x.dimension();
0174
0175
0176
0177
0178
0179
0180 return (dimension_value == y.dimension()) &&
0181
0182 !((x.seq_count < y.seq_count ? y.seq_count - x.seq_count : x.seq_count - y.seq_count)
0183 > static_cast<size_type>(1)) &&
0184
0185
0186
0187 (x.seq_count + (x.curr_elem / dimension_value) == y.seq_count + (y.curr_elem / dimension_value)) &&
0188 (x.curr_elem % dimension_value == y.curr_elem % dimension_value);
0189 }
0190
0191
0192 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(qrng_base)
0193
0194 protected:
0195 typedef std::vector<result_type> state_type;
0196 typedef typename state_type::iterator state_iterator;
0197
0198
0199 size_type curr_seq() const { return seq_count; }
0200
0201 state_iterator state_begin() { return quasi_state.begin(); }
0202 state_iterator state_end() { return quasi_state.end(); }
0203
0204
0205 void reset_seq(size_type seq)
0206 {
0207 seq_count = seq;
0208 curr_elem = 0u;
0209 }
0210
0211 private:
0212 DerivedT& derived() throw()
0213 {
0214 return *static_cast<DerivedT * const>(this);
0215 }
0216
0217
0218 result_type load_cached()
0219 {
0220 return quasi_state[curr_elem++];
0221 }
0222
0223 result_type next_state()
0224 {
0225 size_type new_seq = seq_count;
0226 if (BOOST_LIKELY(++new_seq > seq_count))
0227 {
0228 derived().compute_seq(new_seq);
0229 reset_seq(new_seq);
0230 return load_cached();
0231 }
0232 boost::throw_exception( std::range_error("qrng_base: next_state") );
0233 }
0234
0235
0236
0237 void discard_vector(boost::uintmax_t z)
0238 {
0239 const boost::uintmax_t max_z = (std::numeric_limits<size_type>::max)() - seq_count;
0240
0241
0242 if (max_z < z)
0243 boost::throw_exception( std::range_error("qrng_base: discard_vector") );
0244
0245 std::size_t tmp = curr_elem;
0246 derived().seed(static_cast<size_type>(seq_count + z));
0247 curr_elem = tmp;
0248 }
0249
0250 static std::size_t prevent_zero_dimension(std::size_t dimension)
0251 {
0252 if (dimension == 0)
0253 boost::throw_exception( std::invalid_argument("qrng_base: zero dimension") );
0254 return dimension;
0255 }
0256
0257
0258
0259
0260
0261
0262
0263
0264 private:
0265 std::size_t curr_elem;
0266 size_type seq_count;
0267 protected:
0268 LatticeT lattice;
0269 private:
0270 state_type quasi_state;
0271 };
0272
0273 inline void dimension_assert(const char* generator, std::size_t dim, std::size_t maxdim)
0274 {
0275 if (!dim || dim > maxdim)
0276 {
0277 std::ostringstream os;
0278 os << "The " << generator << " quasi-random number generator only supports dimensions in range [1; "
0279 << maxdim << "], but dimension " << dim << " was supplied.";
0280 boost::throw_exception( std::invalid_argument(os.str()) );
0281 }
0282 }
0283
0284 }
0285
0286 }
0287 }
0288
0289 #include <boost/random/detail/enable_warnings.hpp>
0290
0291 #endif