スラストでインターリーブされたデータを操作する最良の方法は何ですか。たとえば、インターリーブ長が 3 の値を追加したいとします。
[1, 2, 3, 4, 5, 6]
与えるだろう
[6, 15]
またはデータのインターリーブを解除するため、
[1, 2, 3, 4, 5, 6, 7, 8, 9]
与えるだろう
[1, 4, 7, 2, 5, 8, 3, 6, 9]
ありがとう
ここで 2 つの質問があります。1 つ目は、データ セットに対して構造化された削減を実行する方法を尋ね、2 つ目は、マッピングを指定してデータ セットを並べ替える方法を尋ねます。
最初の問題は、データ セットを規則的なサイズのサブセットのコレクションに論理的に分割し、各サブセットに対してリダクションを実行することで解決できます。reduce_by_key
スラストでは、変換された と組み合わせることでこれを行うことができますcounting_iterator
。アイデアは、各データムをそのサブセットのインデックスで「キー」することです。reduce_by_key
連続するすべてのデータムを等しいキーで合計します。
2 番目の問題は、データ セットの順序を変更することで解決できます。への呼び出しでこれを行うことができますgather
。ここで、変換counting_iterator
された は、元の配列から並べ替えられた配列へのインデックスのマッピングを伝達できます。を使用して、このような収集操作を他のアルゴリズム ( などtransform
)と融合することもできpermutation_iterator
ます。その方法については、サンプル プログラムを参照してください。
とはいえ、配列の並べ替えは、メモリの合体の問題により GPU でコストがかかるため、慎重に行う必要があります。
2つの問題を解決する完全なプログラムは次のとおりです。
#include <thrust/device_vector.h>
#include <thrust/reduce.h>
#include <thrust/gather.h>
#include <thrust/functional.h>
struct divide_by_three
: thrust::unary_function<unsigned int, unsigned int>
{
__host__ __device__
unsigned int operator()(unsigned int i)
{
return i / 3;
}
};
struct deinterleave_index
: thrust::unary_function<unsigned int, unsigned int>
{
__host__ __device__
unsigned int operator()(unsigned int i)
{
return (i/3) + 3 * (i%3);
}
};
int main()
{
using namespace thrust;
device_vector<int> example_one(6);
example_one[0] = 1; example_one[1] = 2; example_one[2] = 3;
example_one[3] = 4; example_one[4] = 5; example_one[5] = 6;
// the result will have size two
device_vector<int> example_one_result(2);
// for each datum, associate an key, which is the datum's index divided by three
// reduce the data by key
reduce_by_key(make_transform_iterator(make_counting_iterator(0u), divide_by_three()),
make_transform_iterator(make_counting_iterator(6u), divide_by_three()),
example_one.begin(),
thrust::make_discard_iterator(),
example_one_result.begin());
std::cout << "example one input: [ ";
thrust::copy(example_one.begin(), example_one.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "]" << std::endl;
std::cout << "example one result: [ ";
thrust::copy(example_one_result.begin(), example_one_result.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "]" << std::endl;
device_vector<int> example_two(9);
example_two[0] = 1; example_two[1] = 2; example_two[2] = 3;
example_two[3] = 4; example_two[4] = 5; example_two[5] = 6;
example_two[6] = 7; example_two[7] = 8; example_two[8] = 9;
// the result will be the same size
device_vector<int> example_two_result(9);
// gather using the mapping defined by deinterleave_index
gather(make_transform_iterator(make_counting_iterator(0u), deinterleave_index()),
make_transform_iterator(make_counting_iterator(9u), deinterleave_index()),
example_two.begin(),
example_two_result.begin());
std::cout << "example two input: [ ";
thrust::copy(example_two.begin(), example_two.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "]" << std::endl;
std::cout << "example two result: [ ";
thrust::copy(example_two_result.begin(), example_two_result.end(), std::ostream_iterator<int>(std::cout, " "));
std::cout << "]" << std::endl;
return 0;
}
そして出力:
$ nvcc test.cu -run
example one input: [ 1 2 3 4 5 6 ]
example one result: [ 6 15 ]
example two input: [ 1 2 3 4 5 6 7 8 9 ]
example two result: [ 1 4 7 2 5 8 3 6 9 ]