删除排序列表中的条目:在 GPU 中有效

发布于 2024-12-01 11:55:14 字数 3698 浏览 1 评论 0原文

我正在尝试在 cuda/thrust 中编写以下问题的代码。我得到了一个键列表以及与每个键关联的三个值。我已经设法按字典顺序对它们进行排序。如果具有相同键的输入具有每个值关系,则现在需要减少输入。在下面的示例中,V1(a)<=V1(c)和V2(a)<=V2(c)并且V3(a)<=V3(c),意味着输入a<=V3(c)。输入 c,因此输入 c 从输出中删除。

输入示例:

       Key      V1      V2      V3  
a.      1       2       5       3
b.      1       2       6       2
c.      1       2       7       4           
d.      1       3       6       5           
e.      2       8       8       8
f.      3       1       2       4

输出示例:

         Key    V1  V2  V3
 a.        1    2   5   3
 b.        1    2   6   2
 e.        2    8   8   8
 f.        3    1   2   4
  • 输入 a <输入c==> c 删除
  • 输入 a <输入d==> d 删除

我已经能够使用 for 循环和 if 语句解决上述问题。我目前正在尝试使用基于 GPU 的 cuda/thrust 来解决这个问题。这可以在 GPU 上完成(最好是推力)还是必须用 cuda 编写单独的内核?

我还没有使用 推力:删除重复项中讨论的 unique 来制定此问题键值数组

编辑以包含程序“stl/c++”程序来生成上述场景:“Reducing myMap”部分是我使用 for 循环和 if 语句的实现。

#include <iostream>
#include <tr1/array>
#include <vector>
#include <algorithm>

struct mapItem {
    mapItem(int k, int v1, int v2, int v3){
        key=k; 
        std::tr1::array<int,3> v = {v1, v2, v3};
        values=v;
    };
    int key;
    std::tr1::array<int,3> values;
};

struct sortLexiObj{
    bool operator()(const mapItem& lhs, const mapItem& rhs){ 
        return lhs.values < rhs.values; 
    }
};
struct sortKey{
    bool operator()(const mapItem& lhs, const mapItem& rhs){ 
        return lhs.key < rhs.key; 
    }
};

