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_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
0033
0034
0035
0036
0037
0038
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
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
0056 load_program();
0057
0058
0059 seed(value, queue);
0060
0061
0062 generate_multiplicands(queue);
0063 }
0064
0065
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
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
0089 ~linear_congruential_engine()
0090 {
0091 }
0092
0093
0094
0095
0096
0097
0098
0099 void seed(result_type value, command_queue &queue)
0100 {
0101 (void) queue;
0102
0103 m_seed = value;
0104 }
0105
0106
0107 void seed(command_queue &queue)
0108 {
0109 seed(default_seed, queue);
0110 }
0111
0112
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
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
0163
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
0173 void discard(size_t z, command_queue &queue)
0174 {
0175 generate(discard_iterator(0), discard_iterator(z), queue);
0176 }
0177
0178 private:
0179
0180
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
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
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 }
0236 }
0237
0238 #endif