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