123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- #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 {
- template<class IntType = uint_>
- class discrete_distribution
- {
- public:
- typedef IntType result_type;
-
-
- discrete_distribution()
- : m_probabilities(1, double(1)),
- m_scanned_probabilities(1, double(1))
- {
- }
-
-
- template<class InputIterator>
- discrete_distribution(InputIterator first, InputIterator last)
- : m_probabilities(first, last),
- m_scanned_probabilities(std::distance(first, last))
- {
- if(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)
- {
-
-
- *i = *i / m_scanned_probabilities.back();
-
-
- *j = *j / m_scanned_probabilities.back();
- }
- }
- else {
- m_probabilities.push_back(double(1));
- m_scanned_probabilities.push_back(double(1));
- }
- }
-
- ~discrete_distribution()
- {
- }
-
- ::std::vector<double> probabilities() const
- {
- return m_probabilities;
- }
-
- result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
- {
- return result_type(0);
- }
-
- 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);
- }
-
-
- 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"
- );
- };
- }
- }
- #endif
|