int main(int argc, char** argv){

    std::vector<mapItem> myMap;

    // Set up initial matrix:
    myMap.push_back(mapItem(3, 1, 2, 4));
    myMap.push_back(mapItem(1, 2, 6, 2));
    myMap.push_back(mapItem(1, 2, 5, 3));
    myMap.push_back(mapItem(1, 3, 6, 5));
    myMap.push_back(mapItem(2, 8, 8, 8));
    myMap.push_back(mapItem(1, 2, 7, 4));

    std::sort(myMap.begin(), myMap.end(), sortLexiObj());
    std::stable_sort(myMap.begin(), myMap.end(), sortKey());
    std::cout << "\r\nOriginal sorted Map" << std::endl;
    for(std::vector<mapItem>::iterator mt=myMap.begin(); mt!=myMap.end(); ++mt){
        std::cout << mt->key << "\t";
        for(std::tr1::array<int,3>::iterator it=(mt->values).begin(); it!=(mt->values).end(); ++it){
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    }
    /////////////////////////

    // Reducing myMap
    for(std::vector<mapItem>::iterator it=myMap.begin(); it!=myMap.end(); ++it){
        std::vector<mapItem>::iterator jt=it; ++jt;
        for (; jt != myMap.end();) {
            if (   (it->key == jt->key)){
                if ( it->values.at(0) <= jt->values.at(0) && 
                    it->values.at(1) <= jt->values.at(1) &&
                    it->values.at(2) <= jt->values.at(2) ) {
                    jt = myMap.erase(jt);
                } 
                else ++jt;
            }
            else break;
        }
    }

    std::cout << "\r\nReduced Map" << std::endl;
    for(std::vector<mapItem>::iterator mt=myMap.begin(); mt!=myMap.end(); ++mt){
        std::cout << mt->key << "\t";
        for(std::tr1::array<int,3>::iterator it=(mt->values).begin(); it!=(mt->values).end(); ++it){
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

I am trying to code the following problem in cuda/thrust. I am given a list of key and three values associated with each keys. I have managed to sort them in lexicographic order. The input now needs to be reduced if inputs with same key have each value-wise relation. In example below, V1(a)<=V1(c) and V2(a)<=V2(c) and V3(a)<=V3(c), implies that Input a < Input c, and hence, Input c is removed from output.

Example Input:

       Key      V1      V2      V3  
a.      1       2       5       3
b.      1       2       6       2
c.      1       2       7       4           
d.      1       3       6       5           
e.      2       8       8       8
f.      3       1       2       4

Example Output:

         Key    V1  V2  V3
 a.        1    2   5   3
 b.        1    2   6   2
 e.        2    8   8   8
 f.        3    1   2   4
  • Input a < Input c ==> c removed
  • Input a < Input d ==> d removed

I’ve been able to solve the above problem using for-loops, and if-statements. I am currently trying to solve this using gpu based cuda/thrust. Could this be done on the gpu (preferably thrust) or an individual kernel has to be written in cuda ?

I have not been to formulate this problem using unique as discussed in Thrust: Removing duplicates in key-value arrays

Edited to include program "stl/c++" program to generate above scenario: section "Reducing myMap" is my implementation using for-loops and if-statements.

#include <iostream>
#include <tr1/array>
#include <vector>
#include <algorithm>

struct mapItem {
    mapItem(int k, int v1, int v2, int v3){
        key=k; 
        std::tr1::array<int,3> v = {v1, v2, v3};
        values=v;
    };
    int key;
    std::tr1::array<int,3> values;
};

struct sortLexiObj{
    bool operator()(const mapItem& lhs, const mapItem& rhs){ 
        return lhs.values < rhs.values; 
    }
};
struct sortKey{
    bool operator()(const mapItem& lhs, const mapItem& rhs){ 
        return lhs.key < rhs.key; 
    }
};

int main(int argc, char** argv){

    std::vector<mapItem> myMap;

    // Set up initial matrix:
    myMap.push_back(mapItem(3, 1, 2, 4));
    myMap.push_back(mapItem(1, 2, 6, 2));
    myMap.push_back(mapItem(1, 2, 5, 3));
    myMap.push_back(mapItem(1, 3, 6, 5));
    myMap.push_back(mapItem(2, 8, 8, 8));
    myMap.push_back(mapItem(1, 2, 7, 4));

    std::sort(myMap.begin(), myMap.end(), sortLexiObj());
    std::stable_sort(myMap.begin(), myMap.end(), sortKey());
    std::cout << "\r\nOriginal sorted Map" << std::endl;
    for(std::vector<mapItem>::iterator mt=myMap.begin(); mt!=myMap.end(); ++mt){
        std::cout << mt->key << "\t";
        for(std::tr1::array<int,3>::iterator it=(mt->values).begin(); it!=(mt->values).end(); ++it){
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    }
    /////////////////////////

    // Reducing myMap
    for(std::vector<mapItem>::iterator it=myMap.begin(); it!=myMap.end(); ++it){
        std::vector<mapItem>::iterator jt=it; ++jt;
        for (; jt != myMap.end();) {
            if (   (it->key == jt->key)){
                if ( it->values.at(0) <= jt->values.at(0) && 
                    it->values.at(1) <= jt->values.at(1) &&
                    it->values.at(2) <= jt->values.at(2) ) {
                    jt = myMap.erase(jt);
                } 
                else ++jt;
            }
            else break;
        }
    }

    std::cout << "\r\nReduced Map" << std::endl;
    for(std::vector<mapItem>::iterator mt=myMap.begin(); mt!=myMap.end(); ++mt){
        std::cout << mt->key << "\t";
        for(std::tr1::array<int,3>::iterator it=(mt->values).begin(); it!=(mt->values).end(); ++it){
            std::cout << *it << " ";
        }
        std::cout << std::endl;
    }

    return 0;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

安稳善良 2024-12-08 11:55:14

我认为您可以将 thrust::unique 与谓词一起使用,如 推力:删除键值数组中的重复项
事实上,我们可以做到这一点,因为unique具有以下特性:

对于 [first、last) 范围内具有相同值的每组连续元素,unique 会删除该组中除第一个之外的所有元素。

,您应该定义一个谓词来测试-相等性,对于具有相同键且第一个元组中所有值都较小的元组,它将返回true

    typedef thrust::tuple<int, int, int, int> tuple_t;
    // a functor which defines your *uniqueness* condition
    struct tupleEqual
    {
      __host__ __device__
        bool operator()(tuple_t x, tuple_t y)
        {
          return ( (x.get<0>() == y.get<0>()) // same key
              && (x.get<1>() <= y.get<1>())   // all values are smaller
              && (x.get<2>() <= y.get<2>()) 
              && (x.get<3>() <= y.get<3>()));
        }
    };

因此 必须将其应用于排序集合。这样,只有第一个元组(最小的)不会被删除。
在 V1、V2 或 V3 中具有相同键和较大值的元组将产生 false,因此不会被删除。

    typedef thrust::device_vector< int >                IntVector;
    typedef IntVector::iterator                         IntIterator;
    typedef thrust::tuple< IntIterator, IntIterator, IntIterator, IntIterator >   IntIteratorTuple;
    typedef thrust::zip_iterator< IntIteratorTuple >    ZipIterator;

    IntVector keyVector;
    IntVector valVector1, valVector2, valVector3;

    tupleEqual predicate;
    ZipIterator newEnd = thrust::unique(
        thrust::make_zip_iterator(
            thrust::make_tuple(
                keyVector.begin(),
                valVector1.begin(),
                valVector2.begin(),
                valVector3.begin() ) ),
        thrust::make_zip_iterator(
            thrust::make_tuple(
                keyVector.end(),
                valVector1.end(),
                valVector2.end(),
                valVector3.end() ) ),
        predicate );

    IntIteratorTuple endTuple = newEnd.get_iterator_tuple();

    keyVector.erase( thrust::get<0>( endTuple ), keyVector.end() );
    valVector1.erase( thrust::get<1>( endTuple ), valVector1.end() );
    valVector2.erase( thrust::get<2>( endTuple ), valVector2.end() );
    valVector3.erase( thrust::get<3>( endTuple ), valVector3.end() );

I think that you can use thrust::unique with a predicate as it's shown in Thrust: Removing duplicates in key-value arrays.
Actually, we can do it because of the following characteristic of unique:

For each group of consecutive elements in the range [first, last) with the same value, unique removes all but the first element of the group.

So, you should define a predicate to test for pseudo-equality that will return true for tuples that have the same key and all values are smaller in the first tuple:

    typedef thrust::tuple<int, int, int, int> tuple_t;
    // a functor which defines your *uniqueness* condition
    struct tupleEqual
    {
      __host__ __device__
        bool operator()(tuple_t x, tuple_t y)
        {
          return ( (x.get<0>() == y.get<0>()) // same key
              && (x.get<1>() <= y.get<1>())   // all values are smaller
              && (x.get<2>() <= y.get<2>()) 
              && (x.get<3>() <= y.get<3>()));
        }
    };

And you have to apply it to a sorted collection. In this way, only the first tuple (the smallest) will not be removed.
A tuple with the same key and a bigger value in V1, V2 or V3 will yield false so it won't be removed.

    typedef thrust::device_vector< int >                IntVector;
    typedef IntVector::iterator                         IntIterator;
    typedef thrust::tuple< IntIterator, IntIterator, IntIterator, IntIterator >   IntIteratorTuple;
    typedef thrust::zip_iterator< IntIteratorTuple >    ZipIterator;

    IntVector keyVector;
    IntVector valVector1, valVector2, valVector3;

    tupleEqual predicate;
    ZipIterator newEnd = thrust::unique(
        thrust::make_zip_iterator(
            thrust::make_tuple(
                keyVector.begin(),
                valVector1.begin(),
                valVector2.begin(),
                valVector3.begin() ) ),
        thrust::make_zip_iterator(
            thrust::make_tuple(
                keyVector.end(),
                valVector1.end(),
                valVector2.end(),
                valVector3.end() ) ),
        predicate );

    IntIteratorTuple endTuple = newEnd.get_iterator_tuple();

    keyVector.erase( thrust::get<0>( endTuple ), keyVector.end() );
    valVector1.erase( thrust::get<1>( endTuple ), valVector1.end() );
    valVector2.erase( thrust::get<2>( endTuple ), valVector2.end() );
    valVector3.erase( thrust::get<3>( endTuple ), valVector3.end() );
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文