C++ Cuda推力获取段中的上一个元素
我有一个值向量和一个键向量(表示一个段) 对于每个元素,我想知道它的前一个元素(在同一段中)。 它可以是值,也可以是原始向量中的索引,这无关紧要 因此,结果应该是(在值的情况下) 对于算法的剩余部分,您可以使用任何元素,而不是C++ Cuda推力获取段中的上一个元素,c++,algorithm,parallel-processing,cuda,thrust,C++,Algorithm,Parallel Processing,Cuda,Thrust,我有一个值向量和一个键向量(表示一个段) 对于每个元素,我想知道它的前一个元素(在同一段中)。 它可以是值,也可以是原始向量中的索引,这无关紧要 因此,结果应该是(在值的情况下) 对于算法的剩余部分,您可以使用任何元素,而不是nan 也许我可以用独占分段扫描和max操作来存档它,而不是sum。 所以有两个问题: 我的方法正确吗 还有更优雅或有效的解决方案吗 可以使用以下步骤实现所需的功能: 按k排序v,以获得彼此相邻的相等键值;这必须通过stable\u sort\u by_key来完成,因为您
nan
也许我可以用独占分段扫描和max
操作来存档它,而不是sum
。
所以有两个问题:
可以使用以下步骤实现所需的功能:
k
排序v
,以获得彼此相邻的相等键值;这必须通过stable\u sort\u by_key
来完成,因为您希望检索“previous”元素,因此必须保留具有相等键的元素之间的顺序if(上一个元素具有相同的键)
然后返回上一个元素的值
其他的
返回-1
以下代码实现这些步骤:
#include <cstdint>
#include <iostream>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/transform.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/zip_iterator.h>
#define PRINTER(name) print(#name, (name))
template <template <typename...> class V, typename T, typename ...Args>
void print(const char* name, const V<T,Args...> & v)
{
std::cout << name << ":\t";
thrust::copy(v.begin(), v.end(), std::ostream_iterator<T>(std::cout, "\t"));
std::cout << std::endl;
}
template<typename... Iterators>
__host__ __device__
thrust::zip_iterator<thrust::tuple<Iterators...>> zip(Iterators... its)
{
return thrust::make_zip_iterator(thrust::make_tuple(its...));
}
template <typename IteratorType, typename Integer>
struct prev_value
{
prev_value(IteratorType first) : first(first){}
template <typename Tuple>
__host__ __device__
Integer operator()(const Tuple& t)
{
const auto& index = thrust::get<0>(t);
const auto& previousValue = thrust::get<1>(t);
Integer result = -1;
const auto& currentKey = *(first+index);
const auto& previousKey = *(first+index-1);
if(currentKey == previousKey)
{
result = previousValue;
}
return result;
}
IteratorType first;
};
template <typename Integer, typename IteratorType>
prev_value<IteratorType, Integer> make_prev_value(IteratorType first)
{
return prev_value<IteratorType, Integer>(first);
}
int main(int argc, char** argv)
{
using Integer = std::int32_t;
using HostVec = thrust::host_vector<Integer>;
using DeviceVec = thrust::device_vector<Integer>;
Integer v[] = {1, 1, 1, 2, 3, 5, 6};
Integer k[] = {0, 0, 1, 1, 0, 2, 2};
Integer size = sizeof(k)/sizeof(k[0]);
HostVec h_k(k, k+size);
HostVec h_v(v, v+size);
// copy data to device
DeviceVec d_k = h_k;
DeviceVec d_v = h_v;
std::cout << "---- input data ----" << std::endl;
PRINTER(d_k);
PRINTER(d_v);
thrust::stable_sort_by_key(d_k.begin(), d_k.end(), d_v.begin());
std::cout << "---- after sorting ----" << std::endl;
PRINTER(d_k);
PRINTER(d_v);
DeviceVec d_r(size, -1);
auto op = make_prev_value<Integer>(d_k.begin());
thrust::transform(zip(thrust::make_counting_iterator(Integer(1)), d_v.begin()),
zip(thrust::make_counting_iterator(size), d_v.end()),
d_r.begin()+1,
op);
std::cout << "---- result ----" << std::endl;
PRINTER(d_r);
return 0;
}
如何定义
段
?您的输入数据已经排序了吗?您的细分市场通常有多大?您的输入向量有多大?键是段的id。它从0开始,没有gapsso[1,1,3]
都属于由k=1
指示的同一段?是的,它是同一段,但k=0
,因为k=1
它是[1,2]
r = [nan, 1, nan, 1, 1, nan, 5]
#include <cstdint>
#include <iostream>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <thrust/transform.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/iterator/zip_iterator.h>
#define PRINTER(name) print(#name, (name))
template <template <typename...> class V, typename T, typename ...Args>
void print(const char* name, const V<T,Args...> & v)
{
std::cout << name << ":\t";
thrust::copy(v.begin(), v.end(), std::ostream_iterator<T>(std::cout, "\t"));
std::cout << std::endl;
}
template<typename... Iterators>
__host__ __device__
thrust::zip_iterator<thrust::tuple<Iterators...>> zip(Iterators... its)
{
return thrust::make_zip_iterator(thrust::make_tuple(its...));
}
template <typename IteratorType, typename Integer>
struct prev_value
{
prev_value(IteratorType first) : first(first){}
template <typename Tuple>
__host__ __device__
Integer operator()(const Tuple& t)
{
const auto& index = thrust::get<0>(t);
const auto& previousValue = thrust::get<1>(t);
Integer result = -1;
const auto& currentKey = *(first+index);
const auto& previousKey = *(first+index-1);
if(currentKey == previousKey)
{
result = previousValue;
}
return result;
}
IteratorType first;
};
template <typename Integer, typename IteratorType>
prev_value<IteratorType, Integer> make_prev_value(IteratorType first)
{
return prev_value<IteratorType, Integer>(first);
}
int main(int argc, char** argv)
{
using Integer = std::int32_t;
using HostVec = thrust::host_vector<Integer>;
using DeviceVec = thrust::device_vector<Integer>;
Integer v[] = {1, 1, 1, 2, 3, 5, 6};
Integer k[] = {0, 0, 1, 1, 0, 2, 2};
Integer size = sizeof(k)/sizeof(k[0]);
HostVec h_k(k, k+size);
HostVec h_v(v, v+size);
// copy data to device
DeviceVec d_k = h_k;
DeviceVec d_v = h_v;
std::cout << "---- input data ----" << std::endl;
PRINTER(d_k);
PRINTER(d_v);
thrust::stable_sort_by_key(d_k.begin(), d_k.end(), d_v.begin());
std::cout << "---- after sorting ----" << std::endl;
PRINTER(d_k);
PRINTER(d_v);
DeviceVec d_r(size, -1);
auto op = make_prev_value<Integer>(d_k.begin());
thrust::transform(zip(thrust::make_counting_iterator(Integer(1)), d_v.begin()),
zip(thrust::make_counting_iterator(size), d_v.end()),
d_r.begin()+1,
op);
std::cout << "---- result ----" << std::endl;
PRINTER(d_r);
return 0;
}
---- input data ----
d_k: 0 0 1 1 0 2 2
d_v: 1 1 1 2 3 5 6
---- after sorting ----
d_k: 0 0 0 1 1 2 2
d_v: 1 1 3 1 2 5 6
---- result ----
d_r: -1 1 1 -1 1 -1 5