annotate DEPENDENCIES/generic/include/boost/random/discrete_distribution.hpp @ 125:34e428693f5d vext

Vext -> Repoint
author Chris Cannam
date Thu, 14 Jun 2018 11:15:39 +0100
parents c530137014c0
children
rev   line source
Chris@16 1 /* boost random/discrete_distribution.hpp header file
Chris@16 2 *
Chris@16 3 * Copyright Steven Watanabe 2009-2011
Chris@16 4 * Distributed under the Boost Software License, Version 1.0. (See
Chris@16 5 * accompanying file LICENSE_1_0.txt or copy at
Chris@16 6 * http://www.boost.org/LICENSE_1_0.txt)
Chris@16 7 *
Chris@16 8 * See http://www.boost.org for most recent version including documentation.
Chris@16 9 *
Chris@101 10 * $Id$
Chris@16 11 */
Chris@16 12
Chris@16 13 #ifndef BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
Chris@16 14 #define BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
Chris@16 15
Chris@16 16 #include <vector>
Chris@16 17 #include <limits>
Chris@16 18 #include <numeric>
Chris@16 19 #include <utility>
Chris@16 20 #include <iterator>
Chris@16 21 #include <boost/assert.hpp>
Chris@16 22 #include <boost/random/uniform_01.hpp>
Chris@101 23 #include <boost/random/uniform_int_distribution.hpp>
Chris@16 24 #include <boost/random/detail/config.hpp>
Chris@16 25 #include <boost/random/detail/operators.hpp>
Chris@16 26 #include <boost/random/detail/vector_io.hpp>
Chris@16 27
Chris@16 28 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
Chris@16 29 #include <initializer_list>
Chris@16 30 #endif
Chris@16 31
Chris@16 32 #include <boost/range/begin.hpp>
Chris@16 33 #include <boost/range/end.hpp>
Chris@16 34
Chris@16 35 #include <boost/random/detail/disable_warnings.hpp>
Chris@16 36
Chris@16 37 namespace boost {
Chris@16 38 namespace random {
Chris@101 39 namespace detail {
Chris@101 40
Chris@101 41 template<class IntType, class WeightType>
Chris@101 42 struct integer_alias_table {
Chris@101 43 WeightType get_weight(IntType bin) const {
Chris@101 44 WeightType result = _average;
Chris@101 45 if(bin < _excess) ++result;
Chris@101 46 return result;
Chris@101 47 }
Chris@101 48 template<class Iter>
Chris@101 49 WeightType init_average(Iter begin, Iter end) {
Chris@101 50 WeightType weight_average = 0;
Chris@101 51 IntType excess = 0;
Chris@101 52 IntType n = 0;
Chris@101 53 // weight_average * n + excess == current partial sum
Chris@101 54 // This is a bit messy, but it's guaranteed not to overflow
Chris@101 55 for(Iter iter = begin; iter != end; ++iter) {
Chris@101 56 ++n;
Chris@101 57 if(*iter < weight_average) {
Chris@101 58 WeightType diff = weight_average - *iter;
Chris@101 59 weight_average -= diff / n;
Chris@101 60 if(diff % n > excess) {
Chris@101 61 --weight_average;
Chris@101 62 excess += n - diff % n;
Chris@101 63 } else {
Chris@101 64 excess -= diff % n;
Chris@101 65 }
Chris@101 66 } else {
Chris@101 67 WeightType diff = *iter - weight_average;
Chris@101 68 weight_average += diff / n;
Chris@101 69 if(diff % n < n - excess) {
Chris@101 70 excess += diff % n;
Chris@101 71 } else {
Chris@101 72 ++weight_average;
Chris@101 73 excess -= n - diff % n;
Chris@101 74 }
Chris@101 75 }
Chris@101 76 }
Chris@101 77 _alias_table.resize(static_cast<std::size_t>(n));
Chris@101 78 _average = weight_average;
Chris@101 79 _excess = excess;
Chris@101 80 return weight_average;
Chris@101 81 }
Chris@101 82 void init_empty()
Chris@101 83 {
Chris@101 84 _alias_table.clear();
Chris@101 85 _alias_table.push_back(std::make_pair(static_cast<WeightType>(1),
Chris@101 86 static_cast<IntType>(0)));
Chris@101 87 _average = static_cast<WeightType>(1);
Chris@101 88 _excess = static_cast<IntType>(0);
Chris@101 89 }
Chris@101 90 bool operator==(const integer_alias_table& other) const
Chris@101 91 {
Chris@101 92 return _alias_table == other._alias_table &&
Chris@101 93 _average == other._average && _excess == other._excess;
Chris@101 94 }
Chris@101 95 static WeightType normalize(WeightType val, WeightType average)
Chris@101 96 {
Chris@101 97 return val;
Chris@101 98 }
Chris@101 99 static void normalize(std::vector<WeightType>&) {}
Chris@101 100 template<class URNG>
Chris@101 101 WeightType test(URNG &urng) const
Chris@101 102 {
Chris@101 103 return uniform_int_distribution<WeightType>(0, _average)(urng);
Chris@101 104 }
Chris@101 105 bool accept(IntType result, WeightType val) const
Chris@101 106 {
Chris@101 107 return result < _excess || val < _average;
Chris@101 108 }
Chris@101 109 static WeightType try_get_sum(const std::vector<WeightType>& weights)
Chris@101 110 {
Chris@101 111 WeightType result = static_cast<WeightType>(0);
Chris@101 112 for(typename std::vector<WeightType>::const_iterator
Chris@101 113 iter = weights.begin(), end = weights.end();
Chris@101 114 iter != end; ++iter)
Chris@101 115 {
Chris@101 116 if((std::numeric_limits<WeightType>::max)() - result > *iter) {
Chris@101 117 return static_cast<WeightType>(0);
Chris@101 118 }
Chris@101 119 result += *iter;
Chris@101 120 }
Chris@101 121 return result;
Chris@101 122 }
Chris@101 123 template<class URNG>
Chris@101 124 static WeightType generate_in_range(URNG &urng, WeightType max)
Chris@101 125 {
Chris@101 126 return uniform_int_distribution<WeightType>(
Chris@101 127 static_cast<WeightType>(0), max-1)(urng);
Chris@101 128 }
Chris@101 129 typedef std::vector<std::pair<WeightType, IntType> > alias_table_t;
Chris@101 130 alias_table_t _alias_table;
Chris@101 131 WeightType _average;
Chris@101 132 IntType _excess;
Chris@101 133 };
Chris@101 134
Chris@101 135 template<class IntType, class WeightType>
Chris@101 136 struct real_alias_table {
Chris@101 137 WeightType get_weight(IntType) const
Chris@101 138 {
Chris@101 139 return WeightType(1.0);
Chris@101 140 }
Chris@101 141 template<class Iter>
Chris@101 142 WeightType init_average(Iter first, Iter last)
Chris@101 143 {
Chris@101 144 std::size_t size = std::distance(first, last);
Chris@101 145 WeightType weight_sum =
Chris@101 146 std::accumulate(first, last, static_cast<WeightType>(0));
Chris@101 147 _alias_table.resize(size);
Chris@101 148 return weight_sum / size;
Chris@101 149 }
Chris@101 150 void init_empty()
Chris@101 151 {
Chris@101 152 _alias_table.clear();
Chris@101 153 _alias_table.push_back(std::make_pair(static_cast<WeightType>(1),
Chris@101 154 static_cast<IntType>(0)));
Chris@101 155 }
Chris@101 156 bool operator==(const real_alias_table& other) const
Chris@101 157 {
Chris@101 158 return _alias_table == other._alias_table;
Chris@101 159 }
Chris@101 160 static WeightType normalize(WeightType val, WeightType average)
Chris@101 161 {
Chris@101 162 return val / average;
Chris@101 163 }
Chris@101 164 static void normalize(std::vector<WeightType>& weights)
Chris@101 165 {
Chris@101 166 WeightType sum =
Chris@101 167 std::accumulate(weights.begin(), weights.end(),
Chris@101 168 static_cast<WeightType>(0));
Chris@101 169 for(typename std::vector<WeightType>::iterator
Chris@101 170 iter = weights.begin(),
Chris@101 171 end = weights.end();
Chris@101 172 iter != end; ++iter)
Chris@101 173 {
Chris@101 174 *iter /= sum;
Chris@101 175 }
Chris@101 176 }
Chris@101 177 template<class URNG>
Chris@101 178 WeightType test(URNG &urng) const
Chris@101 179 {
Chris@101 180 return uniform_01<WeightType>()(urng);
Chris@101 181 }
Chris@101 182 bool accept(IntType, WeightType) const
Chris@101 183 {
Chris@101 184 return true;
Chris@101 185 }
Chris@101 186 static WeightType try_get_sum(const std::vector<WeightType>& weights)
Chris@101 187 {
Chris@101 188 return static_cast<WeightType>(1);
Chris@101 189 }
Chris@101 190 template<class URNG>
Chris@101 191 static WeightType generate_in_range(URNG &urng, WeightType)
Chris@101 192 {
Chris@101 193 return uniform_01<WeightType>()(urng);
Chris@101 194 }
Chris@101 195 typedef std::vector<std::pair<WeightType, IntType> > alias_table_t;
Chris@101 196 alias_table_t _alias_table;
Chris@101 197 };
Chris@101 198
Chris@101 199 template<bool IsIntegral>
Chris@101 200 struct select_alias_table;
Chris@101 201
Chris@101 202 template<>
Chris@101 203 struct select_alias_table<true> {
Chris@101 204 template<class IntType, class WeightType>
Chris@101 205 struct apply {
Chris@101 206 typedef integer_alias_table<IntType, WeightType> type;
Chris@101 207 };
Chris@101 208 };
Chris@101 209
Chris@101 210 template<>
Chris@101 211 struct select_alias_table<false> {
Chris@101 212 template<class IntType, class WeightType>
Chris@101 213 struct apply {
Chris@101 214 typedef real_alias_table<IntType, WeightType> type;
Chris@101 215 };
Chris@101 216 };
Chris@101 217
Chris@101 218 }
Chris@16 219
Chris@16 220 /**
Chris@16 221 * The class @c discrete_distribution models a \random_distribution.
Chris@16 222 * It produces integers in the range [0, n) with the probability
Chris@16 223 * of producing each value is specified by the parameters of the
Chris@16 224 * distribution.
Chris@16 225 */
Chris@16 226 template<class IntType = int, class WeightType = double>
Chris@16 227 class discrete_distribution {
Chris@16 228 public:
Chris@16 229 typedef WeightType input_type;
Chris@16 230 typedef IntType result_type;
Chris@16 231
Chris@16 232 class param_type {
Chris@16 233 public:
Chris@16 234
Chris@16 235 typedef discrete_distribution distribution_type;
Chris@16 236
Chris@16 237 /**
Chris@16 238 * Constructs a @c param_type object, representing a distribution
Chris@16 239 * with \f$p(0) = 1\f$ and \f$p(k|k>0) = 0\f$.
Chris@16 240 */
Chris@16 241 param_type() : _probabilities(1, static_cast<WeightType>(1)) {}
Chris@16 242 /**
Chris@16 243 * If @c first == @c last, equivalent to the default constructor.
Chris@16 244 * Otherwise, the values of the range represent weights for the
Chris@16 245 * possible values of the distribution.
Chris@16 246 */
Chris@16 247 template<class Iter>
Chris@16 248 param_type(Iter first, Iter last) : _probabilities(first, last)
Chris@16 249 {
Chris@16 250 normalize();
Chris@16 251 }
Chris@16 252 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
Chris@16 253 /**
Chris@16 254 * If wl.size() == 0, equivalent to the default constructor.
Chris@16 255 * Otherwise, the values of the @c initializer_list represent
Chris@16 256 * weights for the possible values of the distribution.
Chris@16 257 */
Chris@16 258 param_type(const std::initializer_list<WeightType>& wl)
Chris@16 259 : _probabilities(wl)
Chris@16 260 {
Chris@16 261 normalize();
Chris@16 262 }
Chris@16 263 #endif
Chris@16 264 /**
Chris@16 265 * If the range is empty, equivalent to the default constructor.
Chris@16 266 * Otherwise, the elements of the range represent
Chris@16 267 * weights for the possible values of the distribution.
Chris@16 268 */
Chris@16 269 template<class Range>
Chris@16 270 explicit param_type(const Range& range)
Chris@16 271 : _probabilities(boost::begin(range), boost::end(range))
Chris@16 272 {
Chris@16 273 normalize();
Chris@16 274 }
Chris@16 275
Chris@16 276 /**
Chris@16 277 * If nw is zero, equivalent to the default constructor.
Chris@16 278 * Otherwise, the range of the distribution is [0, nw),
Chris@16 279 * and the weights are found by calling fw with values
Chris@16 280 * evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and
Chris@16 281 * \f$\mbox{xmax} - \delta/2\f$, where
Chris@16 282 * \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$.
Chris@16 283 */
Chris@16 284 template<class Func>
Chris@16 285 param_type(std::size_t nw, double xmin, double xmax, Func fw)
Chris@16 286 {
Chris@16 287 std::size_t n = (nw == 0) ? 1 : nw;
Chris@16 288 double delta = (xmax - xmin) / n;
Chris@16 289 BOOST_ASSERT(delta > 0);
Chris@16 290 for(std::size_t k = 0; k < n; ++k) {
Chris@16 291 _probabilities.push_back(fw(xmin + k*delta + delta/2));
Chris@16 292 }
Chris@16 293 normalize();
Chris@16 294 }
Chris@16 295
Chris@16 296 /**
Chris@16 297 * Returns a vector containing the probabilities of each possible
Chris@16 298 * value of the distribution.
Chris@16 299 */
Chris@16 300 std::vector<WeightType> probabilities() const
Chris@16 301 {
Chris@16 302 return _probabilities;
Chris@16 303 }
Chris@16 304
Chris@16 305 /** Writes the parameters to a @c std::ostream. */
Chris@16 306 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
Chris@16 307 {
Chris@16 308 detail::print_vector(os, parm._probabilities);
Chris@16 309 return os;
Chris@16 310 }
Chris@16 311
Chris@16 312 /** Reads the parameters from a @c std::istream. */
Chris@16 313 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
Chris@16 314 {
Chris@16 315 std::vector<WeightType> temp;
Chris@16 316 detail::read_vector(is, temp);
Chris@16 317 if(is) {
Chris@16 318 parm._probabilities.swap(temp);
Chris@16 319 }
Chris@16 320 return is;
Chris@16 321 }
Chris@16 322
Chris@16 323 /** Returns true if the two sets of parameters are the same. */
Chris@16 324 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
Chris@16 325 {
Chris@16 326 return lhs._probabilities == rhs._probabilities;
Chris@16 327 }
Chris@16 328 /** Returns true if the two sets of parameters are different. */
Chris@16 329 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
Chris@16 330 private:
Chris@16 331 /// @cond show_private
Chris@16 332 friend class discrete_distribution;
Chris@16 333 explicit param_type(const discrete_distribution& dist)
Chris@16 334 : _probabilities(dist.probabilities())
Chris@16 335 {}
Chris@16 336 void normalize()
Chris@16 337 {
Chris@101 338 impl_type::normalize(_probabilities);
Chris@16 339 }
Chris@16 340 std::vector<WeightType> _probabilities;
Chris@16 341 /// @endcond
Chris@16 342 };
Chris@16 343
Chris@16 344 /**
Chris@16 345 * Creates a new @c discrete_distribution object that has
Chris@16 346 * \f$p(0) = 1\f$ and \f$p(i|i>0) = 0\f$.
Chris@16 347 */
Chris@16 348 discrete_distribution()
Chris@16 349 {
Chris@101 350 _impl.init_empty();
Chris@16 351 }
Chris@16 352 /**
Chris@16 353 * Constructs a discrete_distribution from an iterator range.
Chris@16 354 * If @c first == @c last, equivalent to the default constructor.
Chris@16 355 * Otherwise, the values of the range represent weights for the
Chris@16 356 * possible values of the distribution.
Chris@16 357 */
Chris@16 358 template<class Iter>
Chris@16 359 discrete_distribution(Iter first, Iter last)
Chris@16 360 {
Chris@16 361 init(first, last);
Chris@16 362 }
Chris@16 363 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
Chris@16 364 /**
Chris@16 365 * Constructs a @c discrete_distribution from a @c std::initializer_list.
Chris@16 366 * If the @c initializer_list is empty, equivalent to the default
Chris@16 367 * constructor. Otherwise, the values of the @c initializer_list
Chris@16 368 * represent weights for the possible values of the distribution.
Chris@16 369 * For example, given the distribution
Chris@16 370 *
Chris@16 371 * @code
Chris@16 372 * discrete_distribution<> dist{1, 4, 5};
Chris@16 373 * @endcode
Chris@16 374 *
Chris@16 375 * The probability of a 0 is 1/10, the probability of a 1 is 2/5,
Chris@16 376 * the probability of a 2 is 1/2, and no other values are possible.
Chris@16 377 */
Chris@16 378 discrete_distribution(std::initializer_list<WeightType> wl)
Chris@16 379 {
Chris@16 380 init(wl.begin(), wl.end());
Chris@16 381 }
Chris@16 382 #endif
Chris@16 383 /**
Chris@16 384 * Constructs a discrete_distribution from a Boost.Range range.
Chris@16 385 * If the range is empty, equivalent to the default constructor.
Chris@16 386 * Otherwise, the values of the range represent weights for the
Chris@16 387 * possible values of the distribution.
Chris@16 388 */
Chris@16 389 template<class Range>
Chris@16 390 explicit discrete_distribution(const Range& range)
Chris@16 391 {
Chris@16 392 init(boost::begin(range), boost::end(range));
Chris@16 393 }
Chris@16 394 /**
Chris@16 395 * Constructs a discrete_distribution that approximates a function.
Chris@16 396 * If nw is zero, equivalent to the default constructor.
Chris@16 397 * Otherwise, the range of the distribution is [0, nw),
Chris@16 398 * and the weights are found by calling fw with values
Chris@16 399 * evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and
Chris@16 400 * \f$\mbox{xmax} - \delta/2\f$, where
Chris@16 401 * \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$.
Chris@16 402 */
Chris@16 403 template<class Func>
Chris@16 404 discrete_distribution(std::size_t nw, double xmin, double xmax, Func fw)
Chris@16 405 {
Chris@16 406 std::size_t n = (nw == 0) ? 1 : nw;
Chris@16 407 double delta = (xmax - xmin) / n;
Chris@16 408 BOOST_ASSERT(delta > 0);
Chris@16 409 std::vector<WeightType> weights;
Chris@16 410 for(std::size_t k = 0; k < n; ++k) {
Chris@16 411 weights.push_back(fw(xmin + k*delta + delta/2));
Chris@16 412 }
Chris@16 413 init(weights.begin(), weights.end());
Chris@16 414 }
Chris@16 415 /**
Chris@16 416 * Constructs a discrete_distribution from its parameters.
Chris@16 417 */
Chris@16 418 explicit discrete_distribution(const param_type& parm)
Chris@16 419 {
Chris@16 420 param(parm);
Chris@16 421 }
Chris@16 422
Chris@16 423 /**
Chris@16 424 * Returns a value distributed according to the parameters of the
Chris@16 425 * discrete_distribution.
Chris@16 426 */
Chris@16 427 template<class URNG>
Chris@16 428 IntType operator()(URNG& urng) const
Chris@16 429 {
Chris@101 430 BOOST_ASSERT(!_impl._alias_table.empty());
Chris@101 431 IntType result;
Chris@101 432 WeightType test;
Chris@101 433 do {
Chris@101 434 result = uniform_int_distribution<IntType>((min)(), (max)())(urng);
Chris@101 435 test = _impl.test(urng);
Chris@101 436 } while(!_impl.accept(result, test));
Chris@101 437 if(test < _impl._alias_table[result].first) {
Chris@16 438 return result;
Chris@16 439 } else {
Chris@101 440 return(_impl._alias_table[result].second);
Chris@16 441 }
Chris@16 442 }
Chris@16 443
Chris@16 444 /**
Chris@16 445 * Returns a value distributed according to the parameters
Chris@16 446 * specified by param.
Chris@16 447 */
Chris@16 448 template<class URNG>
Chris@16 449 IntType operator()(URNG& urng, const param_type& parm) const
Chris@16 450 {
Chris@101 451 if(WeightType limit = impl_type::try_get_sum(parm._probabilities)) {
Chris@101 452 WeightType val = impl_type::generate_in_range(urng, limit);
Chris@16 453 WeightType sum = 0;
Chris@16 454 std::size_t result = 0;
Chris@16 455 for(typename std::vector<WeightType>::const_iterator
Chris@101 456 iter = parm._probabilities.begin(),
Chris@101 457 end = parm._probabilities.end();
Chris@16 458 iter != end; ++iter, ++result)
Chris@16 459 {
Chris@16 460 sum += *iter;
Chris@16 461 if(sum > val) {
Chris@16 462 return result;
Chris@16 463 }
Chris@16 464 }
Chris@101 465 // This shouldn't be reachable, but round-off error
Chris@101 466 // can prevent any match from being found when val is
Chris@101 467 // very close to 1.
Chris@101 468 return static_cast<IntType>(parm._probabilities.size() - 1);
Chris@101 469 } else {
Chris@101 470 // WeightType is integral and sum(parm._probabilities)
Chris@101 471 // would overflow. Just use the easy solution.
Chris@101 472 return discrete_distribution(parm)(urng);
Chris@16 473 }
Chris@16 474 }
Chris@16 475
Chris@16 476 /** Returns the smallest value that the distribution can produce. */
Chris@16 477 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
Chris@16 478 /** Returns the largest value that the distribution can produce. */
Chris@16 479 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
Chris@101 480 { return static_cast<result_type>(_impl._alias_table.size() - 1); }
Chris@16 481
Chris@16 482 /**
Chris@16 483 * Returns a vector containing the probabilities of each
Chris@16 484 * value of the distribution. For example, given
Chris@16 485 *
Chris@16 486 * @code
Chris@16 487 * discrete_distribution<> dist = { 1, 4, 5 };
Chris@16 488 * std::vector<double> p = dist.param();
Chris@16 489 * @endcode
Chris@16 490 *
Chris@16 491 * the vector, p will contain {0.1, 0.4, 0.5}.
Chris@101 492 *
Chris@101 493 * If @c WeightType is integral, then the weights
Chris@101 494 * will be returned unchanged.
Chris@16 495 */
Chris@16 496 std::vector<WeightType> probabilities() const
Chris@16 497 {
Chris@101 498 std::vector<WeightType> result(_impl._alias_table.size());
Chris@16 499 std::size_t i = 0;
Chris@101 500 for(typename impl_type::alias_table_t::const_iterator
Chris@101 501 iter = _impl._alias_table.begin(),
Chris@101 502 end = _impl._alias_table.end();
Chris@16 503 iter != end; ++iter, ++i)
Chris@16 504 {
Chris@101 505 WeightType val = iter->first;
Chris@16 506 result[i] += val;
Chris@101 507 result[iter->second] += _impl.get_weight(i) - val;
Chris@16 508 }
Chris@101 509 impl_type::normalize(result);
Chris@16 510 return(result);
Chris@16 511 }
Chris@16 512
Chris@16 513 /** Returns the parameters of the distribution. */
Chris@16 514 param_type param() const
Chris@16 515 {
Chris@16 516 return param_type(*this);
Chris@16 517 }
Chris@16 518 /** Sets the parameters of the distribution. */
Chris@16 519 void param(const param_type& parm)
Chris@16 520 {
Chris@16 521 init(parm._probabilities.begin(), parm._probabilities.end());
Chris@16 522 }
Chris@16 523
Chris@16 524 /**
Chris@16 525 * Effects: Subsequent uses of the distribution do not depend
Chris@16 526 * on values produced by any engine prior to invoking reset.
Chris@16 527 */
Chris@16 528 void reset() {}
Chris@16 529
Chris@16 530 /** Writes a distribution to a @c std::ostream. */
Chris@16 531 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, discrete_distribution, dd)
Chris@16 532 {
Chris@16 533 os << dd.param();
Chris@16 534 return os;
Chris@16 535 }
Chris@16 536
Chris@16 537 /** Reads a distribution from a @c std::istream */
Chris@16 538 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, discrete_distribution, dd)
Chris@16 539 {
Chris@16 540 param_type parm;
Chris@16 541 if(is >> parm) {
Chris@16 542 dd.param(parm);
Chris@16 543 }
Chris@16 544 return is;
Chris@16 545 }
Chris@16 546
Chris@16 547 /**
Chris@16 548 * Returns true if the two distributions will return the
Chris@16 549 * same sequence of values, when passed equal generators.
Chris@16 550 */
Chris@16 551 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(discrete_distribution, lhs, rhs)
Chris@16 552 {
Chris@101 553 return lhs._impl == rhs._impl;
Chris@16 554 }
Chris@16 555 /**
Chris@16 556 * Returns true if the two distributions may return different
Chris@16 557 * sequences of values, when passed equal generators.
Chris@16 558 */
Chris@16 559 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(discrete_distribution)
Chris@16 560
Chris@16 561 private:
Chris@16 562
Chris@16 563 /// @cond show_private
Chris@16 564
Chris@16 565 template<class Iter>
Chris@16 566 void init(Iter first, Iter last, std::input_iterator_tag)
Chris@16 567 {
Chris@16 568 std::vector<WeightType> temp(first, last);
Chris@16 569 init(temp.begin(), temp.end());
Chris@16 570 }
Chris@16 571 template<class Iter>
Chris@16 572 void init(Iter first, Iter last, std::forward_iterator_tag)
Chris@16 573 {
Chris@16 574 std::vector<std::pair<WeightType, IntType> > below_average;
Chris@16 575 std::vector<std::pair<WeightType, IntType> > above_average;
Chris@101 576 WeightType weight_average = _impl.init_average(first, last);
Chris@101 577 WeightType normalized_average = _impl.get_weight(0);
Chris@16 578 std::size_t i = 0;
Chris@16 579 for(; first != last; ++first, ++i) {
Chris@101 580 WeightType val = impl_type::normalize(*first, weight_average);
Chris@16 581 std::pair<WeightType, IntType> elem(val, static_cast<IntType>(i));
Chris@101 582 if(val < normalized_average) {
Chris@16 583 below_average.push_back(elem);
Chris@16 584 } else {
Chris@16 585 above_average.push_back(elem);
Chris@16 586 }
Chris@16 587 }
Chris@16 588
Chris@101 589 typename impl_type::alias_table_t::iterator
Chris@16 590 b_iter = below_average.begin(),
Chris@16 591 b_end = below_average.end(),
Chris@16 592 a_iter = above_average.begin(),
Chris@16 593 a_end = above_average.end()
Chris@16 594 ;
Chris@16 595 while(b_iter != b_end && a_iter != a_end) {
Chris@101 596 _impl._alias_table[b_iter->second] =
Chris@16 597 std::make_pair(b_iter->first, a_iter->second);
Chris@101 598 a_iter->first -= (_impl.get_weight(b_iter->second) - b_iter->first);
Chris@101 599 if(a_iter->first < normalized_average) {
Chris@16 600 *b_iter = *a_iter++;
Chris@16 601 } else {
Chris@16 602 ++b_iter;
Chris@16 603 }
Chris@16 604 }
Chris@16 605 for(; b_iter != b_end; ++b_iter) {
Chris@101 606 _impl._alias_table[b_iter->second].first =
Chris@101 607 _impl.get_weight(b_iter->second);
Chris@16 608 }
Chris@16 609 for(; a_iter != a_end; ++a_iter) {
Chris@101 610 _impl._alias_table[a_iter->second].first =
Chris@101 611 _impl.get_weight(a_iter->second);
Chris@16 612 }
Chris@16 613 }
Chris@16 614 template<class Iter>
Chris@16 615 void init(Iter first, Iter last)
Chris@16 616 {
Chris@16 617 if(first == last) {
Chris@101 618 _impl.init_empty();
Chris@16 619 } else {
Chris@16 620 typename std::iterator_traits<Iter>::iterator_category category;
Chris@16 621 init(first, last, category);
Chris@16 622 }
Chris@16 623 }
Chris@101 624 typedef typename detail::select_alias_table<
Chris@101 625 (::boost::is_integral<WeightType>::value)
Chris@101 626 >::template apply<IntType, WeightType>::type impl_type;
Chris@101 627 impl_type _impl;
Chris@16 628 /// @endcond
Chris@16 629 };
Chris@16 630
Chris@16 631 }
Chris@16 632 }
Chris@16 633
Chris@16 634 #include <boost/random/detail/enable_warnings.hpp>
Chris@16 635
Chris@16 636 #endif