|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r67740 - in trunk: boost/random boost/random/detail libs/random/test
From: steven_at_[hidden]
Date: 2011-01-06 18:51:47
Author: steven_watanabe
Date: 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
New Revision: 67740
URL: http://svn.boost.org/trac/boost/changeset/67740
Log:
Implement piecewise_constant_distribution.
Added:
trunk/boost/random/detail/vector_io.hpp (contents, props changed)
trunk/boost/random/piecewise_constant_distribution.hpp (contents, props changed)
trunk/libs/random/test/test_piecewise_constant.cpp (contents, props changed)
trunk/libs/random/test/test_piecewise_constant_distribution.cpp (contents, props changed)
Text files modified:
trunk/boost/random/discrete_distribution.hpp | 129 ++++++++++-----------------------------
trunk/libs/random/test/Jamfile.v2 | 2
2 files changed, 35 insertions(+), 96 deletions(-)
Added: trunk/boost/random/detail/vector_io.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/random/detail/vector_io.hpp 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -0,0 +1,75 @@
+/* boost random/vector_io.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_DETAIL_VECTOR_IO_HPP
+#define BOOST_RANDOM_DETAIL_VECTOR_IO_HPP
+
+#include <vector>
+#include <iosfwd>
+#include <istream>
+
+namespace boost {
+namespace random {
+namespace detail {
+
+template<class CharT, class Traits, class T>
+void print_vector(std::basic_ostream<CharT, Traits>& os,
+ const std::vector<T>& vec)
+{
+ typename std::vector<T>::const_iterator
+ iter = vec.begin(),
+ end = vec.end();
+ os << '[';
+ if(iter != end) {
+ os << *iter;
+ ++iter;
+ for(; iter != end; ++iter)
+ {
+ os << ' ' << *iter;
+ }
+ }
+ os << ']';
+}
+
+template<class CharT, class Traits, class T>
+void read_vector(std::basic_istream<CharT, Traits>& is, std::vector<T>& vec)
+{
+ char ch;
+ if(!(is >> ch)) {
+ return;
+ }
+ if(ch != '[') {
+ is.putback(ch);
+ is.setstate(std::ios_base::failbit);
+ return;
+ }
+ T val;
+ while(is >> std::ws >> val) {
+ vec.push_back(val);
+ }
+ if(is.fail()) {
+ is.clear();
+ if(!(is >> ch)) {
+ return;
+ }
+ if(ch != ']') {
+ is.putback(ch);
+ is.setstate(std::ios_base::failbit);
+ }
+ }
+}
+
+}
+}
+}
+
+#endif // BOOST_RANDOM_DETAIL_VECTOR_IO_HPP
Modified: trunk/boost/random/discrete_distribution.hpp
==============================================================================
--- trunk/boost/random/discrete_distribution.hpp (original)
+++ trunk/boost/random/discrete_distribution.hpp 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -1,11 +1,14 @@
-// discrete_distribution.hpp
-//
-// Copyright (c) 2009-2010
-// Steven Watanabe
-//
-// 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)
+/* 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$
+ */
#ifndef BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
#define BOOST_RANDOM_DISCRETE_DISTRIBUTION_HPP_INCLUDED
@@ -19,6 +22,8 @@
#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>
@@ -112,37 +117,31 @@
return _probabilities;
}
-#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
/** Writes the parameters to a @c std::ostream. */
- template<class CharT, class Traits>
- friend std::basic_ostream<CharT, Traits>&
- operator<<(std::basic_ostream<CharT, Traits>& os,
- const param_type& parm)
+ BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
{
- parm.print(os);
+ detail::print_vector(os, parm._probabilities);
return os;
}
/** Reads the parameters from a @c std::istream. */
- template<class CharT, class Traits>
- friend std::basic_istream<CharT, Traits>&
- operator>>(std::basic_istream<CharT, Traits>& is, param_type& parm)
+ BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
{
- parm.read(is);
+ std::vector<WeightType> temp;
+ detail::read_vector(is, temp);
+ if(is) {
+ parm._probabilities.swap(temp);
+ }
return is;
}
-#endif
/** Returns true if the two sets of parameters are the same. */
- friend bool operator==(const param_type& lhs, const param_type& rhs)
+ BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
{
return lhs._probabilities == rhs._probabilities;
}
/** Returns true if the two sets of parameters are different. */
- friend bool operator!=(const param_type& lhs, const param_type& rhs)
- {
- return !(lhs == rhs);
- }
+ BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
private:
/// @cond
friend class discrete_distribution;
@@ -162,52 +161,6 @@
*iter /= sum;
}
}
- template<class CharT, class Traits>
- void print(std::basic_ostream<CharT, Traits>& os) const
- {
- typename std::vector<WeightType>::const_iterator
- iter = _probabilities.begin(),
- end = _probabilities.end();
- os << '[';
- if(iter != end) {
- os << *iter;
- ++iter;
- for(; iter != end; ++iter)
- {
- os << ' ' << *iter;
- }
- }
- os << ']';
- }
- template<class CharT, class Traits>
- void read(std::basic_istream<CharT, Traits>& is)
- {
- std::vector<WeightType> result;
- char ch;
- if(!(is >> ch)) {
- return;
- }
- if(ch != '[') {
- is.putback(ch);
- is.setstate(std::ios_base::failbit);
- return;
- }
- WeightType val;
- while(is >> std::ws >> val) {
- result.push_back(val);
- }
- if(is.fail()) {
- is.clear();
- if(!(is >> ch)) {
- return;
- }
- if(ch != ']') {
- is.putback(ch);
- is.setstate(std::ios_base::failbit);
- }
- }
- _probabilities.swap(result);
- }
std::vector<WeightType> _probabilities;
/// @endcond
};
@@ -297,7 +250,8 @@
* discrete_distribution.
*/
template<class URNG>
- IntType operator()(URNG& urng) const {
+ IntType operator()(URNG& urng) const
+ {
assert(!_alias_table.empty());
WeightType test = uniform_01<WeightType>()(urng);
IntType result = uniform_int<IntType>((min)(), (max)())(urng);
@@ -384,33 +338,28 @@
*/
void reset() {}
-#ifndef BOOST_RANDOM_NO_STREAM_OPERATORS
/** Writes a distribution to a @c std::ostream. */
- template<class CharT, class Traits>
- friend std::basic_ostream<CharT, Traits>&
- operator<<(std::basic_ostream<CharT, Traits>& os,
- const discrete_distribution& dd)
+ BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, discrete_distribution, dd)
{
os << dd.param();
return os;
}
/** Reads a distribution from a @c std::istream */
- template<class CharT, class Traits>
- friend std::basic_istream<CharT, Traits>&
- operator>>(std::basic_istream<CharT, Traits>& is, discrete_distribution& dd)
+ BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, discrete_distribution, dd)
{
- dd.read(is);
+ param_type parm;
+ if(is >> parm) {
+ dd.param(parm);
+ }
return is;
}
-#endif
/**
* Returns true if the two distributions will return the
* same sequence of values, when passed equal generators.
*/
- friend bool operator==(const discrete_distribution& lhs,
- const discrete_distribution& rhs)
+ BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(discrete_distribution, lhs, rhs)
{
return lhs._alias_table == rhs._alias_table;
}
@@ -418,24 +367,12 @@
* Returns true if the two distributions may return different
* sequences of values, when passed equal generators.
*/
- friend bool operator!=(const discrete_distribution& lhs,
- const discrete_distribution& rhs)
- {
- return !(lhs == rhs);
- }
+ BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(discrete_distribution)
private:
/// @cond
- template<class CharT, class Traits>
- void read(std::basic_istream<CharT, Traits>& is) {
- param_type parm;
- if(is >> parm) {
- param(parm);
- }
- }
-
template<class Iter>
void init(Iter first, Iter last, std::input_iterator_tag)
{
Added: trunk/boost/random/piecewise_constant_distribution.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/random/piecewise_constant_distribution.hpp 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -0,0 +1,469 @@
+/* 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 <cassert>
+#include <numeric>
+#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_INITIALIZER_LISTS
+#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 RealType input_type;
+ typedef RealType result_type;
+
+ class param_type {
+ public:
+ /**
+ * 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));
+ } 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_INITIALIZER_LISTS
+ /**
+ * 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 F>
+ param_type(const std::initializer_list<RealType>& il, F f)
+ : _intervals(il)
+ {
+ if(_intervals.size() < 2) {
+ _intervals.clear();
+ _intervals.push_back(RealType(0));
+ _intervals.push_back(RealType(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));
+ }
+ }
+
+ /**
+ * 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;
+ 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<WeightType> densities() const
+ {
+ WeightType sum = std::accumulate(_weights.begin(), _weights.end(),
+ static_cast<WeightType>(0));
+ std::vector<WeightType> 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:
+
+ /// @cond
+
+ friend class piecewise_constant_distribution;
+
+ std::vector<RealType> _intervals;
+ std::vector<WeightType> _weights;
+
+ /// @endcond
+ };
+
+ /**
+ * 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_INITIALIZER_LISTS
+ /**
+ * 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 F>
+ piecewise_constant_distribution(std::initializer_list<RealType> il, F f)
+ : _intervals(il)
+ {
+ 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<WeightType> densities() const
+ {
+ std::vector<WeightType> 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, RealType> 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:
+
+ /// @cond
+
+ discrete_distribution<std::size_t, WeightType> _bins;
+ std::vector<RealType> _intervals;
+
+ /// @endcond
+};
+
+}
+}
+
+#endif
Modified: trunk/libs/random/test/Jamfile.v2
==============================================================================
--- trunk/libs/random/test/Jamfile.v2 (original)
+++ trunk/libs/random/test/Jamfile.v2 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -68,6 +68,8 @@
run test_student_t_distribution.cpp /boost//unit_test_framework ;
run test_normal.cpp ;
run test_normal_distribution.cpp /boost//unit_test_framework ;
+run test_piecewise_constant.cpp ;
+run test_piecewise_constant_distribution.cpp /boost//unit_test_framework ;
# run nondet_random_speed.cpp ;
# run random_device.cpp ;
Added: trunk/libs/random/test/test_piecewise_constant.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/random/test/test_piecewise_constant.cpp 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -0,0 +1,127 @@
+/* test_piecewise_constant.cpp
+ *
+ * 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)
+ *
+ * $Id$
+ *
+ */
+
+#include <boost/random/piecewise_constant_distribution.hpp>
+#include <boost/random/uniform_int.hpp>
+#include <boost/random/mersenne_twister.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/exception/diagnostic_information.hpp>
+#include <vector>
+#include <iostream>
+#include <numeric>
+
+#include "chi_squared_test.hpp"
+
+bool do_test(int n, long long max) {
+ std::cout << "running piecewise_constant(p0, p1, ..., p" << n-1 << ")" << " " << max << " times: " << std::flush;
+
+ std::vector<double> expected;
+ {
+ boost::mt19937 egen;
+ for(int i = 0; i < n; ++i) {
+ expected.push_back(egen());
+ }
+ double sum = std::accumulate(expected.begin(), expected.end(), 0.0);
+ for(std::vector<double>::iterator iter = expected.begin(), end = expected.end(); iter != end; ++iter) {
+ *iter /= sum;
+ }
+ }
+ std::vector<double> intervals;
+ for(int i = 0; i <= n; ++i) {
+ intervals.push_back(i);
+ }
+
+ boost::random::piecewise_constant_distribution<> dist(intervals, expected);
+ boost::mt19937 gen;
+ std::vector<long long> results(expected.size());
+ for(long long i = 0; i < max; ++i) {
+ ++results[static_cast<std::size_t>(dist(gen))];
+ }
+
+ long long sum = std::accumulate(results.begin(), results.end(), 0ll);
+ if(sum != max) {
+ std::cout << "*** Failed: incorrect total: " << sum << " ***" << std::endl;
+ return false;
+ }
+ double chsqr = chi_squared_test(results, expected, max);
+
+ bool result = chsqr < 0.99;
+ const char* err = result? "" : "*";
+ std::cout << std::setprecision(17) << chsqr << err << std::endl;
+
+ std::cout << std::setprecision(6);
+
+ return result;
+}
+
+bool do_tests(int repeat, int max_n, long long trials) {
+ boost::mt19937 gen;
+ boost::uniform_int<> idist(1, max_n);
+ int errors = 0;
+ for(int i = 0; i < repeat; ++i) {
+ if(!do_test(idist(gen), trials)) {
+ ++errors;
+ }
+ }
+ if(errors != 0) {
+ std::cout << "*** " << errors << " errors detected ***" << std::endl;
+ }
+ return errors == 0;
+}
+
+int usage() {
+ std::cerr << "Usage: test_piecewise_constant -r <repeat> -n <max n> -t <trials>" << std::endl;
+ return 2;
+}
+
+template<class T>
+bool handle_option(int& argc, char**& argv, char opt, T& value) {
+ if(argv[0][1] == opt && argc > 1) {
+ --argc;
+ ++argv;
+ value = boost::lexical_cast<T>(argv[0]);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+int main(int argc, char** argv) {
+ int repeat = 10;
+ int max_n = 100000;
+ long long trials = 1000000ll;
+
+ if(argc > 0) {
+ --argc;
+ ++argv;
+ }
+ while(argc > 0) {
+ if(argv[0][0] != '-') return usage();
+ else if(!handle_option(argc, argv, 'r', repeat)
+ && !handle_option(argc, argv, 'n', max_n)
+ && !handle_option(argc, argv, 't', trials)) {
+ return usage();
+ }
+ --argc;
+ ++argv;
+ }
+
+ try {
+ if(do_tests(repeat, max_n, trials)) {
+ return 0;
+ } else {
+ return EXIT_FAILURE;
+ }
+ } catch(...) {
+ std::cerr << boost::current_exception_diagnostic_information() << std::endl;
+ return EXIT_FAILURE;
+ }
+}
Added: trunk/libs/random/test/test_piecewise_constant_distribution.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/random/test/test_piecewise_constant_distribution.cpp 2011-01-06 18:51:46 EST (Thu, 06 Jan 2011)
@@ -0,0 +1,193 @@
+/* test_piecewise_constant_distribution.cpp
+ *
+ * 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)
+ *
+ * $Id$
+ *
+ */
+
+#include <boost/random/piecewise_constant_distribution.hpp>
+#include <boost/random/linear_congruential.hpp>
+#include <boost/assign/list_of.hpp>
+#include <sstream>
+#include <vector>
+
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
+
+struct gen {
+ double operator()(double arg) {
+ if(arg < 100) return 100;
+ else if(arg < 103) return 1;
+ else if(arg < 107) return 2;
+ else if(arg < 111) return 1;
+ else if(arg < 114) return 4;
+ else return 100;
+ }
+};
+
+#define CHECK_SEQUENCE(actual, expected) \
+ do { \
+ std::vector<double> _actual = (actual); \
+ std::vector<double> _expected = (expected); \
+ BOOST_CHECK_EQUAL_COLLECTIONS( \
+ _actual.begin(), _actual.end(), \
+ _expected.begin(), _expected.end()); \
+ } while(false)
+
+using boost::assign::list_of;
+
+BOOST_AUTO_TEST_CASE(test_constructors) {
+ boost::random::piecewise_constant_distribution<> dist;
+ CHECK_SEQUENCE(dist.densities(), list_of(1.0));
+ CHECK_SEQUENCE(dist.intervals(), list_of(0.0)(1.0));
+
+#ifndef BOOST_NO_INITIALIZER_LISTS
+ boost::random::piecewise_constant_distribution<> dist_il = {
+ { 99, 103, 107, 111, 115 },
+ gen()
+ };
+ CHECK_SEQUENCE(dist_il.intervals(), list_of(99)(103)(107)(111)(115));
+ CHECK_SEQUENCE(dist_il.densities(), list_of(.03125)(.0625)(.03125)(.125));
+#endif
+ std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5);
+ std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4);
+
+ boost::random::piecewise_constant_distribution<> dist_r(intervals, weights);
+ CHECK_SEQUENCE(dist_r.intervals(), list_of(0)(1)(2)(3)(5));
+ CHECK_SEQUENCE(dist_r.densities(), list_of(.125)(.25)(.125)(.25));
+
+ boost::random::piecewise_constant_distribution<> dist_it(
+ intervals.begin(), intervals.end(), weights.begin());
+ CHECK_SEQUENCE(dist_it.intervals(), list_of(0)(1)(2)(3)(5));
+ CHECK_SEQUENCE(dist_it.densities(), list_of(.125)(.25)(.125)(.25));
+
+ boost::random::piecewise_constant_distribution<> dist_fun(4, 99,115, gen());
+ CHECK_SEQUENCE(dist_fun.intervals(), list_of(99)(103)(107)(111)(115));
+ CHECK_SEQUENCE(dist_fun.densities(), list_of(.03125)(.0625)(.03125)(.125));
+
+ boost::random::piecewise_constant_distribution<> copy(dist);
+ BOOST_CHECK_EQUAL(dist, copy);
+ boost::random::piecewise_constant_distribution<> copy_r(dist_r);
+ BOOST_CHECK_EQUAL(dist_r, copy_r);
+
+ boost::random::piecewise_constant_distribution<> notpow2(3, 99, 111, gen());
+ BOOST_REQUIRE_EQUAL(notpow2.densities().size(), 3u);
+ BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[0], 0.0625, 0.00000000001);
+ BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[1], 0.125, 0.00000000001);
+ BOOST_CHECK_CLOSE_FRACTION(notpow2.densities()[2], 0.0625, 0.00000000001);
+ boost::random::piecewise_constant_distribution<> copy_notpow2(notpow2);
+ BOOST_CHECK_EQUAL(notpow2, copy_notpow2);
+}
+
+BOOST_AUTO_TEST_CASE(test_param) {
+ std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5);
+ std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4);
+ boost::random::piecewise_constant_distribution<> dist(intervals, weights);
+ boost::random::piecewise_constant_distribution<>::param_type
+ param = dist.param();
+ CHECK_SEQUENCE(param.intervals(), list_of(0)(1)(2)(3)(5));
+ CHECK_SEQUENCE(param.densities(), list_of(.125)(.25)(.125)(.25));
+ boost::random::piecewise_constant_distribution<> copy1(param);
+ BOOST_CHECK_EQUAL(dist, copy1);
+ boost::random::piecewise_constant_distribution<> copy2;
+ copy2.param(param);
+ BOOST_CHECK_EQUAL(dist, copy2);
+
+ boost::random::piecewise_constant_distribution<>::param_type
+ param_copy = param;
+ BOOST_CHECK_EQUAL(param, param_copy);
+ BOOST_CHECK(param == param_copy);
+ BOOST_CHECK(!(param != param_copy));
+ boost::random::piecewise_constant_distribution<>::param_type param_default;
+ CHECK_SEQUENCE(param_default.intervals(), list_of(0.0)(1.0));
+ CHECK_SEQUENCE(param_default.densities(), list_of(1.0));
+ BOOST_CHECK(param != param_default);
+ BOOST_CHECK(!(param == param_default));
+
+#ifndef BOOST_NO_INITIALIZER_LISTS
+ boost::random::piecewise_constant_distribution<>::param_type parm_il = {
+ { 99, 103, 107, 111, 115 },
+ gen()
+ };
+ CHECK_SEQUENCE(param_il.intervals(), list_of(99)(103)(107)(111)(115));
+ CHECK_SEQUENCE(param_il.densities(), list_of(.03125)(.0625)(.03125)(.125));
+#endif
+
+ boost::random::piecewise_constant_distribution<>::param_type
+ parm_r(intervals, weights);
+ CHECK_SEQUENCE(parm_r.intervals(), list_of(0)(1)(2)(3)(5));
+ CHECK_SEQUENCE(parm_r.densities(), list_of(.125)(.25)(.125)(.25));
+
+ boost::random::piecewise_constant_distribution<>::param_type
+ parm_it(intervals.begin(), intervals.end(), weights.begin());
+ CHECK_SEQUENCE(parm_it.intervals(), list_of(0)(1)(2)(3)(5));
+ CHECK_SEQUENCE(parm_it.densities(), list_of(.125)(.25)(.125)(.25));
+
+ boost::random::piecewise_constant_distribution<>::param_type
+ parm_fun(4, 99, 115, gen());
+ CHECK_SEQUENCE(parm_fun.intervals(), list_of(99)(103)(107)(111)(115));
+ CHECK_SEQUENCE(parm_fun.densities(), list_of(.03125)(.0625)(.03125)(.125));
+}
+
+BOOST_AUTO_TEST_CASE(test_min_max) {
+ std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5);
+ std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4);
+ boost::random::piecewise_constant_distribution<> dist;
+ BOOST_CHECK_EQUAL((dist.min)(), 0.0);
+ BOOST_CHECK_EQUAL((dist.max)(), 1.0);
+ boost::random::piecewise_constant_distribution<> dist_r(intervals, weights);
+ BOOST_CHECK_EQUAL((dist_r.min)(), 0.0);
+ BOOST_CHECK_EQUAL((dist_r.max)(), 5.0);
+}
+
+BOOST_AUTO_TEST_CASE(test_comparison) {
+ std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5);
+ std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4);
+ boost::random::piecewise_constant_distribution<> dist;
+ boost::random::piecewise_constant_distribution<> dist_copy(dist);
+ boost::random::piecewise_constant_distribution<> dist_r(intervals, weights);
+ boost::random::piecewise_constant_distribution<> dist_r_copy(dist_r);
+ BOOST_CHECK(dist == dist_copy);
+ BOOST_CHECK(!(dist != dist_copy));
+ BOOST_CHECK(dist_r == dist_r_copy);
+ BOOST_CHECK(!(dist_r != dist_r_copy));
+ BOOST_CHECK(dist != dist_r);
+ BOOST_CHECK(!(dist == dist_r));
+}
+
+BOOST_AUTO_TEST_CASE(test_streaming) {
+ std::vector<double> intervals = boost::assign::list_of(0)(1)(2)(3)(5);
+ std::vector<double> weights = boost::assign::list_of(1)(2)(1)(4);
+ boost::random::piecewise_constant_distribution<> dist(intervals, weights);
+ std::stringstream stream;
+ stream << dist;
+ boost::random::piecewise_constant_distribution<> restored_dist;
+ stream >> restored_dist;
+ BOOST_CHECK_EQUAL(dist, restored_dist);
+}
+
+BOOST_AUTO_TEST_CASE(test_generation) {
+ std::vector<double> intervals = boost::assign::list_of(1)(2);
+ std::vector<double> weights = boost::assign::list_of(1);
+ boost::minstd_rand0 gen;
+ boost::random::piecewise_constant_distribution<> dist;
+ boost::random::piecewise_constant_distribution<> dist_r(intervals, weights);
+ for(int i = 0; i < 10; ++i) {
+ double value = dist(gen);
+ BOOST_CHECK_GE(value, 0.0);
+ BOOST_CHECK_LT(value, 1.0);
+ double value_r = dist_r(gen);
+ BOOST_CHECK_GE(value_r, 1.0);
+ BOOST_CHECK_LT(value_r, 2.0);
+ double value_param = dist_r(gen, dist.param());
+ BOOST_CHECK_GE(value_param, 0.0);
+ BOOST_CHECK_LT(value_param, 1.0);
+ double value_r_param = dist(gen, dist_r.param());
+ BOOST_CHECK_GE(value_r_param, 1.0);
+ BOOST_CHECK_LT(value_r_param, 2.0);
+ }
+}
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk