Mercurial > hg > vamp-build-and-test
comparison DEPENDENCIES/generic/include/boost/random/piecewise_constant_distribution.hpp @ 16:2665513ce2d3
Add boost headers
author | Chris Cannam |
---|---|
date | Tue, 05 Aug 2014 11:11:38 +0100 |
parents | |
children | c530137014c0 |
comparison
equal
deleted
inserted
replaced
15:663ca0da4350 | 16:2665513ce2d3 |
---|---|
1 /* boost random/piecewise_constant_distribution.hpp header file | |
2 * | |
3 * Copyright Steven Watanabe 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: piecewise_constant_distribution.hpp 85813 2013-09-21 20:17:00Z jewillco $ | |
11 */ | |
12 | |
13 #ifndef BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED | |
14 #define BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED | |
15 | |
16 #include <vector> | |
17 #include <numeric> | |
18 #include <boost/assert.hpp> | |
19 #include <boost/random/uniform_real.hpp> | |
20 #include <boost/random/discrete_distribution.hpp> | |
21 #include <boost/random/detail/config.hpp> | |
22 #include <boost/random/detail/operators.hpp> | |
23 #include <boost/random/detail/vector_io.hpp> | |
24 | |
25 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST | |
26 #include <initializer_list> | |
27 #endif | |
28 | |
29 #include <boost/range/begin.hpp> | |
30 #include <boost/range/end.hpp> | |
31 | |
32 namespace boost { | |
33 namespace random { | |
34 | |
35 /** | |
36 * The class @c piecewise_constant_distribution models a \random_distribution. | |
37 */ | |
38 template<class RealType = double, class WeightType = double> | |
39 class piecewise_constant_distribution { | |
40 public: | |
41 typedef std::size_t input_type; | |
42 typedef RealType result_type; | |
43 | |
44 class param_type { | |
45 public: | |
46 | |
47 typedef piecewise_constant_distribution distribution_type; | |
48 | |
49 /** | |
50 * Constructs a @c param_type object, representing a distribution | |
51 * that produces values uniformly distributed in the range [0, 1). | |
52 */ | |
53 param_type() | |
54 { | |
55 _weights.push_back(WeightType(1)); | |
56 _intervals.push_back(RealType(0)); | |
57 _intervals.push_back(RealType(1)); | |
58 } | |
59 /** | |
60 * Constructs a @c param_type object from two iterator ranges | |
61 * containing the interval boundaries and the interval weights. | |
62 * If there are less than two boundaries, then this is equivalent to | |
63 * the default constructor and creates a single interval, [0, 1). | |
64 * | |
65 * The values of the interval boundaries must be strictly | |
66 * increasing, and the number of weights must be one less than | |
67 * the number of interval boundaries. If there are extra | |
68 * weights, they are ignored. | |
69 */ | |
70 template<class IntervalIter, class WeightIter> | |
71 param_type(IntervalIter intervals_first, IntervalIter intervals_last, | |
72 WeightIter weight_first) | |
73 : _intervals(intervals_first, intervals_last) | |
74 { | |
75 if(_intervals.size() < 2) { | |
76 _intervals.clear(); | |
77 _intervals.push_back(RealType(0)); | |
78 _intervals.push_back(RealType(1)); | |
79 _weights.push_back(WeightType(1)); | |
80 } else { | |
81 _weights.reserve(_intervals.size() - 1); | |
82 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { | |
83 _weights.push_back(*weight_first++); | |
84 } | |
85 } | |
86 } | |
87 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST | |
88 /** | |
89 * Constructs a @c param_type object from an | |
90 * initializer_list containing the interval boundaries | |
91 * and a unary function specifying the weights. Each | |
92 * weight is determined by calling the function at the | |
93 * midpoint of the corresponding interval. | |
94 * | |
95 * If the initializer_list contains less than two elements, | |
96 * this is equivalent to the default constructor and the | |
97 * distribution will produce values uniformly distributed | |
98 * in the range [0, 1). | |
99 */ | |
100 template<class T, class F> | |
101 param_type(const std::initializer_list<T>& il, F f) | |
102 : _intervals(il.begin(), il.end()) | |
103 { | |
104 if(_intervals.size() < 2) { | |
105 _intervals.clear(); | |
106 _intervals.push_back(RealType(0)); | |
107 _intervals.push_back(RealType(1)); | |
108 _weights.push_back(WeightType(1)); | |
109 } else { | |
110 _weights.reserve(_intervals.size() - 1); | |
111 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { | |
112 RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; | |
113 _weights.push_back(f(midpoint)); | |
114 } | |
115 } | |
116 } | |
117 #endif | |
118 /** | |
119 * Constructs a @c param_type object from Boost.Range | |
120 * ranges holding the interval boundaries and the weights. If | |
121 * there are less than two interval boundaries, this is equivalent | |
122 * to the default constructor and the distribution will produce | |
123 * values uniformly distributed in the range [0, 1). The | |
124 * number of weights must be one less than the number of | |
125 * interval boundaries. | |
126 */ | |
127 template<class IntervalRange, class WeightRange> | |
128 param_type(const IntervalRange& intervals_arg, | |
129 const WeightRange& weights_arg) | |
130 : _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)), | |
131 _weights(boost::begin(weights_arg), boost::end(weights_arg)) | |
132 { | |
133 if(_intervals.size() < 2) { | |
134 _intervals.clear(); | |
135 _intervals.push_back(RealType(0)); | |
136 _intervals.push_back(RealType(1)); | |
137 _weights.push_back(WeightType(1)); | |
138 } | |
139 } | |
140 | |
141 /** | |
142 * Constructs the parameters for a distribution that approximates a | |
143 * function. The range of the distribution is [xmin, xmax). This | |
144 * range is divided into nw equally sized intervals and the weights | |
145 * are found by calling the unary function f on the midpoints of the | |
146 * intervals. | |
147 */ | |
148 template<class F> | |
149 param_type(std::size_t nw, RealType xmin, RealType xmax, F f) | |
150 { | |
151 std::size_t n = (nw == 0) ? 1 : nw; | |
152 double delta = (xmax - xmin) / n; | |
153 BOOST_ASSERT(delta > 0); | |
154 for(std::size_t k = 0; k < n; ++k) { | |
155 _weights.push_back(f(xmin + k*delta + delta/2)); | |
156 _intervals.push_back(xmin + k*delta); | |
157 } | |
158 _intervals.push_back(xmax); | |
159 } | |
160 | |
161 /** Returns a vector containing the interval boundaries. */ | |
162 std::vector<RealType> intervals() const { return _intervals; } | |
163 | |
164 /** | |
165 * Returns a vector containing the probability densities | |
166 * over all the intervals of the distribution. | |
167 */ | |
168 std::vector<RealType> densities() const | |
169 { | |
170 RealType sum = std::accumulate(_weights.begin(), _weights.end(), | |
171 static_cast<RealType>(0)); | |
172 std::vector<RealType> result; | |
173 result.reserve(_weights.size()); | |
174 for(std::size_t i = 0; i < _weights.size(); ++i) { | |
175 RealType width = _intervals[i + 1] - _intervals[i]; | |
176 result.push_back(_weights[i] / (sum * width)); | |
177 } | |
178 return result; | |
179 } | |
180 | |
181 /** Writes the parameters to a @c std::ostream. */ | |
182 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) | |
183 { | |
184 detail::print_vector(os, parm._intervals); | |
185 detail::print_vector(os, parm._weights); | |
186 return os; | |
187 } | |
188 | |
189 /** Reads the parameters from a @c std::istream. */ | |
190 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) | |
191 { | |
192 std::vector<RealType> new_intervals; | |
193 std::vector<WeightType> new_weights; | |
194 detail::read_vector(is, new_intervals); | |
195 detail::read_vector(is, new_weights); | |
196 if(is) { | |
197 parm._intervals.swap(new_intervals); | |
198 parm._weights.swap(new_weights); | |
199 } | |
200 return is; | |
201 } | |
202 | |
203 /** Returns true if the two sets of parameters are the same. */ | |
204 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) | |
205 { | |
206 return lhs._intervals == rhs._intervals | |
207 && lhs._weights == rhs._weights; | |
208 } | |
209 /** Returns true if the two sets of parameters are different. */ | |
210 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) | |
211 | |
212 private: | |
213 | |
214 friend class piecewise_constant_distribution; | |
215 | |
216 std::vector<RealType> _intervals; | |
217 std::vector<WeightType> _weights; | |
218 }; | |
219 | |
220 /** | |
221 * Creates a new @c piecewise_constant_distribution with | |
222 * a single interval, [0, 1). | |
223 */ | |
224 piecewise_constant_distribution() | |
225 { | |
226 _intervals.push_back(RealType(0)); | |
227 _intervals.push_back(RealType(1)); | |
228 } | |
229 /** | |
230 * Constructs a piecewise_constant_distribution from two iterator ranges | |
231 * containing the interval boundaries and the interval weights. | |
232 * If there are less than two boundaries, then this is equivalent to | |
233 * the default constructor and creates a single interval, [0, 1). | |
234 * | |
235 * The values of the interval boundaries must be strictly | |
236 * increasing, and the number of weights must be one less than | |
237 * the number of interval boundaries. If there are extra | |
238 * weights, they are ignored. | |
239 * | |
240 * For example, | |
241 * | |
242 * @code | |
243 * double intervals[] = { 0.0, 1.0, 4.0 }; | |
244 * double weights[] = { 1.0, 1.0 }; | |
245 * piecewise_constant_distribution<> dist( | |
246 * &intervals[0], &intervals[0] + 3, &weights[0]); | |
247 * @endcode | |
248 * | |
249 * The distribution has a 50% chance of producing a | |
250 * value between 0 and 1 and a 50% chance of producing | |
251 * a value between 1 and 4. | |
252 */ | |
253 template<class IntervalIter, class WeightIter> | |
254 piecewise_constant_distribution(IntervalIter first_interval, | |
255 IntervalIter last_interval, | |
256 WeightIter first_weight) | |
257 : _intervals(first_interval, last_interval) | |
258 { | |
259 if(_intervals.size() < 2) { | |
260 _intervals.clear(); | |
261 _intervals.push_back(RealType(0)); | |
262 _intervals.push_back(RealType(1)); | |
263 } else { | |
264 std::vector<WeightType> actual_weights; | |
265 actual_weights.reserve(_intervals.size() - 1); | |
266 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { | |
267 actual_weights.push_back(*first_weight++); | |
268 } | |
269 typedef discrete_distribution<std::size_t, WeightType> bins_type; | |
270 typename bins_type::param_type bins_param(actual_weights); | |
271 _bins.param(bins_param); | |
272 } | |
273 } | |
274 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST | |
275 /** | |
276 * Constructs a piecewise_constant_distribution from an | |
277 * initializer_list containing the interval boundaries | |
278 * and a unary function specifying the weights. Each | |
279 * weight is determined by calling the function at the | |
280 * midpoint of the corresponding interval. | |
281 * | |
282 * If the initializer_list contains less than two elements, | |
283 * this is equivalent to the default constructor and the | |
284 * distribution will produce values uniformly distributed | |
285 * in the range [0, 1). | |
286 */ | |
287 template<class T, class F> | |
288 piecewise_constant_distribution(std::initializer_list<T> il, F f) | |
289 : _intervals(il.begin(), il.end()) | |
290 { | |
291 if(_intervals.size() < 2) { | |
292 _intervals.clear(); | |
293 _intervals.push_back(RealType(0)); | |
294 _intervals.push_back(RealType(1)); | |
295 } else { | |
296 std::vector<WeightType> actual_weights; | |
297 actual_weights.reserve(_intervals.size() - 1); | |
298 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { | |
299 RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; | |
300 actual_weights.push_back(f(midpoint)); | |
301 } | |
302 typedef discrete_distribution<std::size_t, WeightType> bins_type; | |
303 typename bins_type::param_type bins_param(actual_weights); | |
304 _bins.param(bins_param); | |
305 } | |
306 } | |
307 #endif | |
308 /** | |
309 * Constructs a piecewise_constant_distribution from Boost.Range | |
310 * ranges holding the interval boundaries and the weights. If | |
311 * there are less than two interval boundaries, this is equivalent | |
312 * to the default constructor and the distribution will produce | |
313 * values uniformly distributed in the range [0, 1). The | |
314 * number of weights must be one less than the number of | |
315 * interval boundaries. | |
316 */ | |
317 template<class IntervalsRange, class WeightsRange> | |
318 piecewise_constant_distribution(const IntervalsRange& intervals_arg, | |
319 const WeightsRange& weights_arg) | |
320 : _bins(weights_arg), | |
321 _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)) | |
322 { | |
323 if(_intervals.size() < 2) { | |
324 _intervals.clear(); | |
325 _intervals.push_back(RealType(0)); | |
326 _intervals.push_back(RealType(1)); | |
327 } | |
328 } | |
329 /** | |
330 * Constructs a piecewise_constant_distribution that approximates a | |
331 * function. The range of the distribution is [xmin, xmax). This | |
332 * range is divided into nw equally sized intervals and the weights | |
333 * are found by calling the unary function f on the midpoints of the | |
334 * intervals. | |
335 */ | |
336 template<class F> | |
337 piecewise_constant_distribution(std::size_t nw, | |
338 RealType xmin, | |
339 RealType xmax, | |
340 F f) | |
341 : _bins(nw, xmin, xmax, f) | |
342 { | |
343 if(nw == 0) { nw = 1; } | |
344 RealType delta = (xmax - xmin) / nw; | |
345 _intervals.reserve(nw + 1); | |
346 for(std::size_t i = 0; i < nw; ++i) { | |
347 _intervals.push_back(xmin + i * delta); | |
348 } | |
349 _intervals.push_back(xmax); | |
350 } | |
351 /** | |
352 * Constructs a piecewise_constant_distribution from its parameters. | |
353 */ | |
354 explicit piecewise_constant_distribution(const param_type& parm) | |
355 : _bins(parm._weights), | |
356 _intervals(parm._intervals) | |
357 { | |
358 } | |
359 | |
360 /** | |
361 * Returns a value distributed according to the parameters of the | |
362 * piecewist_constant_distribution. | |
363 */ | |
364 template<class URNG> | |
365 RealType operator()(URNG& urng) const | |
366 { | |
367 std::size_t i = _bins(urng); | |
368 return uniform_real<RealType>(_intervals[i], _intervals[i+1])(urng); | |
369 } | |
370 | |
371 /** | |
372 * Returns a value distributed according to the parameters | |
373 * specified by param. | |
374 */ | |
375 template<class URNG> | |
376 RealType operator()(URNG& urng, const param_type& parm) const | |
377 { | |
378 return piecewise_constant_distribution(parm)(urng); | |
379 } | |
380 | |
381 /** Returns the smallest value that the distribution can produce. */ | |
382 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const | |
383 { return _intervals.front(); } | |
384 /** Returns the largest value that the distribution can produce. */ | |
385 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const | |
386 { return _intervals.back(); } | |
387 | |
388 /** | |
389 * Returns a vector containing the probability density | |
390 * over each interval. | |
391 */ | |
392 std::vector<RealType> densities() const | |
393 { | |
394 std::vector<RealType> result(_bins.probabilities()); | |
395 for(std::size_t i = 0; i < result.size(); ++i) { | |
396 result[i] /= (_intervals[i+1] - _intervals[i]); | |
397 } | |
398 return(result); | |
399 } | |
400 /** Returns a vector containing the interval boundaries. */ | |
401 std::vector<RealType> intervals() const { return _intervals; } | |
402 | |
403 /** Returns the parameters of the distribution. */ | |
404 param_type param() const | |
405 { | |
406 return param_type(_intervals, _bins.probabilities()); | |
407 } | |
408 /** Sets the parameters of the distribution. */ | |
409 void param(const param_type& parm) | |
410 { | |
411 std::vector<RealType> new_intervals(parm._intervals); | |
412 typedef discrete_distribution<std::size_t, RealType> bins_type; | |
413 typename bins_type::param_type bins_param(parm._weights); | |
414 _bins.param(bins_param); | |
415 _intervals.swap(new_intervals); | |
416 } | |
417 | |
418 /** | |
419 * Effects: Subsequent uses of the distribution do not depend | |
420 * on values produced by any engine prior to invoking reset. | |
421 */ | |
422 void reset() { _bins.reset(); } | |
423 | |
424 /** Writes a distribution to a @c std::ostream. */ | |
425 BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR( | |
426 os, piecewise_constant_distribution, pcd) | |
427 { | |
428 os << pcd.param(); | |
429 return os; | |
430 } | |
431 | |
432 /** Reads a distribution from a @c std::istream */ | |
433 BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR( | |
434 is, piecewise_constant_distribution, pcd) | |
435 { | |
436 param_type parm; | |
437 if(is >> parm) { | |
438 pcd.param(parm); | |
439 } | |
440 return is; | |
441 } | |
442 | |
443 /** | |
444 * Returns true if the two distributions will return the | |
445 * same sequence of values, when passed equal generators. | |
446 */ | |
447 BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR( | |
448 piecewise_constant_distribution, lhs, rhs) | |
449 { | |
450 return lhs._bins == rhs._bins && lhs._intervals == rhs._intervals; | |
451 } | |
452 /** | |
453 * Returns true if the two distributions may return different | |
454 * sequences of values, when passed equal generators. | |
455 */ | |
456 BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(piecewise_constant_distribution) | |
457 | |
458 private: | |
459 discrete_distribution<std::size_t, WeightType> _bins; | |
460 std::vector<RealType> _intervals; | |
461 }; | |
462 | |
463 } | |
464 } | |
465 | |
466 #endif |