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