1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@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 #define BOOST_TEST_MODULE TestLambda
12 #include <boost/test/unit_test.hpp>
14 #include <boost/tuple/tuple_io.hpp>
15 #include <boost/tuple/tuple_comparison.hpp>
17 #include <boost/compute/function.hpp>
18 #include <boost/compute/lambda.hpp>
19 #include <boost/compute/algorithm/copy_n.hpp>
20 #include <boost/compute/algorithm/for_each.hpp>
21 #include <boost/compute/algorithm/transform.hpp>
22 #include <boost/compute/container/vector.hpp>
23 #include <boost/compute/functional/bind.hpp>
24 #include <boost/compute/iterator/zip_iterator.hpp>
25 #include <boost/compute/types/pair.hpp>
26 #include <boost/compute/types/tuple.hpp>
28 #include "check_macros.hpp"
30 #include "context_setup.hpp"
32 namespace bc
= boost::compute
;
33 namespace compute
= boost::compute
;
35 BOOST_AUTO_TEST_CASE(squared_plus_one
)
37 bc::vector
<int> vector(context
);
38 vector
.push_back(1, queue
);
39 vector
.push_back(2, queue
);
40 vector
.push_back(3, queue
);
41 vector
.push_back(4, queue
);
42 vector
.push_back(5, queue
);
44 // multiply each value by itself and add one
45 bc::transform(vector
.begin(),
48 (bc::_1
* bc::_1
) + 1,
50 CHECK_RANGE_EQUAL(int, 5, vector
, (2, 5, 10, 17, 26));
53 BOOST_AUTO_TEST_CASE(abs_int
)
55 bc::vector
<int> vector(context
);
56 vector
.push_back(-1, queue
);
57 vector
.push_back(-2, queue
);
58 vector
.push_back(3, queue
);
59 vector
.push_back(-4, queue
);
60 vector
.push_back(5, queue
);
62 bc::transform(vector
.begin(),
67 CHECK_RANGE_EQUAL(int, 5, vector
, (1, 2, 3, 4, 5));
70 template<class Result
, class Expr
>
71 void check_lambda_result(const Expr
&)
75 typename ::boost::compute::lambda::result_of
<Expr
>::type
,
81 template<class Result
, class Expr
, class Arg1
>
82 void check_lambda_result(const Expr
&, const Arg1
&)
86 typename ::boost::compute::lambda::result_of
<
88 typename
boost::tuple
<Arg1
>
95 template<class Result
, class Expr
, class Arg1
, class Arg2
>
96 void check_lambda_result(const Expr
&, const Arg1
&, const Arg2
&)
100 typename ::boost::compute::lambda::result_of
<
102 typename
boost::tuple
<Arg1
, Arg2
>
109 template<class Result
, class Expr
, class Arg1
, class Arg2
, class Arg3
>
110 void check_lambda_result(const Expr
&, const Arg1
&, const Arg2
&, const Arg3
&)
112 BOOST_STATIC_ASSERT((
114 typename ::boost::compute::lambda::result_of
<
116 typename
boost::tuple
<Arg1
, Arg2
, Arg3
>
123 BOOST_AUTO_TEST_CASE(result_of
)
125 using ::boost::compute::lambda::_1
;
126 using ::boost::compute::lambda::_2
;
127 using ::boost::compute::lambda::_3
;
129 namespace proto
= ::boost::proto
;
131 using boost::compute::int_
;
133 check_lambda_result
<int_
>(proto::lit(1));
134 check_lambda_result
<int_
>(proto::lit(1) + 2);
135 check_lambda_result
<float>(proto::lit(1.2f
));
136 check_lambda_result
<float>(proto::lit(1) + 1.2f
);
137 check_lambda_result
<float>(proto::lit(1) / 2 + 1.2f
);
139 using boost::compute::float4_
;
140 using boost::compute::int4_
;
142 check_lambda_result
<int_
>(_1
, int_(1));
143 check_lambda_result
<float>(_1
, float(1.2f
));
144 check_lambda_result
<float4_
>(_1
, float4_(1, 2, 3, 4));
145 check_lambda_result
<float4_
>(2.0f
* _1
, float4_(1, 2, 3, 4));
146 check_lambda_result
<float4_
>(_1
* 2.0f
, float4_(1, 2, 3, 4));
148 check_lambda_result
<float>(dot(_1
, _2
), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0));
149 check_lambda_result
<float>(dot(_1
, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3));
150 check_lambda_result
<float>(distance(_1
, _2
), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0));
151 check_lambda_result
<float>(distance(_1
, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3));
153 check_lambda_result
<float>(length(_1
), float4_(3, 2, 1, 0));
155 check_lambda_result
<float4_
>(cross(_1
, _2
), float4_(0, 1, 2, 3), float4_(3, 2, 1, 0));
156 check_lambda_result
<float4_
>(cross(_1
, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3));
158 check_lambda_result
<float4_
>(max(_1
, _2
), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3));
159 check_lambda_result
<float4_
>(max(_1
, float(1.0f
)), float4_(0, 1, 2, 3));
160 check_lambda_result
<int4_
>(max(_1
, int4_(3, 2, 1, 0)), int4_(0, 1, 2, 3));
161 check_lambda_result
<int4_
>(max(_1
, int_(1)), int4_(0, 1, 2, 3));
162 check_lambda_result
<float4_
>(min(_1
, float4_(3, 2, 1, 0)), float4_(0, 1, 2, 3));
164 check_lambda_result
<float4_
>(step(_1
, _2
), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3));
165 check_lambda_result
<int4_
>(step(_1
, _2
), float(3.0f
), int4_(0, 1, 2, 3));
167 check_lambda_result
<float4_
>(
168 smoothstep(_1
, _2
, _3
),
169 float4_(3, 2, 1, 0), float4_(3, 2, 1, 0), float4_(0, 1, 2, 3)
171 check_lambda_result
<int4_
>(
172 smoothstep(_1
, _2
, _3
),
173 float(2.0f
), float(3.0f
), int4_(0, 1, 2, 3)
176 check_lambda_result
<int4_
>(bc::lambda::isinf(_1
), float4_(0, 1, 2, 3));
178 check_lambda_result
<int>(_1
+ 2, int(2));
179 check_lambda_result
<float>(_1
+ 2, float(2.2f
));
181 check_lambda_result
<int>(_1
+ _2
, int(1), int(2));
182 check_lambda_result
<float>(_1
+ _2
, int(1), float(2.2f
));
184 check_lambda_result
<int>(_1
+ _1
, int(1));
185 check_lambda_result
<float>(_1
* _1
, float(1));
187 using boost::compute::lambda::get
;
189 check_lambda_result
<float>(get
<0>(_1
), float4_(1, 2, 3, 4));
190 check_lambda_result
<bool>(get
<0>(_1
) < 1.f
, float4_(1, 2, 3, 4));
191 check_lambda_result
<bool>(_1
< 1.f
, float(2));
193 using boost::compute::lambda::make_pair
;
195 check_lambda_result
<int>(get
<0>(make_pair(_1
, _2
)), int(1), float(1.2f
));
196 check_lambda_result
<float>(get
<1>(make_pair(_1
, _2
)), int(1), float(1.2f
));
197 check_lambda_result
<std::pair
<int, float> >(make_pair(_1
, _2
), int(1), float(1.2f
));
199 using boost::compute::lambda::make_tuple
;
201 check_lambda_result
<boost::tuple
<int> >(make_tuple(_1
), int(1));
202 check_lambda_result
<boost::tuple
<int, float> >(make_tuple(_1
, _2
), int(1), float(1.2f
));
203 check_lambda_result
<boost::tuple
<int, int> >(make_tuple(_1
, _1
), int(1));
204 check_lambda_result
<boost::tuple
<int, float> >(make_tuple(_1
, _2
), int(1), float(1.4f
));
205 check_lambda_result
<boost::tuple
<char, int, float> >(
206 make_tuple(_1
, _2
, _3
), char('a'), int(2), float(3.4f
)
208 check_lambda_result
<boost::tuple
<int, int, int> >(
209 make_tuple(_1
, _1
, _1
), int(1), float(1.4f
)
211 check_lambda_result
<boost::tuple
<int, float, int, float, int> >(
212 make_tuple(_1
, _2
, _1
, _2
, _1
), int(1), float(1.4f
)
216 BOOST_AUTO_TEST_CASE(make_function_from_lamdba
)
218 using boost::compute::lambda::_1
;
220 int data
[] = { 2, 4, 6, 8, 10 };
221 compute::vector
<int> vector(data
, data
+ 5, queue
);
223 compute::function
<int(int)> f
= _1
* 2 + 3;
226 vector
.begin(), vector
.end(), vector
.begin(), f
, queue
228 CHECK_RANGE_EQUAL(int, 5, vector
, (7, 11, 15, 19, 23));
231 BOOST_AUTO_TEST_CASE(make_function_from_binary_lamdba
)
233 using boost::compute::lambda::_1
;
234 using boost::compute::lambda::_2
;
235 using boost::compute::lambda::abs
;
237 int data1
[] = { 2, 4, 6, 8, 10 };
238 int data2
[] = { 10, 8, 6, 4, 2 };
239 compute::vector
<int> vec1(data1
, data1
+ 5, queue
);
240 compute::vector
<int> vec2(data2
, data2
+ 5, queue
);
241 compute::vector
<int> result(5, context
);
243 compute::function
<int(int, int)> f
= abs(_1
- _2
);
246 vec1
.begin(), vec1
.end(), vec2
.begin(), result
.begin(), f
, queue
248 CHECK_RANGE_EQUAL(int, 5, result
, (8, 4, 0, 4, 8));
251 BOOST_AUTO_TEST_CASE(lambda_binary_function_with_pointer_modf
)
253 using boost::compute::lambda::_1
;
254 using boost::compute::lambda::_2
;
255 using boost::compute::lambda::abs
;
257 bc::float_ data1
[] = { 2.2f
, 4.2f
, 6.3f
, 8.3f
, 10.2f
};
258 compute::vector
<bc::float_
> vec1(data1
, data1
+ 5, queue
);
259 compute::vector
<bc::float_
> vec2(size_t(5), context
);
260 compute::vector
<bc::float_
> result(5, context
);
263 bc::make_transform_iterator(vec1
.begin(), _1
+ 0.01f
),
264 bc::make_transform_iterator(vec1
.end(), _1
+ 0.01f
),
267 bc::lambda::modf(_1
, _2
),
270 CHECK_RANGE_CLOSE(bc::float_
, 5, result
, (0.21f
, 0.21f
, 0.31f
, 0.31f
, 0.21f
), 0.01f
);
271 CHECK_RANGE_CLOSE(bc::float_
, 5, vec2
, (2, 4, 6, 8, 10), 0.01f
);
274 BOOST_AUTO_TEST_CASE(lambda_tenary_function_with_pointer_remquo
)
276 if(!has_remquo_func(device
))
281 using boost::compute::lambda::_1
;
282 using boost::compute::lambda::_2
;
283 using boost::compute::lambda::get
;
285 bc::float_ data1
[] = { 2.2f
, 4.2f
, 6.3f
, 8.3f
, 10.2f
};
286 bc::float_ data2
[] = { 4.4f
, 4.2f
, 6.3f
, 16.6f
, 10.2f
};
287 compute::vector
<bc::float_
> vec1(data1
, data1
+ 5, queue
);
288 compute::vector
<bc::float_
> vec2(data2
, data2
+ 5, queue
);
289 compute::vector
<bc::int_
> vec3(size_t(5), context
);
290 compute::vector
<bc::float_
> result(5, context
);
293 compute::make_zip_iterator(
294 boost::make_tuple(vec1
.begin(), vec2
.begin(), vec3
.begin())
296 compute::make_zip_iterator(
297 boost::make_tuple(vec1
.end(), vec2
.end(), vec3
.end())
300 bc::lambda::remquo(get
<0>(_1
), get
<1>(_1
), get
<2>(_1
)),
303 CHECK_RANGE_CLOSE(bc::float_
, 5, result
, (2.2f
, 0.0f
, 0.0f
, 8.3f
, 0.0f
), 0.01f
);
304 CHECK_RANGE_EQUAL(bc::int_
, 5, vec3
, (0, 1, 1, 0, 1));
307 BOOST_AUTO_TEST_CASE(lambda_get_vector
)
309 using boost::compute::_1
;
310 using boost::compute::int2_
;
311 using boost::compute::lambda::get
;
313 int data
[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
314 compute::vector
<int2_
> vector(4, context
);
317 reinterpret_cast<int2_
*>(data
),
318 reinterpret_cast<int2_
*>(data
) + 4,
323 // extract first component of each vector
324 compute::vector
<int> first_component(4, context
);
328 first_component
.begin(),
332 CHECK_RANGE_EQUAL(int, 4, first_component
, (1, 3, 5, 7));
334 // extract second component of each vector
335 compute::vector
<int> second_component(4, context
);
339 first_component
.begin(),
343 CHECK_RANGE_EQUAL(int, 4, first_component
, (2, 4, 6, 8));
346 BOOST_AUTO_TEST_CASE(lambda_get_pair
)
348 using boost::compute::_1
;
349 using boost::compute::lambda::get
;
351 compute::vector
<std::pair
<int, float> > vector(context
);
352 vector
.push_back(std::make_pair(1, 1.2f
), queue
);
353 vector
.push_back(std::make_pair(3, 3.4f
), queue
);
354 vector
.push_back(std::make_pair(5, 5.6f
), queue
);
355 vector
.push_back(std::make_pair(7, 7.8f
), queue
);
357 // extract first compoenent of each pair
358 compute::vector
<int> first_component(4, context
);
362 first_component
.begin(),
366 CHECK_RANGE_EQUAL(int, 4, first_component
, (1, 3, 5, 7));
368 // extract second compoenent of each pair
369 compute::vector
<float> second_component(4, context
);
373 second_component
.begin(),
377 CHECK_RANGE_EQUAL(float, 4, second_component
, (1.2f
, 3.4f
, 5.6f
, 7.8f
));
380 BOOST_AUTO_TEST_CASE(lambda_get_tuple
)
382 using boost::compute::_1
;
383 using boost::compute::lambda::get
;
385 compute::vector
<boost::tuple
<int, char, float> > vector(context
);
387 vector
.push_back(boost::make_tuple(1, 'a', 1.2f
), queue
);
388 vector
.push_back(boost::make_tuple(3, 'b', 3.4f
), queue
);
389 vector
.push_back(boost::make_tuple(5, 'c', 5.6f
), queue
);
390 vector
.push_back(boost::make_tuple(7, 'd', 7.8f
), queue
);
392 // extract first component of each tuple
393 compute::vector
<int> first_component(4, context
);
397 first_component
.begin(),
401 CHECK_RANGE_EQUAL(int, 4, first_component
, (1, 3, 5, 7));
403 // extract second component of each tuple
404 compute::vector
<char> second_component(4, context
);
408 second_component
.begin(),
412 CHECK_RANGE_EQUAL(char, 4, second_component
, ('a', 'b', 'c', 'd'));
414 // extract third component of each tuple
415 compute::vector
<float> third_component(4, context
);
419 third_component
.begin(),
423 CHECK_RANGE_EQUAL(float, 4, third_component
, (1.2f
, 3.4f
, 5.6f
, 7.8f
));
426 BOOST_AUTO_TEST_CASE(lambda_get_zip_iterator
)
428 using boost::compute::_1
;
429 using boost::compute::lambda::get
;
431 float data
[] = { 1.2f
, 2.3f
, 3.4f
, 4.5f
, 5.6f
, 6.7f
, 7.8f
, 9.0f
};
432 compute::vector
<float> input(8, context
);
433 compute::copy(data
, data
+ 8, input
.begin(), queue
);
435 compute::vector
<float> output(8, context
);
438 compute::make_zip_iterator(
439 boost::make_tuple(input
.begin(), output
.begin())
441 compute::make_zip_iterator(
442 boost::make_tuple(input
.end(), output
.end())
444 get
<1>(_1
) = get
<0>(_1
),
447 CHECK_RANGE_EQUAL(float, 8, output
,
448 (1.2f
, 2.3f
, 3.4f
, 4.5f
, 5.6f
, 6.7f
, 7.8f
, 9.0f
)
452 BOOST_AUTO_TEST_CASE(lambda_make_pair
)
454 using boost::compute::_1
;
455 using boost::compute::_2
;
456 using boost::compute::lambda::make_pair
;
458 int int_data
[] = { 1, 3, 5, 7 };
459 float float_data
[] = { 1.2f
, 2.3f
, 3.4f
, 4.5f
};
461 compute::vector
<int> int_vector(int_data
, int_data
+ 4, queue
);
462 compute::vector
<float> float_vector(float_data
, float_data
+ 4, queue
);
463 compute::vector
<std::pair
<int, float> > output_vector(4, context
);
468 float_vector
.begin(),
469 output_vector
.begin(),
470 make_pair(_1
- 1, 0 - _2
),
474 std::vector
<std::pair
<int, float> > host_vector(4);
475 compute::copy_n(output_vector
.begin(), 4, host_vector
.begin(), queue
);
476 BOOST_CHECK(host_vector
[0] == std::make_pair(0, -1.2f
));
477 BOOST_CHECK(host_vector
[1] == std::make_pair(2, -2.3f
));
478 BOOST_CHECK(host_vector
[2] == std::make_pair(4, -3.4f
));
479 BOOST_CHECK(host_vector
[3] == std::make_pair(6, -4.5f
));
482 BOOST_AUTO_TEST_CASE(lambda_make_tuple
)
484 using boost::compute::_1
;
485 using boost::compute::lambda::get
;
486 using boost::compute::lambda::make_tuple
;
488 std::vector
<boost::tuple
<int, float> > data
;
489 data
.push_back(boost::make_tuple(2, 1.2f
));
490 data
.push_back(boost::make_tuple(4, 2.4f
));
491 data
.push_back(boost::make_tuple(6, 4.6f
));
492 data
.push_back(boost::make_tuple(8, 6.8f
));
494 compute::vector
<boost::tuple
<int, float> > input_vector(4, context
);
495 compute::copy(data
.begin(), data
.end(), input_vector
.begin(), queue
);
497 // reverse the elements in the tuple
498 compute::vector
<boost::tuple
<float, int> > output_vector(4, context
);
501 input_vector
.begin(),
503 output_vector
.begin(),
504 make_tuple(get
<1>(_1
), get
<0>(_1
)),
508 std::vector
<boost::tuple
<float, int> > host_vector(4);
509 compute::copy_n(output_vector
.begin(), 4, host_vector
.begin(), queue
);
510 BOOST_CHECK_EQUAL(host_vector
[0], boost::make_tuple(1.2f
, 2));
511 BOOST_CHECK_EQUAL(host_vector
[1], boost::make_tuple(2.4f
, 4));
512 BOOST_CHECK_EQUAL(host_vector
[2], boost::make_tuple(4.6f
, 6));
513 BOOST_CHECK_EQUAL(host_vector
[3], boost::make_tuple(6.8f
, 8));
515 // duplicate each element in the tuple
516 compute::vector
<boost::tuple
<int, int, float, float> > doubled_vector(4, context
);
518 input_vector
.begin(),
520 doubled_vector
.begin(),
521 make_tuple(get
<0>(_1
), get
<0>(_1
), get
<1>(_1
), get
<1>(_1
)),
525 std::vector
<boost::tuple
<int, int, float, float> > doubled_host_vector(4);
526 compute::copy_n(doubled_vector
.begin(), 4, doubled_host_vector
.begin(), queue
);
527 BOOST_CHECK_EQUAL(doubled_host_vector
[0], boost::make_tuple(2, 2, 1.2f
, 1.2f
));
528 BOOST_CHECK_EQUAL(doubled_host_vector
[1], boost::make_tuple(4, 4, 2.4f
, 2.4f
));
529 BOOST_CHECK_EQUAL(doubled_host_vector
[2], boost::make_tuple(6, 6, 4.6f
, 4.6f
));
530 BOOST_CHECK_EQUAL(doubled_host_vector
[3], boost::make_tuple(8, 8, 6.8f
, 6.8f
));
533 BOOST_AUTO_TEST_CASE(bind_lambda_function
)
535 using compute::placeholders::_1
;
536 namespace lambda
= compute::lambda
;
538 int data
[] = { 1, 2, 3, 4 };
539 compute::vector
<int> vector(data
, data
+ 4, queue
);
542 vector
.begin(), vector
.end(), vector
.begin(),
543 compute::bind(lambda::_1
* lambda::_2
, _1
, 2),
546 CHECK_RANGE_EQUAL(int, 4, vector
, (2, 4, 6, 8));
549 BOOST_AUTO_TEST_CASE(lambda_function_with_uint_args
)
551 compute::uint_ host_data
[] = { 1, 3, 5, 7, 9 };
552 compute::vector
<compute::uint_
> device_vector(host_data
, host_data
+ 5, queue
);
554 using boost::compute::lambda::clamp
;
555 using compute::lambda::_1
;
558 device_vector
.begin(), device_vector
.end(),
559 device_vector
.begin(),
560 clamp(_1
, compute::uint_(4), compute::uint_(6)),
563 CHECK_RANGE_EQUAL(compute::uint_
, 5, device_vector
, (4, 4, 5, 6, 6));
566 BOOST_AUTO_TEST_CASE(lambda_function_with_short_args
)
568 compute::short_ host_data
[] = { 1, 3, 5, 7, 9 };
569 compute::vector
<compute::short_
> device_vector(host_data
, host_data
+ 5, queue
);
571 using boost::compute::lambda::clamp
;
572 using compute::lambda::_1
;
575 device_vector
.begin(), device_vector
.end(),
576 device_vector
.begin(),
577 clamp(_1
, compute::short_(4), compute::short_(6)),
580 CHECK_RANGE_EQUAL(compute::short_
, 5, device_vector
, (4, 4, 5, 6, 6));
583 BOOST_AUTO_TEST_CASE(lambda_function_with_uchar_args
)
585 compute::uchar_ host_data
[] = { 1, 3, 5, 7, 9 };
586 compute::vector
<compute::uchar_
> device_vector(host_data
, host_data
+ 5, queue
);
588 using boost::compute::lambda::clamp
;
589 using compute::lambda::_1
;
592 device_vector
.begin(), device_vector
.end(),
593 device_vector
.begin(),
594 clamp(_1
, compute::uchar_(4), compute::uchar_(6)),
597 CHECK_RANGE_EQUAL(compute::uchar_
, 5, device_vector
, (4, 4, 5, 6, 6));
600 BOOST_AUTO_TEST_CASE(lambda_function_with_char_args
)
602 compute::char_ host_data
[] = { 1, 3, 5, 7, 9 };
603 compute::vector
<compute::char_
> device_vector(host_data
, host_data
+ 5, queue
);
605 using boost::compute::lambda::clamp
;
606 using compute::lambda::_1
;
609 device_vector
.begin(), device_vector
.end(),
610 device_vector
.begin(),
611 clamp(_1
, compute::char_(4), compute::char_(6)),
614 CHECK_RANGE_EQUAL(compute::char_
, 5, device_vector
, (4, 4, 5, 6, 6));
617 BOOST_AUTO_TEST_SUITE_END()