Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-17 08:49:57

0001 /* boost random/piecewise_constant_distribution.hpp header file
0002  *
0003  * Copyright Steven Watanabe 2011
0004  * Distributed under the Boost Software License, Version 1.0. (See
0005  * accompanying file LICENSE_1_0.txt or copy at
0006  * http://www.boost.org/LICENSE_1_0.txt)
0007  *
0008  * See http://www.boost.org for most recent version including documentation.
0009  *
0010  * $Id$
0011  */
0012 
0013 #ifndef BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED
0014 #define BOOST_RANDOM_PIECEWISE_CONSTANT_DISTRIBUTION_HPP_INCLUDED
0015 
0016 #include <vector>
0017 #include <numeric>
0018 #include <boost/assert.hpp>
0019 #include <boost/random/uniform_real.hpp>
0020 #include <boost/random/discrete_distribution.hpp>
0021 #include <boost/random/detail/config.hpp>
0022 #include <boost/random/detail/operators.hpp>
0023 #include <boost/random/detail/vector_io.hpp>
0024 
0025 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
0026 #include <initializer_list>
0027 #endif
0028 
0029 namespace boost {
0030 namespace random {
0031 
0032 /**
0033  * The class @c piecewise_constant_distribution models a \random_distribution.
0034  */
0035 template<class RealType = double, class WeightType = double>
0036 class piecewise_constant_distribution {
0037 public:
0038     typedef std::size_t input_type;
0039     typedef RealType result_type;
0040 
0041     class param_type {
0042     public:
0043 
0044         typedef piecewise_constant_distribution distribution_type;
0045 
0046         /**
0047          * Constructs a @c param_type object, representing a distribution
0048          * that produces values uniformly distributed in the range [0, 1).
0049          */
0050         param_type()
0051         {
0052             _weights.push_back(WeightType(1));
0053             _intervals.push_back(RealType(0));
0054             _intervals.push_back(RealType(1));
0055         }
0056         /**
0057          * Constructs a @c param_type object from two iterator ranges
0058          * containing the interval boundaries and the interval weights.
0059          * If there are less than two boundaries, then this is equivalent to
0060          * the default constructor and creates a single interval, [0, 1).
0061          *
0062          * The values of the interval boundaries must be strictly
0063          * increasing, and the number of weights must be one less than
0064          * the number of interval boundaries.  If there are extra
0065          * weights, they are ignored.
0066          */
0067         template<class IntervalIter, class WeightIter>
0068         param_type(IntervalIter intervals_first, IntervalIter intervals_last,
0069                    WeightIter weight_first)
0070           : _intervals(intervals_first, intervals_last)
0071         {
0072             if(_intervals.size() < 2) {
0073                 _intervals.clear();
0074                 _intervals.push_back(RealType(0));
0075                 _intervals.push_back(RealType(1));
0076                 _weights.push_back(WeightType(1));
0077             } else {
0078                 _weights.reserve(_intervals.size() - 1);
0079                 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) {
0080                     _weights.push_back(*weight_first++);
0081                 }
0082             }
0083         }
0084 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
0085         /**
0086          * Constructs a @c param_type object from an
0087          * initializer_list containing the interval boundaries
0088          * and a unary function specifying the weights.  Each
0089          * weight is determined by calling the function at the
0090          * midpoint of the corresponding interval.
0091          *
0092          * If the initializer_list contains less than two elements,
0093          * this is equivalent to the default constructor and the
0094          * distribution will produce values uniformly distributed
0095          * in the range [0, 1).
0096          */
0097         template<class T, class F>
0098         param_type(const std::initializer_list<T>& il, F f)
0099           : _intervals(il.begin(), il.end())
0100         {
0101             if(_intervals.size() < 2) {
0102                 _intervals.clear();
0103                 _intervals.push_back(RealType(0));
0104                 _intervals.push_back(RealType(1));
0105                 _weights.push_back(WeightType(1));
0106             } else {
0107                 _weights.reserve(_intervals.size() - 1);
0108                 for(std::size_t i = 0; i < _intervals.size() - 1; ++i) {
0109                     RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2;
0110                     _weights.push_back(f(midpoint));
0111                 }
0112             }
0113         }
0114 #endif
0115         /**
0116          * Constructs a @c param_type object from Boost.Range
0117          * ranges holding the interval boundaries and the weights.  If
0118          * there are less than two interval boundaries, this is equivalent
0119          * to the default constructor and the distribution will produce
0120          * values uniformly distributed in the range [0, 1).  The
0121          * number of weights must be one less than the number of
0122          * interval boundaries.
0123          */
0124         template<class IntervalRange, class WeightRange>
0125         param_type(const IntervalRange& intervals_arg,
0126                    const WeightRange& weights_arg)
0127           : _intervals(std::begin(intervals_arg), std::end(intervals_arg)),
0128             _weights(std::begin(weights_arg), std::end(weights_arg))
0129         {
0130             if(_intervals.size() < 2) {
0131                 _intervals.clear();
0132                 _intervals.push_back(RealType(0));
0133                 _intervals.push_back(RealType(1));
0134                 _weights.push_back(WeightType(1));
0135             }
0136         }
0137 
0138         /**
0139          * Constructs the parameters for a distribution that approximates a
0140          * function.  The range of the distribution is [xmin, xmax).  This
0141          * range is divided into nw equally sized intervals and the weights
0142          * are found by calling the unary function f on the midpoints of the
0143          * intervals.
0144          */
0145         template<class F>
0146         param_type(std::size_t nw, RealType xmin, RealType xmax, F f)
0147         {
0148             std::size_t n = (nw == 0) ? 1 : nw;
0149             double delta = (xmax - xmin) / n;
0150             BOOST_ASSERT(delta > 0);
0151             for(std::size_t k = 0; k < n; ++k) {
0152                 _weights.push_back(f(xmin + k*delta + delta/2));
0153                 _intervals.push_back(xmin + k*delta);
0154             }
0155             _intervals.push_back(xmax);
0156         }
0157 
0158         /**  Returns a vector containing the interval boundaries. */
0159         std::vector<RealType> intervals() const { return _intervals; }
0160 
0161         /**
0162          * Returns a vector containing the probability densities
0163          * over all the intervals of the distribution.
0164          */
0165         std::vector<RealType> densities() const
0166         {
0167             RealType sum = std::accumulate(_weights.begin(), _weights.end(),
0168                                              static_cast<RealType>(0));
0169             std::vector<RealType> result;
0170             result.reserve(_weights.size());
0171             for(std::size_t i = 0; i < _weights.size(); ++i) {
0172                 RealType width = _intervals[i + 1] - _intervals[i];
0173                 result.push_back(_weights[i] / (sum * width));
0174             }
0175             return result;
0176         }
0177 
0178         /** Writes the parameters to a @c std::ostream. */
0179         BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(os, param_type, parm)
0180         {
0181             detail::print_vector(os, parm._intervals);
0182             detail::print_vector(os, parm._weights);
0183             return os;
0184         }
0185 
0186         /** Reads the parameters from a @c std::istream. */
0187         BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(is, param_type, parm)
0188         {
0189             std::vector<RealType> new_intervals;
0190             std::vector<WeightType> new_weights;
0191             detail::read_vector(is, new_intervals);
0192             detail::read_vector(is, new_weights);
0193             if(is) {
0194                 parm._intervals.swap(new_intervals);
0195                 parm._weights.swap(new_weights);
0196             }
0197             return is;
0198         }
0199 
0200         /** Returns true if the two sets of parameters are the same. */
0201         BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(param_type, lhs, rhs)
0202         {
0203             return lhs._intervals == rhs._intervals
0204                 && lhs._weights == rhs._weights;
0205         }
0206         /** Returns true if the two sets of parameters are different. */
0207         BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(param_type)
0208 
0209     private:
0210 
0211         friend class piecewise_constant_distribution;
0212 
0213         std::vector<RealType> _intervals;
0214         std::vector<WeightType> _weights;
0215     };
0216 
0217     /**
0218      * Creates a new @c piecewise_constant_distribution with
0219      * a single interval, [0, 1).
0220      */
0221     piecewise_constant_distribution()
0222     {
0223         _intervals.push_back(RealType(0));
0224         _intervals.push_back(RealType(1));
0225     }
0226     /**
0227      * Constructs a piecewise_constant_distribution from two iterator ranges
0228      * containing the interval boundaries and the interval weights.
0229      * If there are less than two boundaries, then this is equivalent to
0230      * the default constructor and creates a single interval, [0, 1).
0231      *
0232      * The values of the interval boundaries must be strictly
0233      * increasing, and the number of weights must be one less than
0234      * the number of interval boundaries.  If there are extra
0235      * weights, they are ignored.
0236      *
0237      * For example,
0238      *
0239      * @code
0240      * double intervals[] = { 0.0, 1.0, 4.0 };
0241      * double weights[] = { 1.0, 1.0 };
0242      * piecewise_constant_distribution<> dist(
0243      *     &intervals[0], &intervals[0] + 3, &weights[0]);
0244      * @endcode
0245      *
0246      * The distribution has a 50% chance of producing a
0247      * value between 0 and 1 and a 50% chance of producing
0248      * a value between 1 and 4.
0249      */
0250     template<class IntervalIter, class WeightIter>
0251     piecewise_constant_distribution(IntervalIter first_interval,
0252                                     IntervalIter last_interval,
0253                                     WeightIter first_weight)
0254       : _intervals(first_interval, last_interval)
0255     {
0256         if(_intervals.size() < 2) {
0257             _intervals.clear();
0258             _intervals.push_back(RealType(0));
0259             _intervals.push_back(RealType(1));
0260         } else {
0261             std::vector<WeightType> actual_weights;
0262             actual_weights.reserve(_intervals.size() - 1);
0263             for(std::size_t i = 0; i < _intervals.size() - 1; ++i) {
0264                 actual_weights.push_back(*first_weight++);
0265             }
0266             typedef discrete_distribution<std::size_t, WeightType> bins_type;
0267             typename bins_type::param_type bins_param(actual_weights);
0268             _bins.param(bins_param);
0269         }
0270     }
0271 #ifndef BOOST_NO_CXX11_HDR_INITIALIZER_LIST
0272     /**
0273      * Constructs a piecewise_constant_distribution from an
0274      * initializer_list containing the interval boundaries
0275      * and a unary function specifying the weights.  Each
0276      * weight is determined by calling the function at the
0277      * midpoint of the corresponding interval.
0278      *
0279      * If the initializer_list contains less than two elements,
0280      * this is equivalent to the default constructor and the
0281      * distribution will produce values uniformly distributed
0282      * in the range [0, 1).
0283      */
0284     template<class T, class F>
0285     piecewise_constant_distribution(std::initializer_list<T> il, F f)
0286       : _intervals(il.begin(), il.end())
0287     {
0288         if(_intervals.size() < 2) {
0289             _intervals.clear();
0290             _intervals.push_back(RealType(0));
0291             _intervals.push_back(RealType(1));
0292         } else {
0293             std::vector<WeightType> actual_weights;
0294             actual_weights.reserve(_intervals.size() - 1);
0295             for(std::size_t i = 0; i < _intervals.size() - 1; ++i) {
0296                 RealType midpoint = (_intervals[i] + _intervals[i + 1]) / 2;
0297                 actual_weights.push_back(f(midpoint));
0298             }
0299             typedef discrete_distribution<std::size_t, WeightType> bins_type;
0300             typename bins_type::param_type bins_param(actual_weights);
0301             _bins.param(bins_param);
0302         }
0303     }
0304 #endif
0305     /**
0306      * Constructs a piecewise_constant_distribution from Boost.Range
0307      * ranges holding the interval boundaries and the weights.  If
0308      * there are less than two interval boundaries, this is equivalent
0309      * to the default constructor and the distribution will produce
0310      * values uniformly distributed in the range [0, 1).  The
0311      * number of weights must be one less than the number of
0312      * interval boundaries.
0313      */
0314     template<class IntervalsRange, class WeightsRange>
0315     piecewise_constant_distribution(const IntervalsRange& intervals_arg,
0316                                     const WeightsRange& weights_arg)
0317       : _bins(weights_arg),
0318         _intervals(std::begin(intervals_arg), std::end(intervals_arg))
0319     {
0320         if(_intervals.size() < 2) {
0321             _intervals.clear();
0322             _intervals.push_back(RealType(0));
0323             _intervals.push_back(RealType(1));
0324         }
0325     }
0326     /**
0327      * Constructs a piecewise_constant_distribution that approximates a
0328      * function.  The range of the distribution is [xmin, xmax).  This
0329      * range is divided into nw equally sized intervals and the weights
0330      * are found by calling the unary function f on the midpoints of the
0331      * intervals.
0332      */
0333     template<class F>
0334     piecewise_constant_distribution(std::size_t nw,
0335                                     RealType xmin,
0336                                     RealType xmax,
0337                                     F f)
0338       : _bins(nw, xmin, xmax, f)
0339     {
0340         if(nw == 0) { nw = 1; }
0341         RealType delta = (xmax - xmin) / nw;
0342         _intervals.reserve(nw + 1);
0343         for(std::size_t i = 0; i < nw; ++i) {
0344             _intervals.push_back(xmin + i * delta);
0345         }
0346         _intervals.push_back(xmax);
0347     }
0348     /**
0349      * Constructs a piecewise_constant_distribution from its parameters.
0350      */
0351     explicit piecewise_constant_distribution(const param_type& parm)
0352       : _bins(parm._weights),
0353         _intervals(parm._intervals)
0354     {
0355     }
0356 
0357     /**
0358      * Returns a value distributed according to the parameters of the
0359      * piecewist_constant_distribution.
0360      */
0361     template<class URNG>
0362     RealType operator()(URNG& urng) const
0363     {
0364         std::size_t i = _bins(urng);
0365         return uniform_real<RealType>(_intervals[i], _intervals[i+1])(urng);
0366     }
0367 
0368     /**
0369      * Returns a value distributed according to the parameters
0370      * specified by param.
0371      */
0372     template<class URNG>
0373     RealType operator()(URNG& urng, const param_type& parm) const
0374     {
0375         return piecewise_constant_distribution(parm)(urng);
0376     }
0377 
0378     /** Returns the smallest value that the distribution can produce. */
0379     result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
0380     { return _intervals.front(); }
0381     /** Returns the largest value that the distribution can produce. */
0382     result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
0383     { return _intervals.back(); }
0384 
0385     /**
0386      * Returns a vector containing the probability density
0387      * over each interval.
0388      */
0389     std::vector<RealType> densities() const
0390     {
0391         std::vector<RealType> result(_bins.probabilities());
0392         for(std::size_t i = 0; i < result.size(); ++i) {
0393             result[i] /= (_intervals[i+1] - _intervals[i]);
0394         }
0395         return(result);
0396     }
0397     /**  Returns a vector containing the interval boundaries. */
0398     std::vector<RealType> intervals() const { return _intervals; }
0399 
0400     /** Returns the parameters of the distribution. */
0401     param_type param() const
0402     {
0403         return param_type(_intervals, _bins.probabilities());
0404     }
0405     /** Sets the parameters of the distribution. */
0406     void param(const param_type& parm)
0407     {
0408         std::vector<RealType> new_intervals(parm._intervals);
0409         typedef discrete_distribution<std::size_t, WeightType> bins_type;
0410         typename bins_type::param_type bins_param(parm._weights);
0411         _bins.param(bins_param);
0412         _intervals.swap(new_intervals);
0413     }
0414 
0415     /**
0416      * Effects: Subsequent uses of the distribution do not depend
0417      * on values produced by any engine prior to invoking reset.
0418      */
0419     void reset() { _bins.reset(); }
0420 
0421     /** Writes a distribution to a @c std::ostream. */
0422     BOOST_RANDOM_DETAIL_OSTREAM_OPERATOR(
0423         os, piecewise_constant_distribution, pcd)
0424     {
0425         os << pcd.param();
0426         return os;
0427     }
0428 
0429     /** Reads a distribution from a @c std::istream */
0430     BOOST_RANDOM_DETAIL_ISTREAM_OPERATOR(
0431         is, piecewise_constant_distribution, pcd)
0432     {
0433         param_type parm;
0434         if(is >> parm) {
0435             pcd.param(parm);
0436         }
0437         return is;
0438     }
0439 
0440     /**
0441      * Returns true if the two distributions will return the
0442      * same sequence of values, when passed equal generators.
0443      */
0444     BOOST_RANDOM_DETAIL_EQUALITY_OPERATOR(
0445         piecewise_constant_distribution, lhs,  rhs)
0446     {
0447         return lhs._bins == rhs._bins && lhs._intervals == rhs._intervals;
0448     }
0449     /**
0450      * Returns true if the two distributions may return different
0451      * sequences of values, when passed equal generators.
0452      */
0453     BOOST_RANDOM_DETAIL_INEQUALITY_OPERATOR(piecewise_constant_distribution)
0454 
0455 private:
0456     discrete_distribution<std::size_t, WeightType> _bins;
0457     std::vector<RealType> _intervals;
0458 };
0459 
0460 }
0461 }
0462 
0463 #endif