Added boost header
This commit is contained in:
453
test/external/boost/random/discrete_distribution.hpp
vendored
Normal file
453
test/external/boost/random/discrete_distribution.hpp
vendored
Normal file
@@ -0,0 +1,453 @@
|
||||
/* boost random/discrete_distribution.hpp header file
|
||||
*
|
||||
* Copyright Steven Watanabe 2009-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: discrete_distribution.hpp 71018 2011-04-05 21:27:52Z steven_watanabe $
|
||||
*/
|
||||
|
||||
#ifndef BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
|
||||
#define BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
|
||||
|
||||
#include <vector>
|
||||
#include <limits>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <iterator>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/random/uniform_01.hpp>
|
||||
#include <boost/random/uniform_int.hpp>
|
||||
#include <boost/random/detail/config.hpp>
|
||||
#include <boost/random/detail/operators.hpp>
|
||||
#include <boost/random/detail/vector_io.hpp>
|
||||
|
||||
#ifndef BOOST_NO_INITIALIZER_LISTS
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
|
||||
#include <boost/range/begin.hpp>
|
||||
#include <boost/range/end.hpp>
|
||||
|
||||
#include <boost/random/detail/disable_warnings.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace random {
|
||||
|
||||
/**
|
||||
* The class @c discrete_distribution models a \random_distribution.
|
||||
* It produces integers in the range [0, n) with the probability
|
||||
* of producing each value is specified by the parameters of the
|
||||
* distribution.
|
||||
*/
|
||||
template<class IntType = int, class WeightType = double>
|
||||
class discrete_distribution {
|
||||
public:
|
||||
typedef WeightType input_type;
|
||||
typedef IntType result_type;
|
||||
|
||||
class param_type {
|
||||
public:
|
||||
|
||||
typedef discrete_distribution distribution_type;
|
||||
|
||||
/**
|
||||
* Constructs a @c param_type object, representing a distribution
|
||||
* with \f$p(0) = 1\f$ and \f$p(k|k>0) = 0\f$.
|
||||
*/
|
||||
param_type() : _probabilities(1, static_cast<WeightType>(1)) {}
|
||||
/**
|
||||
* If @c first == @c last, equivalent to the default constructor.
|
||||
* Otherwise, the values of the range represent weights for the
|
||||
* possible values of the distribution.
|
||||
*/
|
||||
template<class Iter>
|
||||
param_type(Iter first, Iter last) : _probabilities(first, last)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
#ifndef BOOST_NO_INITIALIZER_LISTS
|
||||
/**
|
||||
* If wl.size() == 0, equivalent to the default constructor.
|
||||
* Otherwise, the values of the @c initializer_list represent
|
||||
* weights for the possible values of the distribution.
|
||||
*/
|
||||
param_type(const std::initializer_list<WeightType>& wl)
|
||||
: _probabilities(wl)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* If the range is empty, equivalent to the default constructor.
|
||||
* Otherwise, the elements of the range represent
|
||||
* weights for the possible values of the distribution.
|
||||
*/
|
||||
template<class Range>
|
||||
explicit param_type(const Range& range)
|
||||
: _probabilities(boost::begin(range), boost::end(range))
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* If nw is zero, equivalent to the default constructor.
|
||||
* Otherwise, the range of the distribution is [0, nw),
|
||||
* and the weights are found by calling fw with values
|
||||
* evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and
|
||||
* \f$\mbox{xmax} - \delta/2\f$, where
|
||||
* \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$.
|
||||
*/
|
||||
template<class Func>
|
||||
param_type(std::size_t nw, double xmin, double xmax, Func fw)
|
||||
{
|
||||
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) {
|
||||
_probabilities.push_back(fw(xmin + k*delta + delta/2));
|
||||
}
|
||||
normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a vector containing the probabilities of each possible
|
||||
* value of the distribution.
|
||||
*/
|
||||
std::vector<WeightType> probabilities() const
|
||||
{
|
||||
return _probabilities;
|
||||
}
|
||||
|
||||
/** Writes the parameters to a @c std::ostream. */
|
||||
BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
|
||||
{
|
||||
detail::print_vector(os, parm._probabilities);
|
||||
return os;
|
||||
}
|
||||
|
||||
/** Reads the parameters from a @c std::istream. */
|
||||
BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
|
||||
{
|
||||
std::vector<WeightType> temp;
|
||||
detail::read_vector(is, temp);
|
||||
if(is) {
|
||||
parm._probabilities.swap(temp);
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
/** Returns true if the two sets of parameters are the same. */
|
||||
BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
|
||||
{
|
||||
return lhs._probabilities == rhs._probabilities;
|
||||
}
|
||||
/** Returns true if the two sets of parameters are different. */
|
||||
BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
|
||||
private:
|
||||
/// @cond show_private
|
||||
friend class discrete_distribution;
|
||||
explicit param_type(const discrete_distribution& dist)
|
||||
: _probabilities(dist.probabilities())
|
||||
{}
|
||||
void normalize()
|
||||
{
|
||||
WeightType sum =
|
||||
std::accumulate(_probabilities.begin(), _probabilities.end(),
|
||||
static_cast<WeightType>(0));
|
||||
for(typename std::vector<WeightType>::iterator
|
||||
iter = _probabilities.begin(),
|
||||
end = _probabilities.end();
|
||||
iter != end; ++iter)
|
||||
{
|
||||
*iter /= sum;
|
||||
}
|
||||
}
|
||||
std::vector<WeightType> _probabilities;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a new @c discrete_distribution object that has
|
||||
* \f$p(0) = 1\f$ and \f$p(i|i>0) = 0\f$.
|
||||
*/
|
||||
discrete_distribution()
|
||||
{
|
||||
_alias_table.push_back(std::make_pair(static_cast<WeightType>(1),
|
||||
static_cast<IntType>(0)));
|
||||
}
|
||||
/**
|
||||
* Constructs a discrete_distribution from an iterator range.
|
||||
* If @c first == @c last, equivalent to the default constructor.
|
||||
* Otherwise, the values of the range represent weights for the
|
||||
* possible values of the distribution.
|
||||
*/
|
||||
template<class Iter>
|
||||
discrete_distribution(Iter first, Iter last)
|
||||
{
|
||||
init(first, last);
|
||||
}
|
||||
#ifndef BOOST_NO_INITIALIZER_LISTS
|
||||
/**
|
||||
* Constructs a @c discrete_distribution from a @c std::initializer_list.
|
||||
* If the @c initializer_list is empty, equivalent to the default
|
||||
* constructor. Otherwise, the values of the @c initializer_list
|
||||
* represent weights for the possible values of the distribution.
|
||||
* For example, given the distribution
|
||||
*
|
||||
* @code
|
||||
* discrete_distribution<> dist{1, 4, 5};
|
||||
* @endcode
|
||||
*
|
||||
* The probability of a 0 is 1/10, the probability of a 1 is 2/5,
|
||||
* the probability of a 2 is 1/2, and no other values are possible.
|
||||
*/
|
||||
discrete_distribution(std::initializer_list<WeightType> wl)
|
||||
{
|
||||
init(wl.begin(), wl.end());
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* Constructs a discrete_distribution from a Boost.Range range.
|
||||
* If the range is empty, equivalent to the default constructor.
|
||||
* Otherwise, the values of the range represent weights for the
|
||||
* possible values of the distribution.
|
||||
*/
|
||||
template<class Range>
|
||||
explicit discrete_distribution(const Range& range)
|
||||
{
|
||||
init(boost::begin(range), boost::end(range));
|
||||
}
|
||||
/**
|
||||
* Constructs a discrete_distribution that approximates a function.
|
||||
* If nw is zero, equivalent to the default constructor.
|
||||
* Otherwise, the range of the distribution is [0, nw),
|
||||
* and the weights are found by calling fw with values
|
||||
* evenly distributed between \f$\mbox{xmin} + \delta/2\f$ and
|
||||
* \f$\mbox{xmax} - \delta/2\f$, where
|
||||
* \f$\delta = (\mbox{xmax} - \mbox{xmin})/\mbox{nw}\f$.
|
||||
*/
|
||||
template<class Func>
|
||||
discrete_distribution(std::size_t nw, double xmin, double xmax, Func fw)
|
||||
{
|
||||
std::size_t n = (nw == 0) ? 1 : nw;
|
||||
double delta = (xmax - xmin) / n;
|
||||
BOOST_ASSERT(delta > 0);
|
||||
std::vector<WeightType> weights;
|
||||
for(std::size_t k = 0; k < n; ++k) {
|
||||
weights.push_back(fw(xmin + k*delta + delta/2));
|
||||
}
|
||||
init(weights.begin(), weights.end());
|
||||
}
|
||||
/**
|
||||
* Constructs a discrete_distribution from its parameters.
|
||||
*/
|
||||
explicit discrete_distribution(const param_type& parm)
|
||||
{
|
||||
param(parm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value distributed according to the parameters of the
|
||||
* discrete_distribution.
|
||||
*/
|
||||
template<class URNG>
|
||||
IntType operator()(URNG& urng) const
|
||||
{
|
||||
BOOST_ASSERT(!_alias_table.empty());
|
||||
WeightType test = uniform_01<WeightType>()(urng);
|
||||
IntType result = uniform_int<IntType>((min)(), (max)())(urng);
|
||||
if(test < _alias_table[result].first) {
|
||||
return result;
|
||||
} else {
|
||||
return(_alias_table[result].second);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value distributed according to the parameters
|
||||
* specified by param.
|
||||
*/
|
||||
template<class URNG>
|
||||
IntType operator()(URNG& urng, const param_type& parm) const
|
||||
{
|
||||
while(true) {
|
||||
WeightType val = uniform_01<WeightType>()(urng);
|
||||
WeightType sum = 0;
|
||||
std::size_t result = 0;
|
||||
for(typename std::vector<WeightType>::const_iterator
|
||||
iter = parm._probabilities.begin(),
|
||||
end = parm._probabilities.end();
|
||||
iter != end; ++iter, ++result)
|
||||
{
|
||||
sum += *iter;
|
||||
if(sum > val) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the smallest value that the distribution can produce. */
|
||||
result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
|
||||
/** Returns the largest value that the distribution can produce. */
|
||||
result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
{ return static_cast<result_type>(_alias_table.size() - 1); }
|
||||
|
||||
/**
|
||||
* Returns a vector containing the probabilities of each
|
||||
* value of the distribution. For example, given
|
||||
*
|
||||
* @code
|
||||
* discrete_distribution<> dist = { 1, 4, 5 };
|
||||
* std::vector<double> p = dist.param();
|
||||
* @endcode
|
||||
*
|
||||
* the vector, p will contain {0.1, 0.4, 0.5}.
|
||||
*/
|
||||
std::vector<WeightType> probabilities() const
|
||||
{
|
||||
std::vector<WeightType> result(_alias_table.size());
|
||||
const WeightType mean =
|
||||
static_cast<WeightType>(1) / _alias_table.size();
|
||||
std::size_t i = 0;
|
||||
for(typename alias_table_t::const_iterator
|
||||
iter = _alias_table.begin(),
|
||||
end = _alias_table.end();
|
||||
iter != end; ++iter, ++i)
|
||||
{
|
||||
WeightType val = iter->first * mean;
|
||||
result[i] += val;
|
||||
result[iter->second] += mean - val;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
/** Returns the parameters of the distribution. */
|
||||
param_type param() const
|
||||
{
|
||||
return param_type(*this);
|
||||
}
|
||||
/** Sets the parameters of the distribution. */
|
||||
void param(const param_type& parm)
|
||||
{
|
||||
init(parm._probabilities.begin(), parm._probabilities.end());
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: Subsequent uses of the distribution do not depend
|
||||
* on values produced by any engine prior to invoking reset.
|
||||
*/
|
||||
void reset() {}
|
||||
|
||||
/** Writes a distribution to a @c std::ostream. */
|
||||
BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, discrete_distribution, dd)
|
||||
{
|
||||
os << dd.param();
|
||||
return os;
|
||||
}
|
||||
|
||||
/** Reads a distribution from a @c std::istream */
|
||||
BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, discrete_distribution, dd)
|
||||
{
|
||||
param_type parm;
|
||||
if(is >> parm) {
|
||||
dd.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(discrete_distribution, lhs, rhs)
|
||||
{
|
||||
return lhs._alias_table == rhs._alias_table;
|
||||
}
|
||||
/**
|
||||
* Returns true if the two distributions may return different
|
||||
* sequences of values, when passed equal generators.
|
||||
*/
|
||||
BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(discrete_distribution)
|
||||
|
||||
private:
|
||||
|
||||
/// @cond show_private
|
||||
|
||||
template<class Iter>
|
||||
void init(Iter first, Iter last, std::input_iterator_tag)
|
||||
{
|
||||
std::vector<WeightType> temp(first, last);
|
||||
init(temp.begin(), temp.end());
|
||||
}
|
||||
template<class Iter>
|
||||
void init(Iter first, Iter last, std::forward_iterator_tag)
|
||||
{
|
||||
std::vector<std::pair<WeightType, IntType> > below_average;
|
||||
std::vector<std::pair<WeightType, IntType> > above_average;
|
||||
std::size_t size = std::distance(first, last);
|
||||
WeightType weight_sum =
|
||||
std::accumulate(first, last, static_cast<WeightType>(0));
|
||||
WeightType weight_average = weight_sum / size;
|
||||
std::size_t i = 0;
|
||||
for(; first != last; ++first, ++i) {
|
||||
WeightType val = *first / weight_average;
|
||||
std::pair<WeightType, IntType> elem(val, static_cast<IntType>(i));
|
||||
if(val < static_cast<WeightType>(1)) {
|
||||
below_average.push_back(elem);
|
||||
} else {
|
||||
above_average.push_back(elem);
|
||||
}
|
||||
}
|
||||
|
||||
_alias_table.resize(size);
|
||||
typename alias_table_t::iterator
|
||||
b_iter = below_average.begin(),
|
||||
b_end = below_average.end(),
|
||||
a_iter = above_average.begin(),
|
||||
a_end = above_average.end()
|
||||
;
|
||||
while(b_iter != b_end && a_iter != a_end) {
|
||||
_alias_table[b_iter->second] =
|
||||
std::make_pair(b_iter->first, a_iter->second);
|
||||
a_iter->first -= (static_cast<WeightType>(1) - b_iter->first);
|
||||
if(a_iter->first < static_cast<WeightType>(1)) {
|
||||
*b_iter = *a_iter++;
|
||||
} else {
|
||||
++b_iter;
|
||||
}
|
||||
}
|
||||
for(; b_iter != b_end; ++b_iter) {
|
||||
_alias_table[b_iter->second].first = static_cast<WeightType>(1);
|
||||
}
|
||||
for(; a_iter != a_end; ++a_iter) {
|
||||
_alias_table[a_iter->second].first = static_cast<WeightType>(1);
|
||||
}
|
||||
}
|
||||
template<class Iter>
|
||||
void init(Iter first, Iter last)
|
||||
{
|
||||
if(first == last) {
|
||||
_alias_table.clear();
|
||||
_alias_table.push_back(std::make_pair(static_cast<WeightType>(1),
|
||||
static_cast<IntType>(0)));
|
||||
} else {
|
||||
typename std::iterator_traits<Iter>::iterator_category category;
|
||||
init(first, last, category);
|
||||
}
|
||||
}
|
||||
typedef std::vector<std::pair<WeightType, IntType> > alias_table_t;
|
||||
alias_table_t _alias_table;
|
||||
/// @endcond
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/random/detail/enable_warnings.hpp>
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user