1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
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
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10
11 #define BOOST_TEST_MODULE TestTransform
12 #include <boost/test/unit_test.hpp>
13
14 #include <boost/compute/lambda.hpp>
15 #include <boost/compute/system.hpp>
16 #include <boost/compute/function.hpp>
17 #include <boost/compute/functional.hpp>
18 #include <boost/compute/algorithm/transform.hpp>
19 #include <boost/compute/container/vector.hpp>
20 #include <boost/compute/iterator/counting_iterator.hpp>
21 #include <boost/compute/functional/field.hpp>
22
23 #include "check_macros.hpp"
24 #include "context_setup.hpp"
25
26 namespace bc = boost::compute;
27 namespace compute = boost::compute;
28
BOOST_AUTO_TEST_CASE(transform_int_abs)29 BOOST_AUTO_TEST_CASE(transform_int_abs)
30 {
31 int data[] = { 1, -2, -3, -4, 5 };
32 bc::vector<int> vector(data, data + 5, queue);
33 CHECK_RANGE_EQUAL(int, 5, vector, (1, -2, -3, -4, 5));
34
35 bc::transform(vector.begin(),
36 vector.end(),
37 vector.begin(),
38 bc::abs<int>(),
39 queue);
40 CHECK_RANGE_EQUAL(int, 5, vector, (1, 2, 3, 4, 5));
41 }
42
BOOST_AUTO_TEST_CASE(transform_float_sqrt)43 BOOST_AUTO_TEST_CASE(transform_float_sqrt)
44 {
45 float data[] = { 1.0f, 4.0f, 9.0f, 16.0f };
46 bc::vector<float> vector(data, data + 4, queue);
47 CHECK_RANGE_EQUAL(float, 4, vector, (1.0f, 4.0f, 9.0f, 16.0f));
48
49 bc::transform(vector.begin(),
50 vector.end(),
51 vector.begin(),
52 bc::sqrt<float>(),
53 queue);
54 queue.finish();
55 BOOST_CHECK_CLOSE(float(vector[0]), 1.0f, 1e-4f);
56 BOOST_CHECK_CLOSE(float(vector[1]), 2.0f, 1e-4f);
57 BOOST_CHECK_CLOSE(float(vector[2]), 3.0f, 1e-4f);
58 BOOST_CHECK_CLOSE(float(vector[3]), 4.0f, 1e-4f);
59 }
60
BOOST_AUTO_TEST_CASE(transform_float_clamp)61 BOOST_AUTO_TEST_CASE(transform_float_clamp)
62 {
63 float data[] = { 10.f, 20.f, 30.f, 40.f, 50.f };
64 bc::vector<float> vector(data, data + 5, queue);
65 CHECK_RANGE_EQUAL(float, 5, vector, (10.0f, 20.0f, 30.0f, 40.0f, 50.0f));
66
67 bc::transform(vector.begin(),
68 vector.end(),
69 vector.begin(),
70 clamp(bc::_1, 15.f, 45.f),
71 queue);
72 CHECK_RANGE_EQUAL(float, 5, vector, (15.0f, 20.0f, 30.0f, 40.0f, 45.0f));
73 }
74
BOOST_AUTO_TEST_CASE(transform_add_int)75 BOOST_AUTO_TEST_CASE(transform_add_int)
76 {
77 int data1[] = { 1, 2, 3, 4 };
78 bc::vector<int> input1(data1, data1 + 4, queue);
79
80 int data2[] = { 10, 20, 30, 40 };
81 bc::vector<int> input2(data2, data2 + 4, queue);
82
83 bc::vector<int> output(4, context);
84 bc::transform(input1.begin(),
85 input1.end(),
86 input2.begin(),
87 output.begin(),
88 bc::plus<int>(),
89 queue);
90 CHECK_RANGE_EQUAL(int, 4, output, (11, 22, 33, 44));
91
92 bc::transform(input1.begin(),
93 input1.end(),
94 input2.begin(),
95 output.begin(),
96 bc::multiplies<int>(),
97 queue);
98 CHECK_RANGE_EQUAL(int, 4, output, (10, 40, 90, 160));
99 }
100
BOOST_AUTO_TEST_CASE(transform_pow4)101 BOOST_AUTO_TEST_CASE(transform_pow4)
102 {
103 float data[] = { 1.0f, 2.0f, 3.0f, 4.0f };
104 bc::vector<float> vector(data, data + 4, queue);
105 CHECK_RANGE_EQUAL(float, 4, vector, (1.0f, 2.0f, 3.0f, 4.0f));
106
107 bc::vector<float> result(4, context);
108 bc::transform(vector.begin(),
109 vector.end(),
110 result.begin(),
111 pown(bc::_1, 4),
112 queue);
113 queue.finish();
114 BOOST_CHECK_CLOSE(float(result[0]), 1.0f, 1e-4f);
115 BOOST_CHECK_CLOSE(float(result[1]), 16.0f, 1e-4f);
116 BOOST_CHECK_CLOSE(float(result[2]), 81.0f, 1e-4f);
117 BOOST_CHECK_CLOSE(float(result[3]), 256.0f, 1e-4f);
118 }
119
BOOST_AUTO_TEST_CASE(transform_custom_function)120 BOOST_AUTO_TEST_CASE(transform_custom_function)
121 {
122 float data[] = { 9.0f, 7.0f, 5.0f, 3.0f };
123 bc::vector<float> vector(data, data + 4, queue);
124
125 BOOST_COMPUTE_FUNCTION(float, pow3add4, (float x),
126 {
127 return pow(x, 3.0f) + 4.0f;
128 });
129
130 bc::vector<float> result(4, context);
131 bc::transform(vector.begin(),
132 vector.end(),
133 result.begin(),
134 pow3add4,
135 queue);
136 queue.finish();
137 BOOST_CHECK_CLOSE(float(result[0]), 733.0f, 1e-4f);
138 BOOST_CHECK_CLOSE(float(result[1]), 347.0f, 1e-4f);
139 BOOST_CHECK_CLOSE(float(result[2]), 129.0f, 1e-4f);
140 BOOST_CHECK_CLOSE(float(result[3]), 31.0f, 1e-4f);
141 }
142
BOOST_AUTO_TEST_CASE(extract_vector_component)143 BOOST_AUTO_TEST_CASE(extract_vector_component)
144 {
145 using bc::int2_;
146
147 int data[] = { 1, 2,
148 3, 4,
149 5, 6,
150 7, 8 };
151 bc::vector<int2_> vector(
152 reinterpret_cast<int2_ *>(data),
153 reinterpret_cast<int2_ *>(data) + 4,
154 queue
155 );
156 CHECK_RANGE_EQUAL(
157 int2_, 4, vector,
158 (int2_(1, 2), int2_(3, 4), int2_(5, 6), int2_(7, 8))
159 );
160
161 bc::vector<int> x_components(4, context);
162 bc::transform(vector.begin(),
163 vector.end(),
164 x_components.begin(),
165 bc::get<0>(),
166 queue);
167 CHECK_RANGE_EQUAL(int, 4, x_components, (1, 3, 5, 7));
168
169 bc::vector<int> y_components(4, context);
170 bc::transform(vector.begin(),
171 vector.end(),
172 y_components.begin(),
173 bc::get<1>(),
174 queue);
175 CHECK_RANGE_EQUAL(int, 4, y_components, (2, 4, 6, 8));
176 }
177
BOOST_AUTO_TEST_CASE(transform_pinned_vector)178 BOOST_AUTO_TEST_CASE(transform_pinned_vector)
179 {
180 int data[] = { 2, -3, 4, -5, 6, -7 };
181 std::vector<int> vector(data, data + 6);
182
183 bc::buffer buffer(context,
184 vector.size() * sizeof(int),
185 bc::buffer::read_write | bc::buffer::use_host_ptr,
186 &vector[0]);
187
188 bc::transform(bc::make_buffer_iterator<int>(buffer, 0),
189 bc::make_buffer_iterator<int>(buffer, 6),
190 bc::make_buffer_iterator<int>(buffer, 0),
191 bc::abs<int>(),
192 queue);
193
194 void *ptr = queue.enqueue_map_buffer(buffer,
195 bc::command_queue::map_read,
196 0,
197 buffer.size());
198 BOOST_VERIFY(ptr == &vector[0]);
199 BOOST_CHECK_EQUAL(vector[0], 2);
200 BOOST_CHECK_EQUAL(vector[1], 3);
201 BOOST_CHECK_EQUAL(vector[2], 4);
202 BOOST_CHECK_EQUAL(vector[3], 5);
203 BOOST_CHECK_EQUAL(vector[4], 6);
204 BOOST_CHECK_EQUAL(vector[5], 7);
205 queue.enqueue_unmap_buffer(buffer, ptr);
206 }
207
BOOST_AUTO_TEST_CASE(transform_popcount)208 BOOST_AUTO_TEST_CASE(transform_popcount)
209 {
210 using boost::compute::uint_;
211
212 uint_ data[] = { 0, 1, 2, 3, 4, 45, 127, 5000, 789, 15963 };
213 bc::vector<uint_> input(data, data + 10, queue);
214 bc::vector<uint_> output(input.size(), context);
215
216 bc::transform(
217 input.begin(),
218 input.end(),
219 output.begin(),
220 bc::popcount<uint_>(),
221 queue
222 );
223 CHECK_RANGE_EQUAL(uint_, 10, output, (0, 1, 1, 2, 1, 4, 7, 5, 5, 10));
224 }
225
226 // generates the first 25 fibonacci numbers in parallel using the
227 // rounding-based fibonacci formula
BOOST_AUTO_TEST_CASE(generate_fibonacci_sequence)228 BOOST_AUTO_TEST_CASE(generate_fibonacci_sequence)
229 {
230 using boost::compute::uint_;
231
232 boost::compute::vector<uint_> sequence(25, context);
233
234 BOOST_COMPUTE_FUNCTION(uint_, nth_fibonacci, (const uint_ n),
235 {
236 const float golden_ratio = (1.f + sqrt(5.f)) / 2.f;
237 return floor(pown(golden_ratio, n) / sqrt(5.f) + 0.5f);
238 });
239
240 boost::compute::transform(
241 boost::compute::make_counting_iterator(uint_(0)),
242 boost::compute::make_counting_iterator(uint_(sequence.size())),
243 sequence.begin(),
244 nth_fibonacci,
245 queue
246 );
247 CHECK_RANGE_EQUAL(
248 uint_, 25, sequence,
249 (0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610,
250 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368)
251 );
252 }
253
BOOST_AUTO_TEST_CASE(field)254 BOOST_AUTO_TEST_CASE(field)
255 {
256 using compute::uint2_;
257 using compute::uint4_;
258 using compute::field;
259
260 unsigned int data[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
261 compute::vector<uint4_> input(
262 reinterpret_cast<uint4_ *>(data),
263 reinterpret_cast<uint4_ *>(data) + 2,
264 queue
265 );
266 compute::vector<uint2_> output(input.size(), context);
267
268 compute::transform(
269 input.begin(),
270 input.end(),
271 output.begin(),
272 compute::field<uint2_>("xz"),
273 queue
274 );
275
276 queue.finish();
277
278 BOOST_CHECK_EQUAL(uint2_(output[0]), uint2_(1, 3));
279 BOOST_CHECK_EQUAL(uint2_(output[1]), uint2_(5, 7));
280 }
281
BOOST_AUTO_TEST_CASE(transform_abs_doctest)282 BOOST_AUTO_TEST_CASE(transform_abs_doctest)
283 {
284 //! [transform_abs]
285 int data[] = { -1, -2, -3, -4 };
286 boost::compute::vector<int> vec(data, data + 4, queue);
287
288 using boost::compute::abs;
289
290 // calculate the absolute value for each element in-place
291 boost::compute::transform(
292 vec.begin(), vec.end(), vec.begin(), abs<int>(), queue
293 );
294
295 // vec == { 1, 2, 3, 4 }
296 //! [transform_abs]
297
298 CHECK_RANGE_EQUAL(int, 4, vec, (1, 2, 3, 4));
299 }
300
BOOST_AUTO_TEST_CASE(abs_if_odd)301 BOOST_AUTO_TEST_CASE(abs_if_odd)
302 {
303 // return absolute value only for odd values
304 BOOST_COMPUTE_FUNCTION(int, abs_if_odd, (int x),
305 {
306 if(x & 1){
307 return abs(x);
308 }
309 else {
310 return x;
311 }
312 });
313
314 int data[] = { -2, -3, -4, -5, -6, -7, -8, -9 };
315 compute::vector<int> vector(data, data + 8, queue);
316
317 compute::transform(
318 vector.begin(), vector.end(), vector.begin(), abs_if_odd, queue
319 );
320
321 CHECK_RANGE_EQUAL(int, 8, vector, (-2, +3, -4, +5, -6, +7, -8, +9));
322 }
323
324 BOOST_AUTO_TEST_SUITE_END()
325