如何在 Thrust 的大一维数组中重新排序固定大小的子数组

How to reorder subarrays of fixed size inside a big 1D array in Thrust

我有 100000 个数组存储在一个大的一维数组中。 每个数组的大小为L =1000,降序排列。

每个数组分为m=5段。(S1,S2,S3,S4,S5) 例如:

A1=[S1,S2,S3,S4,S5]
A2=[S1,S2,S3,S4,S5]
A3=[S1,S2,S3,S4,S5]
…
A100000=[S1,S2,S3,S4,S5]

这里以大容器数组为例如下:

我的问题是:

对于 w=10 个数组中的每个 window(例如)我想按如下方式重组这 10 个数组: 先放这10个数组的S1段,再放S2段,S3段……。 以下是 w =6 的示例:

作为信息 L 、 m 和 w 是可以取不同值的参数。

有没有使用 Thrust 的快速方法?

该方法与所描述的内容非常相似

  1. 构造一个将输入映射到输出的映射向量(即迭代器生成的序列)。我们将使用 thrust::counting_iterator 来提供序数序列 0, 1, 2,...,然后使用 thrust::transform_iterator 构造映射迭代器。挑战在于为传递给变换迭代器的操作创建正确的算法。下面的代码被广泛注释以解释这一点。
  2. 通过 thrust::permutation_iterator 将地图矢量传递给 thrust::copy_n。请注意,有时最好的建议是不要复制数据。如果您只使用一次 "transformed view" 数据,则只需将该排列迭代器传递给您使用一次的任何推力算法,而不是实际复制数据。如果需要多次使用数据的"transformed view",复制一次可能效率更高

这是一个有效的例子:

$ cat t5.cu
#include <thrust/sequence.h>
#include <thrust/iterator/permutation_iterator.h>
#include <thrust/iterator/transform_iterator.h>
#include <thrust/iterator/discard_iterator.h>
#include <thrust/device_vector.h>
#include <thrust/copy.h>
#include <iostream>

typedef int dtype;  // data type
typedef int itype;  // indexing type - change to size_t if L*m*s > int
const itype s = 3;  // segment_width
const itype m = 2;  // number of segments per sub-array
const itype L = 4;  // number of sub-arrays per array
const itype w = 2;  // width of group (# of sub-arrays) for segment reordering
// S1 S1 S2 S2 S1 S1 S2 S2
//  0  1  2  6  7  8  3  4  5  9 10 11 12 13 14 18 19 20 15 16 17 21 22 23

using namespace thrust::placeholders;

int main(){
// we require data that consists of L*m*s elements
// we also require L to be whole-number divisible by w
  thrust::device_vector<dtype> d_data(L*m*s);
  thrust::device_vector<dtype> d_result(L*m*s);
  thrust::sequence(d_data.begin(), d_data.end());
// we will build up the necessary map iterator progressively
// we will start with an target_index sequence i =              0, 1, 2, 3, 4, 5, ... which defines the location in the target vector
// seg_idx    (position within a segment) = i%s                 0, 1, 2, 0, 1, 2, ...
// which_seg  (which segment within sub-array) = (i/(w*s))%m    0, 0, 0, 0, 0, 0, 1, ...
// which_sub  (which sub-array in group) = (i/s)%w              0, 0, 0, 1, 1, 1, 0, ...
// which_grp  (which group in array) = i/(w*s*m)                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 ...
// map index = which_grp*group_width + which_sub*subarray_width + which_seg*segment_width + seg_idx
// map index = (i/(w*s*m))*(w*s*m) + ((i/s)%w)*(s*m) + ((i/(w*s))%m)*s + i%s
  thrust::copy_n(thrust::make_permutation_iterator(d_data.begin(), thrust::make_transform_iterator(thrust::counting_iterator<itype>(0), (_1/(w*s*m))*(w*s*m) + ((_1/s)%w)*(s*m) + ((_1/(w*s))%m)*s + _1%s)), L*m*s, d_result.begin());
  thrust::copy(d_result.begin(), d_result.end(), std::ostream_iterator<dtype>(std::cout, ","));
  std::cout << std::endl;
}
$ nvcc -o t5 t5.cu
$ ./t5
0,1,2,6,7,8,3,4,5,9,10,11,12,13,14,18,19,20,15,16,17,21,22,23,
$

请注意,如果总数据长度 (L*m*s) 大于 int 数量中可以容纳的长度,则必须重构上述代码以使用 size_t 而不是 int 用于 itype 类型定义。