'How to get thrust::unique() to work with a vector of thrust::pair

I'm trying to make a unique thrust device vector of thrust::pair<int, int> using thrust::unique(), but the resulting output doesn't seem to be sorted like it should be. Here's the code in question:

struct make_pair : public thrust::binary_function<int, int, thrust::pair<int, int>> {
    __host__ __device__
        thrust::pair<int, int> operator()(int x, int y) { return thrust::make_pair(x, y); }
};



std::vector<thrust::pair<int, int>> find_borders_launch(int src_width, int src_height, cv::cuda::GpuMat& d_src) {

    thrust::device_vector<int> d_focus_result(src_width * src_height * 9);
    thrust::device_vector<int> d_target_result(src_width * src_height * 9);

    int* d_focus = thrust::raw_pointer_cast(d_focus_result.data());
    int* d_target = thrust::raw_pointer_cast(d_target_result.data());

    dim3 num_blocks = {uint(src_width + 1), uint(src_height + 1)};
    dim3 threads_per_block = {9, 1, 1};
    int substep_size = sizeof(int);

    find_borders_kernel <<<num_blocks, threads_per_block>>> (src_width, src_height, d_src.data, d_src.step, d_focus, d_target, substep_size);


    thrust::device_vector<thrust::pair<int, int>> d_unique(d_focus_result.size());


    thrust::transform(d_focus_result.begin(), d_focus_result.end(), d_target_result.begin(), d_unique.begin(), make_pair() ); //seems to do its job just fine

    thrust::unique(thrust::device, d_unique.begin(), d_unique.end());

    std::vector<thrust::pair<int, int>> output(d_unique.size());
    thrust::copy(d_unique.begin(), d_unique.end(), output.begin() );
    return output;
}

and the output looks something like:


0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 76
-1, -1
0, 76
0, 0
76, 0
-1, -1
76, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
76, 142
-1, -1
76, 142
0, 0
142, 76
-1, -1
142, 76
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
-1, -1
0, 0
...
...
...


and so on for eight million more entries. The documentation says that the first N = num_unique_elements of the array should be all the unique values, but they're clearly not. My second issue- I want to do something like this to cut off the garbage values at the end of the unique vector:

T* new_end = thrust::unique(thrust::device, d_unique.begin(), d_unique.end());

std::vector<thrust::pair<int, int>> output(int(new_end));
thrust::copy(d_unique.begin(), d_unique.begin() + new_end, output.begin() );

but that code throws an error ('T' is not actually part of the code but stands for many different types I have tried so far). I have a feeling I'm going about both parts of this question in the complete wrong way, and based on the fact that I can't find any questions about it on google, I assume the answer is obvious for reasons I am ignorant of.



Solution 1:[1]

solved, thanks to paleonix's comments. I had to sort the array before running unique on it, and the return value of unique wanted to go into thrust::device_vector<thrust::pair<int, int>>::iterator. here's the changed code if anyone in the future comes across the same problem. I'm sure it's super janky, but it works.

    thrust::device_vector<thrust::pair<int, int>> d_unique(d_focus_result.size());

    thrust::transform(d_focus_result.begin(), d_focus_result.end(), d_target_result.begin(), d_unique.begin(), make_pair() ); //seems to do its job just fine

    thrust::sort(thrust::device, d_unique.begin(), d_unique.end());

    thrust::device_vector<thrust::pair<int, int>>::iterator new_end  = thrust::unique(thrust::device, d_unique.begin(), d_unique.end());

    int new_length = thrust::distance(d_unique.begin(), new_end);

    std::vector<thrust::pair<int, int>> output(new_length);

    thrust::copy(d_unique.begin(), d_unique.begin() + new_length, output.begin() );

    return output;

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 classic_sasquatch_behavior