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_LINEAR_CONGRUENTIAL_ENGINE_HPP
0012 #define BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
0013 
0014 #include <algorithm>
0015 
0016 #include <boost/compute/types.hpp>
0017 #include <boost/compute/buffer.hpp>
0018 #include <boost/compute/kernel.hpp>
0019 #include <boost/compute/context.hpp>
0020 #include <boost/compute/program.hpp>
0021 #include <boost/compute/command_queue.hpp>
0022 #include <boost/compute/algorithm/transform.hpp>
0023 #include <boost/compute/container/vector.hpp>
0024 #include <boost/compute/detail/iterator_range_size.hpp>
0025 #include <boost/compute/iterator/discard_iterator.hpp>
0026 #include <boost/compute/utility/program_cache.hpp>
0027 
0028 namespace boost {
0029 namespace compute {
0030 
0031 ///
0032 /// \class linear_congruential_engine
0033 /// \brief 'Quick and Dirty' linear congruential engine
0034 ///
0035 /// Quick and dirty linear congruential engine to generate low quality
0036 /// random numbers very quickly. For uses in which good quality of random
0037 /// numbers is required(Monte-Carlo Simulations), use other engines like
0038 /// Mersenne Twister instead.
0039 ///
0040 template<class T = uint_>
0041 class linear_congruential_engine
0042 {
0043 public:
0044     typedef T result_type;
0045     static const T default_seed = 1;
0046     static const T a = 1099087573;
0047     static const size_t threads = 1024;
0048 
0049     /// Creates a new linear_congruential_engine and seeds it with \p value.
0050     explicit linear_congruential_engine(command_queue &queue,
0051                                         result_type value = default_seed)
0052         : m_context(queue.get_context()),
0053           m_multiplicands(m_context, threads * sizeof(result_type))
0054     {
0055         // setup program
0056         load_program();
0057 
0058         // seed state
0059         seed(value, queue);
0060 
0061         // generate multiplicands
0062         generate_multiplicands(queue);
0063     }
0064 
0065     /// Creates a new linear_congruential_engine object as a copy of \p other.
0066     linear_congruential_engine(const linear_congruential_engine<T> &other)
0067         : m_context(other.m_context),
0068           m_program(other.m_program),
0069           m_seed(other.m_seed),
0070           m_multiplicands(other.m_multiplicands)
0071     {
0072     }
0073 
0074     /// Copies \p other to \c *this.
0075     linear_congruential_engine<T>&
0076     operator=(const linear_congruential_engine<T> &other)
0077     {
0078         if(this != &other){
0079             m_context = other.m_context;
0080             m_program = other.m_program;
0081             m_seed = other.m_seed;
0082             m_multiplicands = other.m_multiplicands;
0083         }
0084 
0085         return *this;
0086     }
0087 
0088     /// Destroys the linear_congruential_engine object.
0089     ~linear_congruential_engine()
0090     {
0091     }
0092 
0093     /// Seeds the random number generator with \p value.
0094     ///
0095     /// \param value seed value for the random-number generator
0096     /// \param queue command queue to perform the operation
0097     ///
0098     /// If no seed value is provided, \c default_seed is used.
0099     void seed(result_type value, command_queue &queue)
0100     {
0101         (void) queue;
0102 
0103         m_seed = value;
0104     }
0105 
0106     /// \overload
0107     void seed(command_queue &queue)
0108     {
0109         seed(default_seed, queue);
0110     }
0111 
0112     /// Generates random numbers and stores them to the range [\p first, \p last).
0113     template<class OutputIterator>
0114     void generate(OutputIterator first, OutputIterator last, command_queue &queue)
0115     {
0116         size_t size = detail::iterator_range_size(first, last);
0117 
0118         kernel fill_kernel(m_program, "fill");
0119         fill_kernel.set_arg(1, m_multiplicands);
0120         fill_kernel.set_arg(2, first.get_buffer());
0121 
0122         size_t offset = 0;
0123 
0124         for(;;){
0125             size_t count = 0;
0126             if(size > threads){
0127                 count = (std::min)(static_cast<size_t>(threads), size - offset);
0128             }
0129             else {
0130                 count = size;
0131             }
0132             fill_kernel.set_arg(0, static_cast<const uint_>(m_seed));
0133             fill_kernel.set_arg(3, static_cast<const uint_>(offset));
0134             queue.enqueue_1d_range_kernel(fill_kernel, 0, count, 0);
0135 
0136             offset += count;
0137 
0138             if(offset >= size){
0139                 break;
0140             }
0141 
0142             update_seed(queue);
0143         }
0144     }
0145 
0146     /// \internal_
0147     void generate(discard_iterator first, discard_iterator last, command_queue &queue)
0148     {
0149         (void) queue;
0150 
0151         size_t size = detail::iterator_range_size(first, last);
0152         uint_ max_mult =
0153             detail::read_single_value<T>(m_multiplicands, threads-1, queue);
0154         while(size >= threads) {
0155             m_seed *= max_mult;
0156             size -= threads;
0157         }
0158         m_seed *=
0159             detail::read_single_value<T>(m_multiplicands, size-1, queue);
0160     }
0161 
0162     /// Generates random numbers, transforms them with \p op, and then stores
0163     /// them to the range [\p first, \p last).
0164     template<class OutputIterator, class Function>
0165     void generate(OutputIterator first, OutputIterator last, Function op, command_queue &queue)
0166     {
0167         vector<T> tmp(std::distance(first, last), queue.get_context());
0168         generate(tmp.begin(), tmp.end(), queue);
0169         transform(tmp.begin(), tmp.end(), first, op, queue);
0170     }
0171 
0172     /// Generates \p z random numbers and discards them.
0173     void discard(size_t z, command_queue &queue)
0174     {
0175         generate(discard_iterator(0), discard_iterator(z), queue);
0176     }
0177 
0178 private:
0179     /// \internal_
0180     /// Generates the multiplicands for each thread
0181     void generate_multiplicands(command_queue &queue)
0182     {
0183         kernel multiplicand_kernel =
0184             m_program.create_kernel("multiplicand");
0185         multiplicand_kernel.set_arg(0, m_multiplicands);
0186 
0187         queue.enqueue_task(multiplicand_kernel);
0188     }
0189 
0190     /// \internal_
0191     void update_seed(command_queue &queue)
0192     {
0193         m_seed *=
0194             detail::read_single_value<T>(m_multiplicands, threads-1, queue);
0195     }
0196 
0197     /// \internal_
0198     void load_program()
0199     {
0200         boost::shared_ptr<program_cache> cache =
0201             program_cache::get_global_cache(m_context);
0202 
0203         std::string cache_key =
0204             std::string("__boost_linear_congruential_engine_") + type_name<T>();
0205 
0206         const char source[] =
0207             "__kernel void multiplicand(__global uint *multiplicands)\n"
0208             "{\n"
0209             "    uint a = 1099087573;\n"
0210             "    multiplicands[0] = a;\n"
0211             "    for(uint i = 1; i < 1024; i++){\n"
0212             "        multiplicands[i] = a * multiplicands[i-1];\n"
0213             "    }\n"
0214             "}\n"
0215 
0216             "__kernel void fill(const uint seed,\n"
0217             "                   __global uint *multiplicands,\n"
0218             "                   __global uint *result,"
0219             "                   const uint offset)\n"
0220             "{\n"
0221             "    const uint i = get_global_id(0);\n"
0222             "    result[offset+i] = seed * multiplicands[i];\n"
0223             "}\n";
0224 
0225         m_program = cache->get_or_build(cache_key, std::string(), source, m_context);
0226     }
0227 
0228 private:
0229     context m_context;
0230     program m_program;
0231     T m_seed;
0232     buffer m_multiplicands;
0233 };
0234 
0235 } // end compute namespace
0236 } // end boost namespace
0237 
0238 #endif // BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP