467 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			467 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| /* 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
 | 
