使用push :: reverse与make_zip_iterator + make_tuple

时间:2018-08-17 19:49:32

标签: cuda reverse thrust

我在对使用推力:: make_zip_iterator(推力:: make_tuple())类型语法构造的zip_iterator上使用推力::反向功能时遇到奇怪的行为(请参阅JackOLantern的答案以了解很好的例子。

我希望反转多个设备向量的任意指示部分,如下面的示例代码所示。当我通过将它们捆绑在一起并将它们压缩在一起来进行一次反转时,会发生意外的行为。范围的前半部分已正确更改为范围的后半部分的倒置,但是范围的后半部分保持不变。

我一直在以类似的方式使用其他推力函数(sort_by_key,uniqe_by_key,neighbord_difference等),没有问题。我是在错误地执行此操作吗?还是出于某种原因,这在根本上不起作用?我的想法是,zip_iterator可能不是反向所需的双向。这是真的?我找不到这样的文档。

一种解决方法是单独反转向量,如下所示。但是,我怀疑这会降低效率。请注意,在我的实际用例中,我有大小为10,000的向量,并且正在将3-7个向量压缩到任意位置以进行操作。

#include <iostream>
#include <ostream>
#include <thrust/device_vector.h>
#include <thrust/host_vector.h>
#include <thrust/tuple.h>
#include <thrust/iterator/zip_iterator.h>
#include <thrust/sequence.h>
#include <thrust/reverse.h>

int main(){

    // initial host vectors
    const int N=10;
    thrust::host_vector<int> h1(N);
    thrust::host_vector<float> h2(N);

    // fill them
    thrust::sequence( h1.begin(), h1.end(), 0);
    thrust::sequence( h2.begin(), h2.end(), 10., 0.5);

    // print initial contents
    for (size_t i=0; i<N; i++){
        std::cout << h1[i] << " " << h2[i] << std::endl;
    }

    // transfer to device
    thrust::device_vector<int> d1 = h1;
    thrust::device_vector<float> d2 = h2;

    // what chunk to invert
    int iStart = 3; int iEnd = 8;

    // attempt to reverse middle via zip_iterators
    thrust::reverse(
            thrust::make_zip_iterator( thrust::make_tuple( d1.begin()+iStart, d2.begin()+iStart)),
            thrust::make_zip_iterator( thrust::make_tuple( d1.begin()+iEnd, d2.begin()+iEnd))
            );

    // pull back and write out unexpected ordering
    thrust::host_vector<int> temp1 = d1;
    thrust::host_vector<float> temp2 = d2;
    std::cout << "<==========>" << std::endl;
    for (size_t i=0; i<N; i++){
        std::cout << temp1[i] << " " << temp2[i] << std::endl;
    }

    // reset device variables
    d1 = h1;
    d2 = h2;

    // reverse individually
    thrust::reverse( d1.begin()+iStart, d1.begin()+iEnd);
    thrust::reverse( d2.begin()+iStart, d2.begin()+iEnd);

    // pull back and write out the desired ordering
    temp1 = d1;
    temp2 = d2;
    std::cout << "<==========>" << std::endl;
    for (size_t i=0; i<N; i++){
        std::cout << temp1[i] << " " << temp2[i] << std::endl;
    }

    return 0;
}

输出

0 10
1 10.5
2 11
3 11.5
4 12
5 12.5
6 13
7 13.5
8 14
9 14.5
<==========>
0 10
1 10.5
2 11
7 13.5
6 13
5 12.5
6 13
7 13.5
8 14
9 14.5
<==========>
0 10
1 10.5
2 11
7 13.5
6 13
5 12.5
4 12
3 11.5
8 14
9 14.5

1 个答案:

答案 0 :(得分:0)

Robert Crovella在评论中提供的信息以及初始帖子中最初给出的解决方法似乎可以回答问题-因此,我将在此处将其合并,以便可以将问题标记为“已回答”。如果其他人希望发布其他解决方案,我很乐意查看它们并移动“官方回答”复选标记。话虽这么说...

问题的解决方案包括两个部分:

  1. 如果使用旧版本的CUDA并进行升级,则可以选择:升级到最新的CUDA版本,并且该操作应该可以运行(经测试可在CUDA 9.2.148上使用-感谢Robert!)
  2. 如果无法升级到较新版本的CUDA:分别对向量应用反向,以实现与初始文章中给出的相同结果。为了完整起见,下面仅复制了具有工作解决方案的代码。

    data2 %>%
      group_by(add) %>%                           # for each add value                      
      mutate(group2 = rleid(group)) %>%           # created group2
      filter(group=="male" & group2==3) %>%       # keep only male after female
      summarise(SUM = sum(x1[row_number() <= 4])) # get sum of x1 for first 4 rows
    
    # # A tibble: 2 x 2
    #   add     SUM
    #   <fct> <dbl>
    # 1 x      94.9
    # 2 y     107.