LIVE / thrust /testing /scan.cu
Xu Ma
update
1c3c0d9
raw
history blame
22.8 kB
#include <unittest/unittest.h>
#include <thrust/scan.h>
#include <thrust/functional.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/iterator/constant_iterator.h>
#include <thrust/iterator/retag.h>
#include <thrust/device_malloc.h>
#include <thrust/device_free.h>
template<typename T>
struct max_functor
{
__host__ __device__
T operator()(T rhs, T lhs) const
{
return thrust::max(rhs,lhs);
}
};
template <class Vector>
void TestScanSimple(void)
{
typedef typename Vector::value_type T;
typename Vector::iterator iter;
Vector input(5);
Vector result(5);
Vector output(5);
input[0] = 1; input[1] = 3; input[2] = -2; input[3] = 4; input[4] = -5;
Vector input_copy(input);
// inclusive scan
iter = thrust::inclusive_scan(input.begin(), input.end(), output.begin());
result[0] = 1; result[1] = 4; result[2] = 2; result[3] = 6; result[4] = 1;
ASSERT_EQUAL(std::size_t(iter - output.begin()), input.size());
ASSERT_EQUAL(input, input_copy);
ASSERT_EQUAL(output, result);
// exclusive scan
iter = thrust::exclusive_scan(input.begin(), input.end(), output.begin(), T(0));
result[0] = 0; result[1] = 1; result[2] = 4; result[3] = 2; result[4] = 6;
ASSERT_EQUAL(std::size_t(iter - output.begin()), input.size());
ASSERT_EQUAL(input, input_copy);
ASSERT_EQUAL(output, result);
// exclusive scan with init
iter = thrust::exclusive_scan(input.begin(), input.end(), output.begin(), T(3));
result[0] = 3; result[1] = 4; result[2] = 7; result[3] = 5; result[4] = 9;
ASSERT_EQUAL(std::size_t(iter - output.begin()), input.size());
ASSERT_EQUAL(input, input_copy);
ASSERT_EQUAL(output, result);
// inclusive scan with op
iter = thrust::inclusive_scan(input.begin(), input.end(), output.begin(), thrust::plus<T>());
result[0] = 1; result[1] = 4; result[2] = 2; result[3] = 6; result[4] = 1;
ASSERT_EQUAL(std::size_t(iter - output.begin()), input.size());
ASSERT_EQUAL(input, input_copy);
ASSERT_EQUAL(output, result);
// exclusive scan with init and op
iter = thrust::exclusive_scan(input.begin(), input.end(), output.begin(), T(3), thrust::plus<T>());
result[0] = 3; result[1] = 4; result[2] = 7; result[3] = 5; result[4] = 9;
ASSERT_EQUAL(std::size_t(iter - output.begin()), input.size());
ASSERT_EQUAL(input, input_copy);
ASSERT_EQUAL(output, result);
// inplace inclusive scan
input = input_copy;
iter = thrust::inclusive_scan(input.begin(), input.end(), input.begin());
result[0] = 1; result[1] = 4; result[2] = 2; result[3] = 6; result[4] = 1;
ASSERT_EQUAL(std::size_t(iter - input.begin()), input.size());
ASSERT_EQUAL(input, result);
// inplace exclusive scan with init
input = input_copy;
iter = thrust::exclusive_scan(input.begin(), input.end(), input.begin(), T(3));
result[0] = 3; result[1] = 4; result[2] = 7; result[3] = 5; result[4] = 9;
ASSERT_EQUAL(std::size_t(iter - input.begin()), input.size());
ASSERT_EQUAL(input, result);
// inplace exclusive scan with implicit init=0
input = input_copy;
iter = thrust::exclusive_scan(input.begin(), input.end(), input.begin());
result[0] = 0; result[1] = 1; result[2] = 4; result[3] = 2; result[4] = 6;
ASSERT_EQUAL(std::size_t(iter - input.begin()), input.size());
ASSERT_EQUAL(input, result);
}
DECLARE_VECTOR_UNITTEST(TestScanSimple);
template<typename InputIterator,
typename OutputIterator>
OutputIterator inclusive_scan(my_system &system,
InputIterator,
InputIterator,
OutputIterator result)
{
system.validate_dispatch();
return result;
}
void TestInclusiveScanDispatchExplicit()
{
thrust::device_vector<int> vec(1);
my_system sys(0);
thrust::inclusive_scan(sys,
vec.begin(),
vec.begin(),
vec.begin());
ASSERT_EQUAL(true, sys.is_valid());
}
DECLARE_UNITTEST(TestInclusiveScanDispatchExplicit);
template<typename InputIterator,
typename OutputIterator>
OutputIterator inclusive_scan(my_tag,
InputIterator,
InputIterator,
OutputIterator result)
{
*result = 13;
return result;
}
void TestInclusiveScanDispatchImplicit()
{
thrust::device_vector<int> vec(1);
thrust::inclusive_scan(thrust::retag<my_tag>(vec.begin()),
thrust::retag<my_tag>(vec.begin()),
thrust::retag<my_tag>(vec.begin()));
ASSERT_EQUAL(13, vec.front());
}
DECLARE_UNITTEST(TestInclusiveScanDispatchImplicit);
template<typename InputIterator,
typename OutputIterator>
OutputIterator exclusive_scan(my_system &system,
InputIterator,
InputIterator,
OutputIterator result)
{
system.validate_dispatch();
return result;
}
void TestExclusiveScanDispatchExplicit()
{
thrust::device_vector<int> vec(1);
my_system sys(0);
thrust::exclusive_scan(sys,
vec.begin(),
vec.begin(),
vec.begin());
ASSERT_EQUAL(true, sys.is_valid());
}
DECLARE_UNITTEST(TestExclusiveScanDispatchExplicit);
template<typename InputIterator,
typename OutputIterator>
OutputIterator exclusive_scan(my_tag,
InputIterator,
InputIterator,
OutputIterator result)
{
*result = 13;
return result;
}
void TestExclusiveScanDispatchImplicit()
{
thrust::device_vector<int> vec(1);
thrust::exclusive_scan(thrust::retag<my_tag>(vec.begin()),
thrust::retag<my_tag>(vec.begin()),
thrust::retag<my_tag>(vec.begin()));
ASSERT_EQUAL(13, vec.front());
}
DECLARE_UNITTEST(TestExclusiveScanDispatchImplicit);
void TestInclusiveScan32(void)
{
typedef int T;
size_t n = 32;
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::host_vector<T> h_output(n);
thrust::device_vector<T> d_output(n);
thrust::inclusive_scan(h_input.begin(), h_input.end(), h_output.begin());
thrust::inclusive_scan(d_input.begin(), d_input.end(), d_output.begin());
ASSERT_EQUAL(d_output, h_output);
}
DECLARE_UNITTEST(TestInclusiveScan32);
void TestExclusiveScan32(void)
{
typedef int T;
size_t n = 32;
T init = 13;
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::host_vector<T> h_output(n);
thrust::device_vector<T> d_output(n);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_output.begin(), init);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_output.begin(), init);
ASSERT_EQUAL(d_output, h_output);
}
DECLARE_UNITTEST(TestExclusiveScan32);
template <class IntVector, class FloatVector>
void TestScanMixedTypes(void)
{
// make sure we get types for default args and operators correct
IntVector int_input(4);
int_input[0] = 1;
int_input[1] = 2;
int_input[2] = 3;
int_input[3] = 4;
FloatVector float_input(4);
float_input[0] = 1.5;
float_input[1] = 2.5;
float_input[2] = 3.5;
float_input[3] = 4.5;
IntVector int_output(4);
FloatVector float_output(4);
// float -> int should use plus<void> operator and float accumulator by default
thrust::inclusive_scan(float_input.begin(), float_input.end(), int_output.begin());
ASSERT_EQUAL(int_output[0], 1); // in: 1.5 accum: 1.5f out: 1
ASSERT_EQUAL(int_output[1], 4); // in: 2.5 accum: 4.0f out: 4
ASSERT_EQUAL(int_output[2], 7); // in: 3.5 accum: 7.5f out: 7
ASSERT_EQUAL(int_output[3], 12); // in: 4.5 accum: 12.f out: 12
// float -> float with plus<int> operator (float accumulator)
thrust::inclusive_scan(float_input.begin(), float_input.end(), float_output.begin(), thrust::plus<int>());
ASSERT_EQUAL(float_output[0], 1.5f); // in: 1.5 accum: 1.5f out: 1.5f
ASSERT_EQUAL(float_output[1], 3.0f); // in: 2.5 accum: 3.0f out: 3.0f
ASSERT_EQUAL(float_output[2], 6.0f); // in: 3.5 accum: 6.0f out: 6.0f
ASSERT_EQUAL(float_output[3], 10.0f); // in: 4.5 accum: 10.f out: 10.f
// float -> int should use plus<void> operator and float accumulator by default
thrust::exclusive_scan(float_input.begin(), float_input.end(), int_output.begin());
ASSERT_EQUAL(int_output[0], 0); // out: 0.0f in: 1.5 accum: 1.5f
ASSERT_EQUAL(int_output[1], 1); // out: 1.5f in: 2.5 accum: 4.0f
ASSERT_EQUAL(int_output[2], 4); // out: 4.0f in: 3.5 accum: 7.5f
ASSERT_EQUAL(int_output[3], 7); // out: 7.5f in: 4.5 accum: 12.f
// float -> int should use plus<> operator and float accumulator by default
thrust::exclusive_scan(float_input.begin(), float_input.end(), int_output.begin(), (float) 5.5);
ASSERT_EQUAL(int_output[0], 5); // out: 5.5f in: 1.5 accum: 7.0f
ASSERT_EQUAL(int_output[1], 7); // out: 7.0f in: 2.5 accum: 9.5f
ASSERT_EQUAL(int_output[2], 9); // out: 9.5f in: 3.5 accum: 13.0f
ASSERT_EQUAL(int_output[3], 13); // out: 13.f in: 4.5 accum: 17.4f
// int -> float should use using plus<> operator and int accumulator by default
thrust::inclusive_scan(int_input.begin(), int_input.end(), float_output.begin());
ASSERT_EQUAL(float_output[0], 1.f); // in: 1 accum: 1 out: 1
ASSERT_EQUAL(float_output[1], 3.f); // in: 2 accum: 3 out: 3
ASSERT_EQUAL(float_output[2], 6.f); // in: 3 accum: 6 out: 6
ASSERT_EQUAL(float_output[3], 10.f); // in: 4 accum: 10 out: 10
// int -> float + float init_value should use using plus<> operator and
// float accumulator by default
thrust::exclusive_scan(int_input.begin(), int_input.end(), float_output.begin(), (float) 5.5);
ASSERT_EQUAL(float_output[0], 5.5f); // out: 5.5f in: 1 accum: 6.5f
ASSERT_EQUAL(float_output[1], 6.5f); // out: 6.0f in: 2 accum: 8.5f
ASSERT_EQUAL(float_output[2], 8.5f); // out: 8.0f in: 3 accum: 11.5f
ASSERT_EQUAL(float_output[3], 11.5f); // out: 11.f in: 4 accum: 15.5f
}
void TestScanMixedTypesHost(void)
{
TestScanMixedTypes< thrust::host_vector<int>, thrust::host_vector<float> >();
}
DECLARE_UNITTEST(TestScanMixedTypesHost);
void TestScanMixedTypesDevice(void)
{
TestScanMixedTypes< thrust::device_vector<int>, thrust::device_vector<float> >();
}
DECLARE_UNITTEST(TestScanMixedTypesDevice);
template <typename T>
struct TestScanWithOperator
{
void operator()(const size_t n)
{
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::host_vector<T> h_output(n);
thrust::device_vector<T> d_output(n);
thrust::inclusive_scan(h_input.begin(), h_input.end(), h_output.begin(), max_functor<T>());
thrust::inclusive_scan(d_input.begin(), d_input.end(), d_output.begin(), max_functor<T>());
ASSERT_EQUAL(d_output, h_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_output.begin(), T(13), max_functor<T>());
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_output.begin(), T(13), max_functor<T>());
ASSERT_EQUAL(d_output, h_output);
}
};
VariableUnitTest<TestScanWithOperator, SignedIntegralTypes> TestScanWithOperatorInstance;
template <typename T>
struct TestScanWithOperatorToDiscardIterator
{
void operator()(const size_t n)
{
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::discard_iterator<> reference(n);
thrust::discard_iterator<> h_result =
thrust::inclusive_scan(h_input.begin(), h_input.end(), thrust::make_discard_iterator(), max_functor<T>());
thrust::discard_iterator<> d_result =
thrust::inclusive_scan(d_input.begin(), d_input.end(), thrust::make_discard_iterator(), max_functor<T>());
ASSERT_EQUAL_QUIET(reference, h_result);
ASSERT_EQUAL_QUIET(reference, d_result);
h_result =
thrust::exclusive_scan(h_input.begin(), h_input.end(), thrust::make_discard_iterator(), T(13), max_functor<T>());
d_result =
thrust::exclusive_scan(d_input.begin(), d_input.end(), thrust::make_discard_iterator(), T(13), max_functor<T>());
ASSERT_EQUAL_QUIET(reference, h_result);
ASSERT_EQUAL_QUIET(reference, d_result);
}
};
VariableUnitTest<TestScanWithOperatorToDiscardIterator, unittest::type_list<unittest::int8_t,unittest::int16_t,unittest::int32_t> > TestScanWithOperatorToDiscardIteratorInstance;
template <typename T>
struct TestScan
{
void operator()(const size_t n)
{
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::host_vector<T> h_output(n);
thrust::device_vector<T> d_output(n);
thrust::inclusive_scan(h_input.begin(), h_input.end(), h_output.begin());
thrust::inclusive_scan(d_input.begin(), d_input.end(), d_output.begin());
ASSERT_EQUAL(d_output, h_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_output.begin());
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_output.begin());
ASSERT_EQUAL(d_output, h_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_output.begin(), (T) 11);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_output.begin(), (T) 11);
ASSERT_EQUAL(d_output, h_output);
// in-place scans
h_output = h_input;
d_output = d_input;
thrust::inclusive_scan(h_output.begin(), h_output.end(), h_output.begin());
thrust::inclusive_scan(d_output.begin(), d_output.end(), d_output.begin());
ASSERT_EQUAL(d_output, h_output);
h_output = h_input;
d_output = d_input;
thrust::exclusive_scan(h_output.begin(), h_output.end(), h_output.begin());
thrust::exclusive_scan(d_output.begin(), d_output.end(), d_output.begin());
ASSERT_EQUAL(d_output, h_output);
}
};
VariableUnitTest<TestScan, IntegralTypes> TestScanInstance;
template <typename T>
struct TestScanToDiscardIterator
{
void operator()(const size_t n)
{
thrust::host_vector<T> h_input = unittest::random_integers<T>(n);
thrust::device_vector<T> d_input = h_input;
thrust::discard_iterator<> h_result =
thrust::inclusive_scan(h_input.begin(), h_input.end(), thrust::make_discard_iterator());
thrust::discard_iterator<> d_result =
thrust::inclusive_scan(d_input.begin(), d_input.end(), thrust::make_discard_iterator());
thrust::discard_iterator<> reference(n);
ASSERT_EQUAL_QUIET(reference, h_result);
ASSERT_EQUAL_QUIET(reference, d_result);
h_result =
thrust::exclusive_scan(h_input.begin(), h_input.end(), thrust::make_discard_iterator(), (T) 11);
d_result =
thrust::exclusive_scan(d_input.begin(), d_input.end(), thrust::make_discard_iterator(), (T) 11);
ASSERT_EQUAL_QUIET(reference, h_result);
ASSERT_EQUAL_QUIET(reference, d_result);
}
};
VariableUnitTest<TestScanToDiscardIterator, unittest::type_list<unittest::int8_t,unittest::int16_t,unittest::int32_t> > TestScanToDiscardIteratorInstance;
void TestScanMixedTypes(void)
{
const unsigned int n = 113;
thrust::host_vector<unsigned int> h_input = unittest::random_integers<unsigned int>(n);
for(size_t i = 0; i < n; i++)
h_input[i] %= 10;
thrust::device_vector<unsigned int> d_input = h_input;
thrust::host_vector<float> h_float_output(n);
thrust::device_vector<float> d_float_output(n);
thrust::host_vector<int> h_int_output(n);
thrust::device_vector<int> d_int_output(n);
//mixed input/output types
thrust::inclusive_scan(h_input.begin(), h_input.end(), h_float_output.begin());
thrust::inclusive_scan(d_input.begin(), d_input.end(), d_float_output.begin());
ASSERT_EQUAL(d_float_output, h_float_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_float_output.begin(), (float) 3.5);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_float_output.begin(), (float) 3.5);
ASSERT_EQUAL(d_float_output, h_float_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_float_output.begin(), (int) 3);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_float_output.begin(), (int) 3);
ASSERT_EQUAL(d_float_output, h_float_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_int_output.begin(), (int) 3);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_int_output.begin(), (int) 3);
ASSERT_EQUAL(d_int_output, h_int_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_int_output.begin(), (float) 3.5);
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_int_output.begin(), (float) 3.5);
ASSERT_EQUAL(d_int_output, h_int_output);
}
DECLARE_UNITTEST(TestScanMixedTypes);
template <typename T, unsigned int N>
void _TestScanWithLargeTypes(void)
{
size_t n = (1024 * 1024) / sizeof(FixedVector<T,N>);
thrust::host_vector< FixedVector<T,N> > h_input(n);
thrust::host_vector< FixedVector<T,N> > h_output(n);
for(size_t i = 0; i < h_input.size(); i++)
h_input[i] = FixedVector<T,N>(i);
thrust::device_vector< FixedVector<T,N> > d_input = h_input;
thrust::device_vector< FixedVector<T,N> > d_output(n);
thrust::inclusive_scan(h_input.begin(), h_input.end(), h_output.begin());
thrust::inclusive_scan(d_input.begin(), d_input.end(), d_output.begin());
ASSERT_EQUAL_QUIET(h_output, d_output);
thrust::exclusive_scan(h_input.begin(), h_input.end(), h_output.begin(), FixedVector<T,N>(0));
thrust::exclusive_scan(d_input.begin(), d_input.end(), d_output.begin(), FixedVector<T,N>(0));
ASSERT_EQUAL_QUIET(h_output, d_output);
}
void TestScanWithLargeTypes(void)
{
_TestScanWithLargeTypes<int, 1>();
#if !defined(__QNX__)
_TestScanWithLargeTypes<int, 8>();
_TestScanWithLargeTypes<int, 64>();
#else
KNOWN_FAILURE;
#endif
}
DECLARE_UNITTEST(TestScanWithLargeTypes);
template <typename T>
struct plus_mod3
{
T * table;
plus_mod3(T * table) : table(table) {}
__host__ __device__
T operator()(T a, T b)
{
return table[(int) (a + b)];
}
};
template <typename Vector>
void TestInclusiveScanWithIndirection(void)
{
// add numbers modulo 3 with external lookup table
typedef typename Vector::value_type T;
Vector data(7);
data[0] = 0;
data[1] = 1;
data[2] = 2;
data[3] = 1;
data[4] = 2;
data[5] = 0;
data[6] = 1;
Vector table(6);
table[0] = 0;
table[1] = 1;
table[2] = 2;
table[3] = 0;
table[4] = 1;
table[5] = 2;
thrust::inclusive_scan(data.begin(), data.end(), data.begin(), plus_mod3<T>(thrust::raw_pointer_cast(&table[0])));
ASSERT_EQUAL(data[0], T(0));
ASSERT_EQUAL(data[1], T(1));
ASSERT_EQUAL(data[2], T(0));
ASSERT_EQUAL(data[3], T(1));
ASSERT_EQUAL(data[4], T(0));
ASSERT_EQUAL(data[5], T(0));
ASSERT_EQUAL(data[6], T(1));
}
DECLARE_INTEGRAL_VECTOR_UNITTEST(TestInclusiveScanWithIndirection);
struct only_set_when_expected_it
{
long long expected;
bool * flag;
__host__ __device__ only_set_when_expected_it operator++() const { return *this; }
__host__ __device__ only_set_when_expected_it operator*() const { return *this; }
template<typename Difference>
__host__ __device__ only_set_when_expected_it operator+(Difference) const { return *this; }
template<typename Index>
__host__ __device__ only_set_when_expected_it operator[](Index) const { return *this; }
__device__
void operator=(long long value) const
{
if (value == expected)
{
*flag = true;
}
}
};
namespace thrust
{
template<>
struct iterator_traits<only_set_when_expected_it>
{
typedef long long value_type;
typedef only_set_when_expected_it reference;
};
}
void TestInclusiveScanWithBigIndexesHelper(int magnitude)
{
thrust::constant_iterator<long long> begin(1);
thrust::constant_iterator<long long> end = begin + (1ll << magnitude);
ASSERT_EQUAL(thrust::distance(begin, end), 1ll << magnitude);
thrust::device_ptr<bool> has_executed = thrust::device_malloc<bool>(1);
*has_executed = false;
only_set_when_expected_it out = { (1ll << magnitude), thrust::raw_pointer_cast(has_executed) };
thrust::inclusive_scan(thrust::device, begin, end, out);
bool has_executed_h = *has_executed;
thrust::device_free(has_executed);
ASSERT_EQUAL(has_executed_h, true);
}
void TestInclusiveScanWithBigIndexes()
{
TestInclusiveScanWithBigIndexesHelper(30);
TestInclusiveScanWithBigIndexesHelper(31);
TestInclusiveScanWithBigIndexesHelper(32);
TestInclusiveScanWithBigIndexesHelper(33);
}
DECLARE_UNITTEST(TestInclusiveScanWithBigIndexes);
void TestExclusiveScanWithBigIndexesHelper(int magnitude)
{
thrust::constant_iterator<long long> begin(1);
thrust::constant_iterator<long long> end = begin + (1ll << magnitude);
ASSERT_EQUAL(thrust::distance(begin, end), 1ll << magnitude);
thrust::device_ptr<bool> has_executed = thrust::device_malloc<bool>(1);
*has_executed = false;
only_set_when_expected_it out = { (1ll << magnitude) - 1, thrust::raw_pointer_cast(has_executed) };
thrust::exclusive_scan(thrust::device, begin, end, out,0ll);
bool has_executed_h = *has_executed;
thrust::device_free(has_executed);
ASSERT_EQUAL(has_executed_h, true);
}
void TestExclusiveScanWithBigIndexes()
{
TestExclusiveScanWithBigIndexesHelper(30);
TestExclusiveScanWithBigIndexesHelper(31);
TestExclusiveScanWithBigIndexesHelper(32);
TestExclusiveScanWithBigIndexesHelper(33);
}
DECLARE_UNITTEST(TestExclusiveScanWithBigIndexes);
#if THRUST_CPP_DIALECT >= 2011
struct Int {
int i{};
__host__ __device__ explicit Int(int num) : i(num) {}
__host__ __device__ Int() : i{} {}
__host__ __device__ Int operator+(Int const& o) const { return Int{this->i + o.i}; }
};
void TestInclusiveScanWithUserDefinedType()
{
thrust::device_vector<Int> vec(5, Int{1});
thrust::inclusive_scan(
thrust::device,
vec.cbegin(),
vec.cend(),
vec.begin());
ASSERT_EQUAL(static_cast<Int>(vec.back()).i, 5);
}
DECLARE_UNITTEST(TestInclusiveScanWithUserDefinedType);
#endif // c++11