CUDA推力:根据“a”中的值,仅对数组中的某些值按“U”键减少“U”;“关键”;排列

CUDA推力:根据“a”中的值,仅对数组中的某些值按“U”键减少“U”;“关键”;排列,cuda,gpu,thrust,reduction,Cuda,Gpu,Thrust,Reduction,假设我有两个设备向量数组,d\u键和d\u数据 例如,如果d_数据是一个扁平的2D 3x5数组(例如{1,2,3,4,5,6,7,8,9,8,7,6,5,4,3}),并且d_键是一个大小为5的1D数组(例如{1,0,0,1,1}),我如何进行缩减,以便在相应的d_键值为1时,我只能在每行基础上添加值(例如,结果是{10,23,14}) 该示例允许我添加d_data中的每个值,但这并不完全正确 或者,我可以在每行的基础上,使用一个zip_迭代器,将d_键与一行d_数据组合,并执行transform

假设我有两个设备向量数组,
d\u键
d\u数据

例如,如果
d_数据
是一个扁平的2D 3x5数组(例如{1,2,3,4,5,6,7,8,9,8,7,6,5,4,3}),并且
d_键
是一个大小为5的1D数组(例如{1,0,0,1,1}),我如何进行缩减,以便在相应的
d_键
值为1时,我只能在每行基础上添加值(例如,结果是{10,23,14})

该示例允许我添加
d_data
中的每个值,但这并不完全正确

或者,我可以在每行的基础上,使用一个
zip_迭代器
,将
d_键
与一行
d_数据
组合,并执行
transform_reduce
,仅在键值为1时添加,但随后我必须循环通过
d_数据
数组


我真正需要的是某种不是内置的
transform\u reduce\u by\u key
功能,但肯定有办法做到这一点!

以下是一些示例代码,使用我在您问题下方的评论中概述的方法,实现类似您所追求的功能。事实上,我们希望使用4元组来获取您的密钥值。在此处复制经过适当修改的注释:


你可以制作一个zip迭代器,将你的3行加上键“row”,并将一个4元组传递给一个特殊的函子。然后,你的特殊函子将对3元组数组进行缩减(也使用键),并返回一个4元组的结果。这个要点可能会给你一些想法

这是一种可能的方法:

#include <thrust/host_vector.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/sequence.h>
#include <thrust/fill.h>
#include <thrust/tuple.h>

#define N 30  // make this evenly divisible by 3 for this example

typedef thrust::tuple<int, int, int, int>  tpl4int;
typedef thrust::host_vector<int>::iterator intiter;
typedef thrust::tuple<intiter, intiter, intiter, intiter>  tpl4intiter;
typedef thrust::zip_iterator<tpl4intiter>  int4zip;



struct r3key_unary_op : public thrust::unary_function<tpl4int, tpl4int>
{
  __host__ __device__
  tpl4int operator()(const tpl4int& x) const
  {
    tpl4int result;
    thrust::get<0>(result) = x.get<0>()*x.get<3>();
    thrust::get<1>(result) = x.get<1>()*x.get<3>();
    thrust::get<2>(result) = x.get<2>()*x.get<3>();
    thrust::get<3>(result) = 1;
    return result;
   }
};

struct r3key_binary_op : public thrust::binary_function<tpl4int, tpl4int, tpl4int>
{
  __host__ __device__
  tpl4int operator()(const tpl4int& x, const tpl4int& y) const
  {
    tpl4int result;
    thrust::get<0>(result) = x.get<0>()*x.get<3>() + y.get<0>()*y.get<3>();
    thrust::get<1>(result) = x.get<1>()*x.get<3>() + y.get<1>()*y.get<3>();
    thrust::get<2>(result) = x.get<2>()*x.get<3>() + y.get<2>()*y.get<3>();
    thrust::get<3>(result) = 1;
    return result;
  }
};


