| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 | //---------------------------------------------------------------------------//// Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>//// 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://boostorg.github.com/compute for more information.//---------------------------------------------------------------------------//#ifndef BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP#define BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP#include <numeric>#include <boost/config.hpp>#include <boost/type_traits.hpp>#include <boost/static_assert.hpp>#include <boost/compute/command_queue.hpp>#include <boost/compute/function.hpp>#include <boost/compute/algorithm/accumulate.hpp>#include <boost/compute/algorithm/copy.hpp>#include <boost/compute/algorithm/transform.hpp>#include <boost/compute/detail/literal.hpp>#include <boost/compute/types/fundamental.hpp>namespace boost {namespace compute {/// \class discrete_distribution/// \brief Produces random integers on the interval [0, n), where/// probability of each integer is given by the weight of the ith/// integer divided by the sum of all weights.////// The following example shows how to setup a discrete distribution to/// produce 0 and 1 with equal probability////// \snippet test/test_discrete_distribution.cpp generate///template<class IntType = uint_>class discrete_distribution{public:    typedef IntType result_type;    /// Creates a new discrete distribution with a single weight p = { 1 }.    /// This distribution produces only zeroes.    discrete_distribution()        : m_probabilities(1, double(1)),          m_scanned_probabilities(1, double(1))    {    }    /// Creates a new discrete distribution with weights given by    /// the range [\p first, \p last).    template<class InputIterator>    discrete_distribution(InputIterator first, InputIterator last)        : m_probabilities(first, last),          m_scanned_probabilities(std::distance(first, last))    {        if(first != last) {            // after this m_scanned_probabilities.back() is a sum of all            // weights from the range [first, last)            std::partial_sum(first, last, m_scanned_probabilities.begin());            std::vector<double>::iterator i = m_probabilities.begin();            std::vector<double>::iterator j = m_scanned_probabilities.begin();            for(; i != m_probabilities.end(); ++i, ++j)            {                // dividing each weight by sum of all weights to                // get probabilities                *i = *i / m_scanned_probabilities.back();                // dividing each partial sum of weights by sum of                // all weights to get partial sums of probabilities                *j = *j / m_scanned_probabilities.back();            }        }        else {            m_probabilities.push_back(double(1));            m_scanned_probabilities.push_back(double(1));        }    }    /// Destroys the discrete_distribution object.    ~discrete_distribution()    {    }    /// Returns the probabilities    ::std::vector<double> probabilities() const    {        return m_probabilities;    }    /// Returns the minimum potentially generated value.    result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const    {        return result_type(0);    }    /// Returns the maximum potentially generated value.    result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const    {        size_t type_max = static_cast<size_t>(            (std::numeric_limits<result_type>::max)()        );        if(m_probabilities.size() - 1 > type_max) {            return (std::numeric_limits<result_type>::max)();        }        return static_cast<result_type>(m_probabilities.size() - 1);    }    /// Generates uniformly distributed integers and stores    /// them to the range [\p first, \p last).    template<class OutputIterator, class Generator>    void generate(OutputIterator first,                  OutputIterator last,                  Generator &generator,                  command_queue &queue)    {        std::string source = "inline IntType scale_random(uint x)\n";        source = source +            "{\n" +            "float rno = convert_float(x) / UINT_MAX;\n";        for(size_t i = 0; i < m_scanned_probabilities.size() - 1; i++)        {            source = source +                "if(rno <= " + detail::make_literal<float>(m_scanned_probabilities[i]) + ")\n" +                "   return " + detail::make_literal(i) + ";\n";        }        source = source +            "return " + detail::make_literal(m_scanned_probabilities.size() - 1) + ";\n" +            "}\n";        BOOST_COMPUTE_FUNCTION(IntType, scale_random, (const uint_ x), {});        scale_random.set_source(source);        scale_random.define("IntType", type_name<IntType>());        generator.generate(first, last, scale_random, queue);    }private:    ::std::vector<double> m_probabilities;    ::std::vector<double> m_scanned_probabilities;    BOOST_STATIC_ASSERT_MSG(        boost::is_integral<IntType>::value,        "Template argument must be integral"    );};} // end compute namespace} // end boost namespace#endif // BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP
 |