diff options
Diffstat (limited to 'src/third_party/boost-1.69.0/boost/random/piecewise_constant_distribution.hpp')
-rw-r--r-- | src/third_party/boost-1.69.0/boost/random/piecewise_constant_distribution.hpp | 466 |
1 files changed, 466 insertions, 0 deletions
diff --git a/src/third_party/boost-1.69.0/boost/random/piecewise_constant_distribution.hpp b/src/third_party/boost-1.69.0/boost/random/piecewise_constant_distribution.hpp new file mode 100644 index 00000000000..488f41c0e34 --- /dev/null +++ b/src/third_party/boost-1.69.0/boost/random/piecewise_constant_distribution.hpp @@ -0,0 +1,466 @@ +/* boost random/piecewise_constant_distribution.hpp header file + * + * Copyright Steven Watanabe 2011 + * Distributed under the Boost Software License, Version 1.0. (See + * accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * See http://www.boost.org for most recent version including documentation. + * + * $Id$ + */ + +#ifndef BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED +#define BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED + +#include <vector> +#include <numeric> +#include <boost/assert.hpp> +#include <boost/random/uniform_real.hpp> +#include <boost/random/discrete_distribution.hpp> +#include <boost/random/detail/config.hpp> +#include <boost/random/detail/operators.hpp> +#include <boost/random/detail/vector_io.hpp> + +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include <initializer_list> +#endif + +#include <boost/range/begin.hpp> +#include <boost/range/end.hpp> + +namespace boost { +namespace random { + +/** + * The class @c piecewise_constant_distribution models a \random_distribution. + */ +template<class RealType = double, class WeightType = double> +class piecewise_constant_distribution { +public: + typedef std::size_t input_type; + typedef RealType result_type; + + class param_type { + public: + + typedef piecewise_constant_distribution distribution_type; + + /** + * Constructs a @c param_type object, representing a distribution + * that produces values uniformly distributed in the range [0, 1). + */ + param_type() + { + _weights.push_back(WeightType(1)); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + /** + * Constructs a @c param_type object from two iterator ranges + * containing the interval boundaries and the interval weights. + * If there are less than two boundaries, then this is equivalent to + * the default constructor and creates a single interval, [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be one less than + * the number of interval boundaries. If there are extra + * weights, they are ignored. + */ + template<class IntervalIter, class WeightIter> + param_type(IntervalIter intervals_first, IntervalIter intervals_last, + WeightIter weight_first) + : _intervals(intervals_first, intervals_last) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } else { + _weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + _weights.push_back(*weight_first++); + } + } + } +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + /** + * Constructs a @c param_type object from an + * initializer_list containing the interval boundaries + * and a unary function specifying the weights. Each + * weight is determined by calling the function at the + * midpoint of the corresponding interval. + * + * If the initializer_list contains less than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template<class T, class F> + param_type(const std::initializer_list<T>& il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } else { + _weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; + _weights.push_back(f(midpoint)); + } + } + } +#endif + /** + * Constructs a @c param_type object from Boost.Range + * ranges holding the interval boundaries and the weights. If + * there are less than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be one less than the number of + * interval boundaries. + */ + template<class IntervalRange, class WeightRange> + param_type(const IntervalRange& intervals_arg, + const WeightRange& weights_arg) + : _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)), + _weights(boost::begin(weights_arg), boost::end(weights_arg)) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + _weights.push_back(WeightType(1)); + } + } + + /** + * Constructs the parameters for a distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the midpoints of the + * intervals. + */ + template<class F> + param_type(std::size_t nw, RealType xmin, RealType xmax, F f) + { + std::size_t n = (nw == 0) ? 1 : nw; + double delta = (xmax - xmin) / n; + BOOST_ASSERT(delta > 0); + for(std::size_t k = 0; k < n; ++k) { + _weights.push_back(f(xmin + k*delta + delta/2)); + _intervals.push_back(xmin + k*delta); + } + _intervals.push_back(xmax); + } + + /** Returns a vector containing the interval boundaries. */ + std::vector<RealType> intervals() const { return _intervals; } + + /** + * Returns a vector containing the probability densities + * over all the intervals of the distribution. + */ + std::vector<RealType> densities() const + { + RealType sum = std::accumulate(_weights.begin(), _weights.end(), + static_cast<RealType>(0)); + std::vector<RealType> result; + result.reserve(_weights.size()); + for(std::size_t i = 0; i < _weights.size(); ++i) { + RealType width = _intervals[i + 1] - _intervals[i]; + result.push_back(_weights[i] / (sum * width)); + } + return result; + } + + /** Writes the parameters to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm) + { + detail::print_vector(os, parm._intervals); + detail::print_vector(os, parm._weights); + return os; + } + + /** Reads the parameters from a @c std::istream. */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm) + { + std::vector<RealType> new_intervals; + std::vector<WeightType> new_weights; + detail::read_vector(is, new_intervals); + detail::read_vector(is, new_weights); + if(is) { + parm._intervals.swap(new_intervals); + parm._weights.swap(new_weights); + } + return is; + } + + /** Returns true if the two sets of parameters are the same. */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs) + { + return lhs._intervals == rhs._intervals + && lhs._weights == rhs._weights; + } + /** Returns true if the two sets of parameters are different. */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type) + + private: + + friend class piecewise_constant_distribution; + + std::vector<RealType> _intervals; + std::vector<WeightType> _weights; + }; + + /** + * Creates a new @c piecewise_constant_distribution with + * a single interval, [0, 1). + */ + piecewise_constant_distribution() + { + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + /** + * Constructs a piecewise_constant_distribution from two iterator ranges + * containing the interval boundaries and the interval weights. + * If there are less than two boundaries, then this is equivalent to + * the default constructor and creates a single interval, [0, 1). + * + * The values of the interval boundaries must be strictly + * increasing, and the number of weights must be one less than + * the number of interval boundaries. If there are extra + * weights, they are ignored. + * + * For example, + * + * @code + * double intervals[] = { 0.0, 1.0, 4.0 }; + * double weights[] = { 1.0, 1.0 }; + * piecewise_constant_distribution<> dist( + * &intervals[0], &intervals[0] + 3, &weights[0]); + * @endcode + * + * The distribution has a 50% chance of producing a + * value between 0 and 1 and a 50% chance of producing + * a value between 1 and 4. + */ + template<class IntervalIter, class WeightIter> + piecewise_constant_distribution(IntervalIter first_interval, + IntervalIter last_interval, + WeightIter first_weight) + : _intervals(first_interval, last_interval) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + std::vector<WeightType> actual_weights; + actual_weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + actual_weights.push_back(*first_weight++); + } + typedef discrete_distribution<std::size_t, WeightType> bins_type; + typename bins_type::param_type bins_param(actual_weights); + _bins.param(bins_param); + } + } +#ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST + /** + * Constructs a piecewise_constant_distribution from an + * initializer_list containing the interval boundaries + * and a unary function specifying the weights. Each + * weight is determined by calling the function at the + * midpoint of the corresponding interval. + * + * If the initializer_list contains less than two elements, + * this is equivalent to the default constructor and the + * distribution will produce values uniformly distributed + * in the range [0, 1). + */ + template<class T, class F> + piecewise_constant_distribution(std::initializer_list<T> il, F f) + : _intervals(il.begin(), il.end()) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } else { + std::vector<WeightType> actual_weights; + actual_weights.reserve(_intervals.size() - 1); + for(std::size_t i = 0; i < _intervals.size() - 1; ++i) { + RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2; + actual_weights.push_back(f(midpoint)); + } + typedef discrete_distribution<std::size_t, WeightType> bins_type; + typename bins_type::param_type bins_param(actual_weights); + _bins.param(bins_param); + } + } +#endif + /** + * Constructs a piecewise_constant_distribution from Boost.Range + * ranges holding the interval boundaries and the weights. If + * there are less than two interval boundaries, this is equivalent + * to the default constructor and the distribution will produce + * values uniformly distributed in the range [0, 1). The + * number of weights must be one less than the number of + * interval boundaries. + */ + template<class IntervalsRange, class WeightsRange> + piecewise_constant_distribution(const IntervalsRange& intervals_arg, + const WeightsRange& weights_arg) + : _bins(weights_arg), + _intervals(boost::begin(intervals_arg), boost::end(intervals_arg)) + { + if(_intervals.size() < 2) { + _intervals.clear(); + _intervals.push_back(RealType(0)); + _intervals.push_back(RealType(1)); + } + } + /** + * Constructs a piecewise_constant_distribution that approximates a + * function. The range of the distribution is [xmin, xmax). This + * range is divided into nw equally sized intervals and the weights + * are found by calling the unary function f on the midpoints of the + * intervals. + */ + template<class F> + piecewise_constant_distribution(std::size_t nw, + RealType xmin, + RealType xmax, + F f) + : _bins(nw, xmin, xmax, f) + { + if(nw == 0) { nw = 1; } + RealType delta = (xmax - xmin) / nw; + _intervals.reserve(nw + 1); + for(std::size_t i = 0; i < nw; ++i) { + _intervals.push_back(xmin + i * delta); + } + _intervals.push_back(xmax); + } + /** + * Constructs a piecewise_constant_distribution from its parameters. + */ + explicit piecewise_constant_distribution(const param_type& parm) + : _bins(parm._weights), + _intervals(parm._intervals) + { + } + + /** + * Returns a value distributed according to the parameters of the + * piecewist_constant_distribution. + */ + template<class URNG> + RealType operator()(URNG& urng) const + { + std::size_t i = _bins(urng); + return uniform_real<RealType>(_intervals[i], _intervals[i+1])(urng); + } + + /** + * Returns a value distributed according to the parameters + * specified by param. + */ + template<class URNG> + RealType operator()(URNG& urng, const param_type& parm) const + { + return piecewise_constant_distribution(parm)(urng); + } + + /** Returns the smallest value that the distribution can produce. */ + result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.front(); } + /** Returns the largest value that the distribution can produce. */ + result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const + { return _intervals.back(); } + + /** + * Returns a vector containing the probability density + * over each interval. + */ + std::vector<RealType> densities() const + { + std::vector<RealType> result(_bins.probabilities()); + for(std::size_t i = 0; i < result.size(); ++i) { + result[i] /= (_intervals[i+1] - _intervals[i]); + } + return(result); + } + /** Returns a vector containing the interval boundaries. */ + std::vector<RealType> intervals() const { return _intervals; } + + /** Returns the parameters of the distribution. */ + param_type param() const + { + return param_type(_intervals, _bins.probabilities()); + } + /** Sets the parameters of the distribution. */ + void param(const param_type& parm) + { + std::vector<RealType> new_intervals(parm._intervals); + typedef discrete_distribution<std::size_t, WeightType> bins_type; + typename bins_type::param_type bins_param(parm._weights); + _bins.param(bins_param); + _intervals.swap(new_intervals); + } + + /** + * Effects: Subsequent uses of the distribution do not depend + * on values produced by any engine prior to invoking reset. + */ + void reset() { _bins.reset(); } + + /** Writes a distribution to a @c std::ostream. */ + BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR( + os, piecewise_constant_distribution, pcd) + { + os << pcd.param(); + return os; + } + + /** Reads a distribution from a @c std::istream */ + BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR( + is, piecewise_constant_distribution, pcd) + { + param_type parm; + if(is >> parm) { + pcd.param(parm); + } + return is; + } + + /** + * Returns true if the two distributions will return the + * same sequence of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR( + piecewise_constant_distribution, lhs, rhs) + { + return lhs._bins == rhs._bins && lhs._intervals == rhs._intervals; + } + /** + * Returns true if the two distributions may return different + * sequences of values, when passed equal generators. + */ + BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(piecewise_constant_distribution) + +private: + discrete_distribution<std::size_t, WeightType> _bins; + std::vector<RealType> _intervals; +}; + +} +} + +#endif |