Count reduction using Thrust - c++

Given some input keys and values, I am trying to count how many consecutive values with the same key exist. I will give an example to make this more clear.
Input keys: { 1, 4, 4, 4, 2, 2, 1 }
Input values: { 9, 8, 7, 6, 5, 4, 3 }
Expected output keys: { 1, 4, 2, 1 }
Expected output values: { 1, 3, 2, 1 }
I am trying to solve this problem on a GPU using CUDA. The reduction capabilities of the Thrust library seemed like a good solution for this and I got to the following:
#include <thrust/reduce.h>
#include <thrust/functional.h>
struct count_functor : public thrust::binary_function<int, int, int>
{
__host__ __device__
int operator()(int input, int counter)
{
return counter + 1;
}
};
const int N = 7;
int A[N] = { 1, 4, 4, 4, 2, 2, 1 }; // input keys
int B[N] = { 9, 8, 7, 6, 5, 4, 3 }; // input values
int C[N]; // output keys
int D[N]; // output values
thrust::pair<int*, int*> new_end;
thrust::equal_to<int> binary_pred;
count_functor binary_op;
new_end = thrust::reduce_by_key(A, A + N, B, C, D, binary_pred, binary_op);
for (int i = 0; i < new_end.first - C; i++) {
std::cout << C[i] << " - " << D[i] << "\n";
}
This code is pretty similar to an example from the Thrust documentation. However, instead of the plus operation, I am trying to count. The output from this code is the following:
1 - 9
4 - 7
2 - 5
1 - 3
However, I would expected the second column to contain the values 1, 3, 2, 1. I think the counts are off because the reduction starts with the first value it finds and does not apply the operator until it has a second value, but I am not sure this is the case.
Am I overlooking something about the reduce_by_key function that could solve this problem or should I use a completely different function to achieve what I want?

For your use case you don't need the values of B, the values of D are only dependent on the values of A.
In order to count how many consecutive values are in A you can supply a thrust::constant_iterator as the input values and apply thrust::reduce_by_key:
#include <thrust/reduce.h>
#include <thrust/functional.h>
#include <iostream>
#include <thrust/iterator/constant_iterator.h>
int main()
{
const int N = 7;
int A[N] = { 1, 4, 4, 4, 2, 2, 1 };
int C[N];
int D[N];
thrust::pair<int*, int*> new_end;
thrust::equal_to<int> binary_pred;
thrust::plus<int> binary_op;
new_end = thrust::reduce_by_key(A, A + N, thrust::make_constant_iterator(1), C, D, binary_pred, binary_op);
for (int i = 0; i < new_end.first - C; i++) {
std::cout << C[i] << " - " << D[i] << "\n";
}
return 0;
}
output
1 - 1
4 - 3
2 - 2
1 - 1

Related

How can i remove the duplicate element in output / arrays?

#include <iostream>
using namespace std;
int main()
{
const int ARRAY_SIZE = 10;
int value[ARRAY_SIZE] = { 1, 2, 3, 4, 3, 4, 2, 3, 5, 6};
int value2[100];
for (int i = 0; i < ARRAY_SIZE; i++)
{
for (int j = i + 1; j <= ARRAY_SIZE; j++)
{
if (value[i] == value[j])
{
cout << value[i] << " ";
}
}
}
return 0;
}
The output is
2 3 3 4 3
How can I make the output become 2 3 4 ?
Edit: I'm trying to print all numbers appearing more than once in the value array
I think I should create one more array to store value, but I stuck with it and don't know how to do it.
It helps considerably to sort your array. Then you only need two indices:
a write index, starting at 0
a read index, starting at 1
Loop over your array using the read index. For every array[read] that has a duplicate value at array[read-1], IFF that value also does not exist at array[write], then copy it over and increment your write index.
Finally, the new length of your data is equal to your write index.
The basic idea is this: if I have a sorted list of values:
1 3 3 4 5 5 5 7 7 9
Then I can easily see if a value is a duplicate or not by comparing the current (read) with the previous.
┌────┐
1 3 3 │4 5│ 5 5 7 7 9 -- not duplicates
└────┘
↑
┌────┐
1 3 3 4 │5 5│ 5 7 7 9 -- duplicate values
└────┘
↑
The only remaining trick is to make just a single copy of that value to the write index, which we can do by simply looking at the last thing we wrote.
You can use a std::map to count the number of times a value is in the array. If the number appears 2 or more times, then print it.
#include <iostream>
#include <map>
int main()
{
const int ARRAY_SIZE = 10;
int value[ARRAY_SIZE] = { 1, 2, 3, 4, 3, 4, 2, 3, 5, 6};
std::map <int, int> mp;
for(int i : value)
++mp[i];
for(const auto& p : mp)
if(p.second > 1)
std::cout << p.first << ' ';
}
Link.

