$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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);
+    }
+}