1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2014 Roshan <thisisroshansmail@gmail.com>
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
11 #ifndef BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
12 #define BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP
16 #include <boost/compute/types.hpp>
17 #include <boost/compute/buffer.hpp>
18 #include <boost/compute/kernel.hpp>
19 #include <boost/compute/context.hpp>
20 #include <boost/compute/program.hpp>
21 #include <boost/compute/command_queue.hpp>
22 #include <boost/compute/algorithm/transform.hpp>
23 #include <boost/compute/container/vector.hpp>
24 #include <boost/compute/detail/iterator_range_size.hpp>
25 #include <boost/compute/iterator/discard_iterator.hpp>
26 #include <boost/compute/utility/program_cache.hpp>
32 /// \class linear_congruential_engine
33 /// \brief 'Quick and Dirty' linear congruential engine
35 /// Quick and dirty linear congruential engine to generate low quality
36 /// random numbers very quickly. For uses in which good quality of random
37 /// numbers is required(Monte-Carlo Simulations), use other engines like
38 /// Mersenne Twister instead.
40 template<class T = uint_>
41 class linear_congruential_engine
44 typedef T result_type;
45 static const T default_seed = 1;
46 static const T a = 1099087573;
47 static const size_t threads = 1024;
49 /// Creates a new linear_congruential_engine and seeds it with \p value.
50 explicit linear_congruential_engine(command_queue &queue,
51 result_type value = default_seed)
52 : m_context(queue.get_context()),
53 m_multiplicands(m_context, threads * sizeof(result_type))
61 // generate multiplicands
62 generate_multiplicands(queue);
65 /// Creates a new linear_congruential_engine object as a copy of \p other.
66 linear_congruential_engine(const linear_congruential_engine<T> &other)
67 : m_context(other.m_context),
68 m_program(other.m_program),
70 m_multiplicands(other.m_multiplicands)
74 /// Copies \p other to \c *this.
75 linear_congruential_engine<T>&
76 operator=(const linear_congruential_engine<T> &other)
79 m_context = other.m_context;
80 m_program = other.m_program;
81 m_seed = other.m_seed;
82 m_multiplicands = other.m_multiplicands;
88 /// Destroys the linear_congruential_engine object.
89 ~linear_congruential_engine()
93 /// Seeds the random number generator with \p value.
95 /// \param value seed value for the random-number generator
96 /// \param queue command queue to perform the operation
98 /// If no seed value is provided, \c default_seed is used.
99 void seed(result_type value, command_queue &queue)
107 void seed(command_queue &queue)
109 seed(default_seed, queue);
112 /// Generates random numbers and stores them to the range [\p first, \p last).
113 template<class OutputIterator>
114 void generate(OutputIterator first, OutputIterator last, command_queue &queue)
116 size_t size = detail::iterator_range_size(first, last);
118 kernel fill_kernel(m_program, "fill");
119 fill_kernel.set_arg(1, m_multiplicands);
120 fill_kernel.set_arg(2, first.get_buffer());
127 count = (std::min)(static_cast<size_t>(threads), size - offset);
132 fill_kernel.set_arg(0, static_cast<const uint_>(m_seed));
133 fill_kernel.set_arg(3, static_cast<const uint_>(offset));
134 queue.enqueue_1d_range_kernel(fill_kernel, 0, count, 0);
147 void generate(discard_iterator first, discard_iterator last, command_queue &queue)
151 size_t size = detail::iterator_range_size(first, last);
153 detail::read_single_value<T>(m_multiplicands, threads-1, queue);
154 while(size >= threads) {
159 detail::read_single_value<T>(m_multiplicands, size-1, queue);
162 /// Generates random numbers, transforms them with \p op, and then stores
163 /// them to the range [\p first, \p last).
164 template<class OutputIterator, class Function>
165 void generate(OutputIterator first, OutputIterator last, Function op, command_queue &queue)
167 vector<T> tmp(std::distance(first, last), queue.get_context());
168 generate(tmp.begin(), tmp.end(), queue);
169 transform(tmp.begin(), tmp.end(), first, op, queue);
172 /// Generates \p z random numbers and discards them.
173 void discard(size_t z, command_queue &queue)
175 generate(discard_iterator(0), discard_iterator(z), queue);
180 /// Generates the multiplicands for each thread
181 void generate_multiplicands(command_queue &queue)
183 kernel multiplicand_kernel =
184 m_program.create_kernel("multiplicand");
185 multiplicand_kernel.set_arg(0, m_multiplicands);
187 queue.enqueue_task(multiplicand_kernel);
191 void update_seed(command_queue &queue)
194 detail::read_single_value<T>(m_multiplicands, threads-1, queue);
200 boost::shared_ptr<program_cache> cache =
201 program_cache::get_global_cache(m_context);
203 std::string cache_key =
204 std::string("__boost_linear_congruential_engine_") + type_name<T>();
206 const char source[] =
207 "__kernel void multiplicand(__global uint *multiplicands)\n"
209 " uint a = 1099087573;\n"
210 " multiplicands[0] = a;\n"
211 " for(uint i = 1; i < 1024; i++){\n"
212 " multiplicands[i] = a * multiplicands[i-1];\n"
216 "__kernel void fill(const uint seed,\n"
217 " __global uint *multiplicands,\n"
218 " __global uint *result,"
219 " const uint offset)\n"
221 " const uint i = get_global_id(0);\n"
222 " result[offset+i] = seed * multiplicands[i];\n"
225 m_program = cache->get_or_build(cache_key, std::string(), source, m_context);
232 buffer m_multiplicands;
235 } // end compute namespace
236 } // end boost namespace
238 #endif // BOOST_COMPUTE_RANDOM_LINEAR_CONGRUENTIAL_ENGINE_HPP