给出4个向量:
int indx(nshape);
float dnx(nshape);
/* nshape > nord */
int indy(nord);
float dny(nord);
indx和indy是包含全局坐标的索引向量(分别为值dnx,dny的键)。在解析这个期望的交错/拼接函数之前,它们的全局范围是未知的。所有已知的是可能的局部范围的长度可以是[0,nord * nord]以及向量indx和indy中的最大值和最小值。
我想创建包含dnx和dny原始值的相同长度的新向量dn1和dn2,但是扩展为用原始向量填充原始向量dnx和dny用于它们不包含的所有全局坐标另一个向量。它们将形成需要全局地址对齐的外部产品的载体。
我无法在网上找到任何在c ++中使用逻辑掩码的参考资料,例如在fortran中进行并行化。我的出发点是使用推力库stable_sort以升序,binary_search来比较数组,分区等。也许有一种清晰简洁的方法。
下面的示例索引和值vecs通常不会从0开始,也不会与临时索引向量的本地寻址一致,也不会出现任何奇怪的模式 - 这些值只是为了帮助说明。)
indx[]={0,2,4,6,8,10,12}; indy[]={1, 2, 3, 4};
dnx[]={99,99,99,99,99,99,99}; dny[]={66,66,66,66};
ind[]={0,1,2,3,4,6,8,10,12}
dn1[]={99,0,99,0,99,99,99,99,99}
dn2[]={0,66,66,66,66,0,0,0,0}
之前我做了类似下面的内容,其中内核应用了比较,填充和流程基于以下条件,并继续通过这些条件行之一再次进入,直到最大的本地索引超过最大向量i的长度, ei,j> nshape:
3
if(indx[i] < indy[j]{kernel_1; i++; if(i > nshape){return}; goto 3}
if(indx[i] == indy[j]){kernel_2;i++;j++; if(i || j > nshape) {return}; goto 3}
if(indx[i] > indy[j]{kernel_3, j++, if(j>nshape){return}; goto 3}
对于mongrel伪代码抱歉。我非常期待任何想法或更好的解决方案与c ++,cuda,推力。 非常感谢。 标记
答案 0 :(得分:1)
我遇到的一种方法是进行并行二进制搜索,从全局索引向量中获取每个值,并查看它是否在键向量中匹配。如果它在键向量中有匹配,则将相应的值放在结果中。如果它在关键向量中没有匹配,则在结果中放置0。
所以对于每个职位:
ind[]={0,1,2,3,4,6,8,10,12}
查看是否存在匹配的索引:
indy[]={1, 2, 3, 4};
我们将使用并行二进制搜索来执行此操作,并返回相应的索引(indy
中的匹配值)。
如果我们找到匹配项,那么在结果中的相关位置,我们将放置对应于indy[matching_index]
的值,即。 dny[matching_index]
。否则在结果中加零。
在推力的情况下,我能够将其减少到两个推力调用。
第一个是thrust::lower_bound
操作,它实际上是矢量化/并行二进制搜索。就像在CUDA情况下一样,我们使用二进制搜索来获取全局向量的每个元素(ind
)并查看关键向量中是否存在匹配(例如indx
),返回索引键向量中的匹配位置(下界)。
第二个电话使用thrust::for_each
有点复杂。我们为extend_functor
操作创建了一个特殊的仿函数(for_each
),该函数使用指向键向量开始的指针(例如indx
)进行初始化,其长度以及指向值向量的指针(例如dnx
)。然后extend_functor
采用全局向量的3元组,下界向量和结果向量值,并执行剩余步骤。如果下限值在键向量的长度内,则检查下限是否在键向量和全局向量之间产生匹配。如果是,则将相应的值放入结果向量中,否则将0置于结果向量中。
以下代码使用CUDA实现此功能,并使用推力。
#include <iostream>
#include <thrust/device_vector.h>
#include <thrust/binary_search.h>
#include <thrust/copy.h>
#define MAX_DSIZE 32768
#define nTPB 256
struct extend_functor
{
int vec_len;
int *vec1;
float *vec2;
extend_functor(int *_vec1, int _vec_len, float *_vec2) : vec1(_vec1), vec2(_vec2), vec_len(_vec_len) {};
template <typename Tuple>
__device__ __host__
void operator()(const Tuple &my_tuple) {
float result = 0.0f;
if (thrust::get<1>(my_tuple) < vec_len)
if (thrust::get<0>(my_tuple) == vec1[thrust::get<1>(my_tuple)]) result = vec2[thrust::get<1>(my_tuple)];
thrust::get<2>(my_tuple) = result;
}
};
// binary search, looking for key in a
__device__ void bsearch_range(const int *a, const int key, const unsigned len_a, unsigned *idx){
unsigned lower = 0;
unsigned upper = len_a;
unsigned midpt;
while (lower < upper){
midpt = (lower + upper)>>1;
if (a[midpt] < key) lower = midpt +1;
else upper = midpt;
}
*idx = lower;
return;
}
// k is the key vector
// g is the global index vector
// v is the value vector
// r is the result vector
__global__ void extend_kernel(const int *k, const unsigned len_k, const int *g, const unsigned len_g, const float *v, float *r){
unsigned idx = (blockDim.x * blockIdx.x) + threadIdx.x;
if (idx < len_g) {
unsigned my_idx;
int g_key = g[idx];
bsearch_range(k, g_key, len_k, &my_idx);
int my_key = -1;
if (my_idx < len_k)
my_key = k[my_idx];
float my_val;
if (g_key == my_key) my_val = v[my_idx];
else my_val = 0.0f;
r[idx] = my_val;
}
}
int main(){
int len_x = 7;
int len_y = 4;
int len_g = 9;
int indx[]={0,2,4,6,8,10,12};
int indy[]={1, 2, 3, 4};
float dnx[]={91.0f,92.0f,93.0f,94.0f,95.0f,96.0f,97.0f};
float dny[]={61.0f,62.0f,63.0f,64.0f};
int ind[]={0,1,2,3,4,6,8,10,12};
int *h_k, *d_k, *h_g, *d_g;
float *h_v, *d_v, *h_r, *d_r;
h_k = (int *)malloc(MAX_DSIZE*sizeof(int));
h_g = (int *)malloc(MAX_DSIZE*sizeof(int));
h_v = (float *)malloc(MAX_DSIZE*sizeof(float));
h_r = (float *)malloc(MAX_DSIZE*sizeof(float));
cudaMalloc(&d_k, MAX_DSIZE*sizeof(int));
cudaMalloc(&d_g, MAX_DSIZE*sizeof(int));
cudaMalloc(&d_v, MAX_DSIZE*sizeof(float));
cudaMalloc(&d_r, MAX_DSIZE*sizeof(float));
// test case x
memcpy(h_k, indx, len_x*sizeof(int));
memcpy(h_g, ind, len_g*sizeof(int));
memcpy(h_v, dnx, len_x*sizeof(float));
cudaMemcpy(d_k, h_k, len_x*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_g, h_g, len_g*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_v, h_v, len_x*sizeof(float), cudaMemcpyHostToDevice);
extend_kernel<<<(len_g+nTPB-1)/nTPB, nTPB >>>(d_k, len_x, d_g, len_g, d_v, d_r);
cudaMemcpy(h_r, d_r, len_g*sizeof(float), cudaMemcpyDeviceToHost);
std::cout << "case x result: ";
for (int i=0; i < len_g; i++)
std::cout << h_r[i] << " ";
std::cout << std::endl;
// test case y
memcpy(h_k, indy, len_y*sizeof(int));
memcpy(h_g, ind, len_g*sizeof(int));
memcpy(h_v, dny, len_y*sizeof(float));
cudaMemcpy(d_k, h_k, len_y*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_g, h_g, len_g*sizeof(int), cudaMemcpyHostToDevice);
cudaMemcpy(d_v, h_v, len_y*sizeof(float), cudaMemcpyHostToDevice);
extend_kernel<<<(len_g+nTPB-1)/nTPB, nTPB >>>(d_k, len_y, d_g, len_g, d_v, d_r);
cudaMemcpy(h_r, d_r, len_g*sizeof(float), cudaMemcpyDeviceToHost);
std::cout << "case y result: ";
for (int i=0; i < len_g; i++)
std::cout << h_r[i] << " ";
std::cout << std::endl;
// using thrust
thrust::device_vector<int> tind(ind, ind+len_g);
thrust::device_vector<int> tindx(indx, indx+len_x);
thrust::device_vector<float> tdnx(dnx, dnx+len_x);
thrust::device_vector<float> tresult(len_g);
thrust::device_vector<int> tbound(len_g);
thrust::lower_bound(tindx.begin(), tindx.end(), tind.begin(), tind.end(), tbound.begin());
thrust::for_each(thrust::make_zip_iterator(thrust::make_tuple(tind.begin(), tbound.begin(), tresult.begin())), thrust::make_zip_iterator(thrust::make_tuple(tind.end(), tbound.end(), tresult.end())), extend_functor(thrust::raw_pointer_cast(tindx.data()), len_x, thrust::raw_pointer_cast(tdnx.data())));
std::cout << "thrust case x result: ";
thrust::copy(tresult.begin(), tresult.end(), std::ostream_iterator<float>(std::cout, " "));
std::cout << std::endl;
return 0;
}