cudathrust

Thrust Gathering/Filtering


What I am trying to do is create a filter on a vector so it removes elements that do not pass a predicate test; but not too sure how I go about it.

I evaluate each element in my inputer vector against the predicate, for example in my code the is_even functor, in a device_vector vector. It is true if it passes the test and false if it's not.

Now I am stuck because I now have this bool vector and I want to gather the elements that passed this predicate test. I store it in a bool vector because I want to keep the result to filter other vectors.

#include ...

template<typename T>
struct is_even : thrust::unary_function<T, bool>
{
    __host__ __device__
    bool operator()(const T &x)
    {
        return (x%2)==0;
    }
};

int main(void)
{
    std::cout << "Loading test!" << std::endl;
    const int N = 1000000;
    thrust::device_vector<int> col1(N);
    thrust::device_vector<float> col2(N, 1); 
    thrust::sequence(col1.begin(), col1.end());

    thrust::device_vector<bool> filter(N);
    thrust::transform(col1.begin(), col1.end(), filter.begin(), is_even<int>());

    // filter col1 and col2 based on filter

    return 0;
}

Solution

  • Within the stream compaction group you may be interested in thrust::copy_if

    We can select the even elements into a new vector directly using your defined predicate without making an intermediate filter vector:

    thrust::copy_if(col1.begin(), col1.end(), result.begin(), is_even<int>());
    

    (result should be a vector of identical type to col1, and already defined to be a length equal to or greater than col1, since it's unknown how many elements will pass the predicate test.)

    If you want to work off of the filter vector you have created, use the stencil version of copy_if instead.

    Here's a worked example using the stencil method based on your comments:

    $ cat t267.cu
    #include <iostream>
    #include <thrust/device_vector.h>
    #include <thrust/sequence.h>
    #include <thrust/transform.h>
    #include <thrust/copy.h>
    
    template<typename T>
    struct is_even : thrust::unary_function<T, bool>
    {
        __host__ __device__
        bool operator()(const T &x)
        {
            return (x%2)==0;
        }
    };
    
    
    struct is_true : thrust::unary_function<bool, bool>
    {
        __host__ __device__
        bool operator()(const bool &x)
        {
            return x;
        }
    };
    
    int main(void)
    {
        std::cout << "Loading test!" << std::endl;
        const int N = 1000000;
        thrust::device_vector<int> col1(N);
        thrust::device_vector<float> col2(N, 1);
        thrust::sequence(col1.begin(), col1.end());
    
        thrust::device_vector<bool> filter(N);
        thrust::device_vector<int> result(N);
        thrust::transform(col1.begin(), col1.end(), filter.begin(), is_even<int>());
        // filter col1 based on filter
        thrust::device_vector<int>::iterator end = thrust::copy_if(col1.begin(), col1.end(), filter.begin(), result.begin(), is_true());
        int len = end - result.begin();
        thrust::host_vector<int> h_result(len);
        thrust::copy_n(result.begin(), len, h_result.begin());
        thrust::copy_n(h_result.begin(), 10, std::ostream_iterator<int>(std::cout, "\n"));
    
    
        return 0;
    }
    $ nvcc -arch=sm_20 -o t267 t267.cu
    $ ./t267
    Loading test!
    0
    2
    4
    6
    8
    10
    12
    14
    16
    18
    $