int main() {

  thrust::host_vector<int> A(N);  // values, in 3 "rows" flattened
  thrust::sequence(A.begin(), A.end());
  thrust::host_vector<int> K(N/3);   // keys in one row
  thrust::fill(K.begin(), K.end(), 1);  // set some keys to 1
  K[9] = 0;  // set some keys to zero

  int4zip first = thrust::make_zip_iterator(thrust::make_tuple(A.begin(), A.begin() + N/3, A.begin() + 2*N/3, K.begin()));
  int4zip  last = thrust::make_zip_iterator(thrust::make_tuple(A.begin() + N/3, A.begin() + 2*N/3, A.end(), K.end()));
  r3key_unary_op my_unary_op;
  r3key_binary_op my_binary_op;
  tpl4int init = my_unary_op(*first);
  // init = thrust::make_tuple((int) 0, (int) 0, (int) 0, (int) 0);
  tpl4int result = thrust::transform_reduce(first, last, my_unary_op, init, my_binary_op);
  std::cout << "row 0 = " << result.get<0>() << std::endl;
  std::cout << "row 1 = " << result.get<1>() << std::endl;
  std::cout << "row 2 = " << result.get<2>() << std::endl;
  return 0;

}
#包括
#包括
#包括
#包括
#包括
#定义n30//在本例中,使其可被3整除
typedef推力::元组tpl4int;
typedef推力::主机向量::迭代器intiter;
typedef推力::元组tpl4intter;
typedef推力::zip_迭代器int4zip;
结构r3key\u一元函数:公共推力::一元函数
{
__主机设备__
tpl4int运算符()(常数tpl4int&x)常数
{
tpl4int结果;
推力::获取(结果)=x.get()*x.get();
推力::获取(结果)=x.get()*x.get();
推力::获取(结果)=x.get()*x.get();
推力:get(结果)=1;
返回结果;
}
};
结构r3key\u binary\u op:公共推力::binary\u函数
{
__主机设备__
tpl4int运算符()(常数tpl4int&x,常数tpl4int&y)常数
{
tpl4int结果;
推力::获取(结果)=x.get()*x.get()+y.get()*y.get();
推力::获取(结果)=x.get()*x.get()+y.get()*y.get();
推力::获取(结果)=x.get()*x.get()+y.get()*y.get();
推力:get(结果)=1;
返回结果;
}
};
int main(){
推力::主机_向量A(N);//值,在3行中展平
推力:顺序(A.begin(),A.end());
推力::主机_向量K(N/3);//一行中的键
推力::填充(K.begin(),K.end(),1);//将一些键设置为1
K[9]=0;//将一些键设置为零
int4zip first=推力::make_-zip_迭代器(推力::make_元组(A.begin(),A.begin()+N/3,A.begin()+2*N/3,K.begin());
int4zip last=推力::make_-zip_迭代器(推力::make_元组(A.begin()+N/3,A.begin()+2*N/3,A.end(),K.end());
r3key_-uniary_-op my_-uniary_-op;
r3key_binary_op my_binary_op;
tpl4int init=我的一元运算(*第一);
//init=推力::生成元组((int)0,(int)0,(int)0,(int)0,(int)0);
tpl4int result=推力::变换减少(第一个、最后一个、我的一元数、初始化、我的二进制数);

std::cout根据附加注释,即不是3行而是数千行,我们可以编写一个转换函子,对整行求和。基于数千行的事实,这应该会让机器非常繁忙:

#include <iostream>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/transform.h>
#include <thrust/sequence.h>
#include <thrust/fill.h>

#define ROW   20
#define COL   10

__device__ int *vals;
__device__ int *keys;

struct test_functor
{
  const int a;

  test_functor(int _a) : a(_a) {}

  __device__
  int operator()(int& x, int& y ) {
    int temp = 0;
    for (int i = 0; i<a; i++)
      temp += vals[i + (y*a)] * keys[i];
    return temp;
    }
};

int main(){
  int *s_vals, *s_keys;
  thrust::host_vector<int> h_vals(ROW*COL);
  thrust::host_vector<int> h_keys(COL);
  thrust::sequence(h_vals.begin(), h_vals.end());
  thrust::fill(h_keys.begin(), h_keys.end(), 1);
  h_keys[0] = 0;
  thrust::device_vector<int> d_vals = h_vals;
  thrust::device_vector<int> d_keys = h_keys;
  thrust::device_vector<int> d_sums(ROW);
  thrust::fill(d_sums.begin(), d_sums.end(), 0);
  s_vals = thrust::raw_pointer_cast(&d_vals[0]);
  s_keys = thrust::raw_pointer_cast(&d_keys[0]);
  cudaMemcpyToSymbol(vals, &s_vals, sizeof(int *));
  cudaMemcpyToSymbol(keys, &s_keys, sizeof(int *));
  thrust::device_vector<int> d_idx(ROW);
  thrust::sequence(d_idx.begin(), d_idx.end());
  thrust::transform(d_sums.begin(), d_sums.end(), d_idx.begin(),  d_sums.begin(), test_functor(COL));
  thrust::host_vector<int> h_sums = d_sums;
  std::cout << "Results :" << std::endl;
  for (unsigned i = 0; i<ROW; i++)
    std::cout<<"h_sums["<<i<<"] = " << h_sums[i] << std::endl;
  return 0;
}

如果愿意,您可以将ROW作为附加参数传递给functor。

您可以制作一个zip迭代器,将3行压缩在一起,并将一个3元组传递给一个特殊的functor。然后,您的特殊functor将对3元组数组进行缩减,并返回一个3元组的结果。这可能会给您一些想法包含数千行。将它们压缩到一个元组似乎不太实际。我还相信您可以结合一些想法(在压缩迭代器中使用计数迭代器来传递元素的索引值)在我发布的第一个示例中,您提到了sum_rows.cu示例,该示例使用一个将求和条件设置为与要求和的元素索引相关联的键值的方法来替换该示例中使用的推力::plus运算符。谢谢!在特斯拉C2070上,缓存似乎不够宽容!列主格式事实证明速度快了一点。我仍然认为可能会进一步提高成绩,但这确实完成了任务,它教会了我一两件事!谢谢!
for (int i=0; i<a; i++)
  temp += vals[(i*ROW)+y]*keys[i];