Find base period of sequence in C++

For a sequence of numbers a1, a2,...,an, we say that there is a period if 1≤p<n and if it holds that it is ai=ai+p for all values for which this equality makes sense.
For example, the sequence of numbers 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 has period 5, because ai=ai+5 for all values such that both indices i and i+5 are within the allowable range (i.e. for 1 to 7 inclusive). The same sequence also has a period of 10. Next, we say that the sequence of numbers is periodic if it exists at least one number that is the period of that sequence, with the smallest such number being called the base sequence period. If such a number does not exist, the sequence is not periodic. For example, the above the sequence of numbers is periodic with the base period 5, while the sequence of numbers 4, 5, 1, 7, 1, 5 is not periodic.
#include <iostream>
#include <vector>
int period(std::vector<double> vektor) {
int p;
for (int i : vektor) {
for (int j : vektor) {
if (vektor[i] == vektor[j])
p = j;
}
}
return p;
}
int main() {
std::vector<double> vektor{1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3};
std::cout << period(vektor);
return 0;
}
This should be solved using vector.
Could you help me fix this code? This returns 3 as base period of sequence.
For starters it is unclear why you are using a vector with the value type double instead of the type int when all initializers have the type int.
The function period should accept a vector by constant reference.
The variable p is not initialized. As a result the function can return an indeterminate value.
The range based for loop does not return indices in a container as you think
for (int i : vektor) {
It returns stored in the vector objects of the type double.
So the condition in the if statement
if (vektor[i] == vektor[j])
makes no sense.
The function can look the following way as it is shown in the demonstration program below.
#include <iostream>
#include <vector>
size_t period( const std::vector<double> &v )
{
size_t p = 0;
for (size_t i = 1; !p && i < v.size(); i++)
{
size_t j = 0;
while (j < v.size() - i && v[j] == v[j + i]) ++j;
if ( j + i == v.size() ) p = i;
}
return p;
}
int main()
{
std::vector<double> v = { 1, 3, 1, 4, 2, 1, 3, 1, 4, 2, 1, 3 };
std::cout << period( v ) << '\n';
}
The program output is
5

Problem with iteration on array in For loop

I'm having a trouble for a long time in a problem related to array and loops.
Assume an array like:
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
The program should print the expected column as shown (note that the table is an idea for clarification of what I actually want to achieve):
max: expected arr[index] for max
------------------------------------
2 : 3 5 value of: arr[0]
3 : 6, 8, 10 value of: arr[3]
1 : 9 value of: arr[7]
This is what I've tried so far:
#include <iostream>
int main(void) {
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
int max = arr[0];
int i = 1, it = i;
for (; i <= max; i++) {
if (i == max) {
std::cout << arr[i] << std::endl;
max = arr[it + 1]; // when loop end has come, increment max to next element value
it = i + 2; // incrementing iterator by 2 next element position (after max)
} else {
std::cout << arr[i] << ' '; // when loop is executing
}
}
return 0;
}
What it actually prints which is unexpected V/S what it should print:
3 5 | 3, 5
3 6 8 | 6, 8, 10
10 1 9 | 1, 9
10 | <nothing>
The program is about to get max value and print the next elements until max value reaches the number of element position.
Where the problem's occurring and how to fix it? Please let me know.
So I rewrote your code, frankly I couldn't follow it, it seems a bit confused with variable names that seem a bit off.
Here's some working code. The two key concepts in the code are the place where each block starts (the variable start) and the size of each block (the variable count). Plus I use the size of the whole array sizeof(arr)/sizeof(arr[0]) to terminate the outer loop. Something that wasn't present in your code. If you are using C++17, you can use std::size(arr) instead of sizeof.
int main(void) {
int arr[] = {2, 3, 5, 3, 6, 8, 10, 1, 9};
size_t start = 0;
while (start < sizeof(arr)/sizeof(arr[0]))
{
int count = arr[start];
for (int i = 0; i < count; ++i)
{
std::cout << arr[start + i + 1] << ' ';
}
std::cout << std::endl;
start += count + 1;
}
}
The output is
3 5
6 8 10
9

Sorting doesn't seem to work

This code is written in C++. I've the following structure:
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
struct Data
{
int h, b, w;
Data(int _h, int _b, int _w) : h(_h), b(_b), w(_w)
{}
bool operator<(const Data& other) const
{
bool overlap = (other.b >= b && other.b <= w) ||
(other.w >= b && other.w <= w) ||
(other.b < b && other.w > w);
if (overlap)
{
return h < other.h;
}
return h > other.h;
}
};
The operator< will be used for sorting. The idea is to sort from highest-h to lowest-h, unless there is any overlapping between either b or w in comparing variables. Remaining code:
vector <int> getOrdering(vector <int> height, vector <int> bloom, vector <int> wilt)
{
vector<Data> vdata;
for (int i = 0; i < height.size(); i++)
{
vdata.push_back(Data(height[i], bloom[i], wilt[i]));
}
sort(vdata.begin(), vdata.end());
vector<int> ans;
for (Data data : vdata)
{
ans.push_back(data.h);
}
return ans;
}
int main()
{
vector <int> p0 = { 1, 2, 3, 4, 5, 6 };
vector <int> p1 = { 1, 3, 1, 3, 1, 3 };
vector <int> p2 = { 2, 4, 2, 4, 2, 4 };
vector<int> ans = getOrdering(p0, p1, p2);
for (int a : ans)
{
cout << a << ' ';
}
cout << endl;
return 0;
}
The way the I've written the operator< function, the code should output 2 4 6 1 3 5. But the output is 6 5 4 3 2 1. I'm using Visual Studio 2013 Ultimate.
After debugging the operator< function, I found out that it is being called for Data object as follows:
1st call: this->h = 2, other.h = 1
2nd call: this->h = 1, other.h = 2
3rd call: this->h = 3, other.h = 2
4th call: this->h = 2, other.h = 3
5th call: this->h = 4, other.h = 3
6th call: this->h = 3, other.h = 4
7th call: this->h = 5, other.h = 4
8th call: this->h = 4, other.h = 5
9th call: this->h = 6, other.h = 5
10th call: this->h = 5, other.h = 6
Note that when Data objects' h values are 1, 3 or 5, their b and w values are same. They will be sorted by ascending order of h. Same goes true for Data objects whose h values are 2, 4 and 6. But in the operator<() no two Data objects are ever compared whose h values are same! 1 compared to 2, 2 compared to 3, 3 compared to 4 and so on. So the overlap variable is always false. The outcome of sort() would be different if Data objects whose h values are same got compared - but that never happened!
Any explanation of this behavior of compiler?
It is because your operator< depends a lot of the data order. If we run you're algorithm with your data, it's the expected output.
The first comparaison is between Data(1,1,2) and Data(2,3,4). According to your operator<, Data(2,3,4) is the lower so the temp order is [Data(2,3,4), Data(1,1,2)]
Then, Data(3,1,2) comes and is compared against the lowest value of the current sorted list, so Data(2,3,4). Again, according to your operator<, Data(3,1,2) is lower so no need to compare against the other values in the list and the new temp ordered list is [Data(3,1,2),Data(2,3,4), Data(1,1,2)].
Then it's the same for each other value, they are each time only compared to the first value in the list since they are lower (according to operator<) and so put in front of the sorted list.
If you change your init list order with:
vector <int> p0 = { 6, 5, 4, 3, 2, 1};
vector <int> p1 = { 3, 1, 3, 1, 3, 1};
vector <int> p2 = { 4, 2, 4, 2, 4, 2};
you'll have the expected output since there will be more comparaison involved.
But the fact that the result depend on the init order show there is clearly a flaw in your operator< function.

Function to return count of duplicate numbers in sorted array

I want to return the number of duplicate values in a sorted array.
For example: a = { 1, 1, 2, 3, 4, 4 }, fratelli(n) should return 2. (They are 1, 1 and 4, 4)
I attempted to use a recursive approach, but it doesn't work. It Always give me 4.
I'm asking if someone please could help me understand better this methods of programming. Thanks a lot!
The function:
#include <iostream>
using namespace std;
int fratelli(int a[], int l, int r)
{
if (l == r) return 0;
else
{
int c = (l+r) / 2;
int n = fratelli(a, l, c) + fratelli(a, c+1, r);
if (a[l] == a[l+1]) n++;
return n;
}
}
int main()
{
const int _N = 11;
int array[_N] = { 1, 1, 2, 3, 5, 5, 7, 8, 8, 11, 12 };
cout << "\n" << fratelli(array, 0, _N-1);
return 0;
}
You have an error on this line:
if (a[l] == a[l+1]) n++;
The check should be at index c not at l. Apart from this your code seems alright to me.