File indexing completed on 2025-01-18 09:30:03
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP
0012 #define BOOST_COMPUTE_RANDOM_DISCRETE_DISTRIBUTION_HPP
0013
0014 #include <numeric>
0015
0016 #include <boost/config.hpp>
0017 #include <boost/type_traits.hpp>
0018 #include <boost/static_assert.hpp>
0019
0020 #include <boost/compute/command_queue.hpp>
0021 #include <boost/compute/function.hpp>
0022 #include <boost/compute/algorithm/accumulate.hpp>
0023 #include <boost/compute/algorithm/copy.hpp>
0024 #include <boost/compute/algorithm/transform.hpp>
0025 #include <boost/compute/detail/literal.hpp>
0026 #include <boost/compute/types/fundamental.hpp>
0027
0028 namespace boost {
0029 namespace compute {
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041 template<class IntType = uint_>
0042 class discrete_distribution
0043 {
0044 public:
0045 typedef IntType result_type;
0046
0047
0048
0049 discrete_distribution()
0050 : m_probabilities(1, double(1)),
0051 m_scanned_probabilities(1, double(1))
0052 {
0053
0054 }
0055
0056
0057
0058 template<class InputIterator>
0059 discrete_distribution(InputIterator first, InputIterator last)
0060 : m_probabilities(first, last),
0061 m_scanned_probabilities(std::distance(first, last))
0062 {
0063 if(first != last) {
0064
0065
0066 std::partial_sum(first, last, m_scanned_probabilities.begin());
0067
0068 std::vector<double>::iterator i = m_probabilities.begin();
0069 std::vector<double>::iterator j = m_scanned_probabilities.begin();
0070 for(; i != m_probabilities.end(); ++i, ++j)
0071 {
0072
0073
0074 *i = *i / m_scanned_probabilities.back();
0075
0076
0077 *j = *j / m_scanned_probabilities.back();
0078 }
0079 }
0080 else {
0081 m_probabilities.push_back(double(1));
0082 m_scanned_probabilities.push_back(double(1));
0083 }
0084 }
0085
0086
0087 ~discrete_distribution()
0088 {
0089 }
0090
0091
0092 ::std::vector<double> probabilities() const
0093 {
0094 return m_probabilities;
0095 }
0096
0097
0098 result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
0099 {
0100 return result_type(0);
0101 }
0102
0103
0104 result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const
0105 {
0106 size_t type_max = static_cast<size_t>(
0107 (std::numeric_limits<result_type>::max)()
0108 );
0109 if(m_probabilities.size() - 1 > type_max) {
0110 return (std::numeric_limits<result_type>::max)();
0111 }
0112 return static_cast<result_type>(m_probabilities.size() - 1);
0113 }
0114
0115
0116
0117 template<class OutputIterator, class Generator>
0118 void generate(OutputIterator first,
0119 OutputIterator last,
0120 Generator &generator,
0121 command_queue &queue)
0122 {
0123 std::string source = "inline IntType scale_random(uint x)\n";
0124
0125 source = source +
0126 "{\n" +
0127 "float rno = convert_float(x) / UINT_MAX;\n";
0128 for(size_t i = 0; i < m_scanned_probabilities.size() - 1; i++)
0129 {
0130 source = source +
0131 "if(rno <= " + detail::make_literal<float>(m_scanned_probabilities[i]) + ")\n" +
0132 " return " + detail::make_literal(i) + ";\n";
0133 }
0134
0135 source = source +
0136 "return " + detail::make_literal(m_scanned_probabilities.size() - 1) + ";\n" +
0137 "}\n";
0138
0139 BOOST_COMPUTE_FUNCTION(IntType, scale_random, (const uint_ x), {});
0140
0141 scale_random.set_source(source);
0142 scale_random.define("IntType", type_name<IntType>());
0143
0144 generator.generate(first, last, scale_random, queue);
0145 }
0146
0147 private:
0148 ::std::vector<double> m_probabilities;
0149 ::std::vector<double> m_scanned_probabilities;
0150
0151 BOOST_STATIC_ASSERT_MSG(
0152 boost::is_integral<IntType>::value,
0153 "Template argument must be integral"
0154 );
0155 };
0156
0157 }
0158 }
0159
0160 #endif