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