Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:30:03

0001 //---------------------------------------------------------------------------//
0002 // Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
0003 //
0004 // Distributed under the Boost Software License, Version 1.0
0005 // See accompanying file LICENSE_1_0.txt or copy at
0006 // http://www.boost.org/LICENSE_1_0.txt
0007 //
0008 // See http://boostorg.github.com/compute for more information.
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 /// \class discrete_distribution
0032 /// \brief Produces random integers on the interval [0, n), where
0033 /// probability of each integer is given by the weight of the ith
0034 /// integer divided by the sum of all weights.
0035 ///
0036 /// The following example shows how to setup a discrete distribution to
0037 /// produce 0 and 1 with equal probability
0038 ///
0039 /// \snippet test/test_discrete_distribution.cpp generate
0040 ///
0041 template<class IntType = uint_>
0042 class discrete_distribution
0043 {
0044 public:
0045     typedef IntType result_type;
0046 
0047     /// Creates a new discrete distribution with a single weight p = { 1 }.
0048     /// This distribution produces only zeroes.
0049     discrete_distribution()
0050         : m_probabilities(1, double(1)),
0051           m_scanned_probabilities(1, double(1))
0052     {
0053 
0054     }
0055 
0056     /// Creates a new discrete distribution with weights given by
0057     /// the range [\p first, \p last).
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             // after this m_scanned_probabilities.back() is a sum of all
0065             // weights from the range [first, last)
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                 // dividing each weight by sum of all weights to
0073                 // get probabilities
0074                 *i = *i / m_scanned_probabilities.back();
0075                 // dividing each partial sum of weights by sum of
0076                 // all weights to get partial sums of probabilities
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     /// Destroys the discrete_distribution object.
0087     ~discrete_distribution()
0088     {
0089     }
0090 
0091     /// Returns the probabilities
0092     ::std::vector<double> probabilities() const
0093     {
0094         return m_probabilities;
0095     }
0096 
0097     /// Returns the minimum potentially generated value.
0098     result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const
0099     {
0100         return result_type(0);
0101     }
0102 
0103     /// Returns the maximum potentially generated value.
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     /// Generates uniformly distributed integers and stores
0116     /// them to the range [\p first, \p last).
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 } // end compute namespace
0158 } // end boost namespace
0159 
0160 #endif // BOOST_COMPUTE_RANDOM_UNIFORM_INT_DISTRIBUTION_HPP