Cuda::thrust: Performing compact operation with Device_vector - c++

I'm still fairly new to Cuda and while a stackoverflow user gave me a descriptive example on how to use thrust::copy_if to compact an array of known size on the host (as I worded my question badly), I've been unable to convert the approach to use device_vectors (to deal with inputted arrays of unknown size on the device).
I'm attempting to generate a compacted list of the positions of all the elements in a vector which match a user specified predicate. The working example I was given is:
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/functional.h>
#include <iostream>
using namespace thrust::placeholders;
int main()
{
const int N = 10;
int objectArray[N] = { 1, 11, 7, 2, 7, 23, 6, 6, 9, 11 };
int results[N]={0};
int* end = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(N), objectArray, results, _1 == 7);
thrust::copy(results, results+N, std::ostream_iterator<int>(std::cout, " "));
std::cout << std::endl << "result count = " << end-results << std::endl;
return 0;
}
I've tried to modify the code to use device vectors (and compute on the device) as follows:
#include <thrust/copy.h>
#include <thrust/iterator/counting_iterator.h>
#include <thrust/functional.h>
#include <iostream>
using namespace thrust::placeholders;
int soughtElement=7;
reader.open("Numeric_1a40Coords.txt");
reader >> sizeOfProteinChain; //This returns the size of the input
reader.close();
thrust::host_vector<int> Host_names(sizeOfProteinChain);
thrust::host_vector<int> Host_results;
ImportNumericNameValues("Numeric_1a40Coords.txt", Host_names); //This populates the vector with "sizeOfProteinChain" number of elements
thrust::device_vector<int> Device_names = Host_Names;
thrust::device_vector<int> Device_results = Host_results;
Host_results = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(sizeOfProteinChain), Device_names, Device_results, _1 == soughtElement);
host_results=device_results;
for (int i=0;i<sizeOfProteinChain;i++)
cout<< host_results[i]<<" ";
cout<<endl;
/*Not sure how to get the resulting number of compacted position elements with device vectors instead of pointer arrays*/
I get errors stating that:
class "thrust::device_vector>" has no member
"iterator_category"
and:
no instance of overloaded function "thrust::copy_if" matches the
argument list
I've been stuck on this for a while and any suggestions on how to correct those errors, or more accurately convert the above sample, would be greatly appreciated. My previous question on this matter can be found here:

You might want to read the thrust quick start guide.
This will get you in trouble:
thrust::host_vector<int> Host_results;
that creates a vector of zero size. Later when you do this:
thrust::device_vector<int> Device_results = Host_results;
You've created another vector of zero size. Although these will not create compile errors, if you try to use these (e.g. by copying something into them) without a proper size allocation, you're going to have trouble at run-time.
This is also wrong:
Host_results = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(sizeOfProteinChain), Device_names, Device_results, _1 == soughtElement);
The return value of the thrust::copy_if function is an iterator. You cannot assign it to a vector. A vector is not the same as an iterator. Host_results is a vector.
Not sure what this is:
host_results=device_results;
Do you actually have a variable or vector somewhere that also begins with a lower case h? Because host_results is not the same as Host_results
Here's a complete worked example demonstrating how to do thrust::copy_if on device vectors of arbitrary length:
$ cat t808.cu
#include <thrust/copy.h>
#include <thrust/device_vector.h>
#include <thrust/iterator/counting_iterator.h>
#include <iostream>
#define COPY_VAL 7
using namespace thrust::placeholders;
int main(){
int objectArray[] = { 1, 11, 7, 2, 7, 23, 6, 6, 9, 11 };
int dsize = sizeof(objectArray)/sizeof(int);
int results[dsize];
thrust::device_vector<int> d_obj(objectArray, objectArray+dsize);
thrust::device_vector<int> d_res(dsize);
int resultCount = thrust::copy_if(thrust::make_counting_iterator(0), thrust::make_counting_iterator(dsize), d_obj.begin(), d_res.begin(), (_1 == COPY_VAL)) - d_res.begin();
thrust::copy(d_res.begin(), d_res.end(), results);
std::cout << "resultCount = " << resultCount << std::endl << "results: " << std::endl;
thrust::copy(d_res.begin(), d_res.end(), std::ostream_iterator<int>(std::cout, ", "));
std::cout << std::endl;
return 0;
}
$ nvcc -o t808 t808.cu
$ ./t808
resultCount = 2
results:
2, 4, 0, 0, 0, 0, 0, 0, 0, 0,
$

Related

Counting Duplicates in C++ - multiset?

UPD:-
Value Instances
 2   3
 3   2
 5   1
I want to limit the count to 1 for all the instances present in the multiset.
#include<bits/stdc++.h>
using namespace std;
int main() {
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(3);
p1.insert(2);
p1.insert(2);
for(auto itr : p1) {
if(p1.count(itr) > 1)
p1.erase(itr);
cout << itr;
}
}
How to fix this ?
My comment:
In that case, you should use a std::set<int> because that is actually what matches your requirement. You could use also a std::map<int, int> to map the key to the number of occurrences if you like.
OPs reply:
Can you add this to a full-fledged answer so that I can accept it for this question?
Here we go:
Just filtering duplicates:
#include <iostream>
#include <set>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once
using Table = std::set<int>;
Table table;
for (int value : sample) table.insert(value);
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 2
Value 3
Value 5
Demo on coliru
Counting the number of occurrences:
#include <iostream>
#include <map>
int main()
{
int sample[] = { 5, 2, 3, 3, 2, 2 };
// add all values at most once but count the number of occurrences
using Table = std::map<int, unsigned>;
Table table;
for (int value : sample) ++table[value];
// output the result
for (const Table::value_type& entry : table) {
std::cout << "Value " << entry.first << " (" << entry.second << " times)\n";
}
}
Output:
Value 2 (3 times)
Value 3 (2 times)
Value 5 (1 times)
Demo on coliru
The trick:
The std::map::operator[] inserts an element if the key is not yet there. This element (in this case std::pair<const int, unsigned>) is default initialized which grants that it starts as { key, 0 }.
So, there are two cases:
The key is not yet there:
The element is created as { key, 0 } and the value (.second of the element) is incremented immediately which results in { key, 1 }.
The key is already there:
The value (.second of the element) is incremented again.
A variation on filtering duplicates:
This keeps the original input order but removes repetitions (by book-keeping in a separate std::set).
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator iterRead = sample.begin();
Sample::iterator iterWrite = sample.begin();
for (; iterRead != sample.end(); ++iterRead) {
if (table.insert(*iterRead).second) *iterWrite++ = *iterRead;
}
sample.erase(iterWrite, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
Value 5
Value 2
Value 3
Demo on coliru
The trick:
std::set::insert() returns a pair of iterator and bool.
The iterator points to the key in the set (inserted or already been there).
The bool denotes if the key was inserted (true) or was already there (false).
The other trick:
Just erasing every found duplicate from the std::vector would result in the worse complexity O(n²).
Hence, two iterators are used, one for reading and one for writing. Thereby, every input value which is not yet in the bookkeeping table (and hence occurs the first time) is written back, otherwise not.
So, every value which occurred the first time is shifted towards the beginning and appended to the previous values which occurred the first time each. Additionally, the iterWrite points past the last written element after the loop and can be used to erase the rest (which contains left input values which are all duplicates).
The complexity of this algorithm is O(n) – much better than the naive approach.
Btw. the standard algorithms std::remove(), std::remove_if() does it the same way.
Thus, the same algorithm could be achieved with std::remove_if():
#include <algorithm>
#include <iostream>
#include <set>
#include <vector>
int main()
{
using Sample = std::vector<int>;
Sample sample = { 5, 2, 3, 3, 2, 2 };
// remove duplicates
using Table = std::set<int>;
Table table;
Sample::iterator last
= std::remove_if(sample.begin(), sample.end(),
[&](int value) { return !table.insert(value).second; });
sample.erase(last, sample.end());
// output the result
for (const Sample::value_type& entry : sample) {
std::cout << "Value " << entry << "\n";
}
}
Output:
like above
Demo on coliru
#include <iostream>
#include <set>
using namespace std;
int main()
{
multiset<int> p1;
p1.insert(5);
p1.insert(2);
p1.insert(3);
p1.insert(4);
p1.insert(2);
p1.insert(2);
for (auto iter = p1.begin(); iter != p1.end();)
{
p1.count(*iter) > 1 ? iter = p1.erase(iter) : iter++;
}
for (auto & iter : p1)
{
cout << iter << ", ";
}
return 0;
}

Is there a function to remove an element from a vector without shifting it in the c++ stdlib?

If I use vector.erase() such as
std::vector<int> n = { 3, 5, 6, 7 };
n.erase(n.begin() + 1);
vector will shift all the elements after the element removed down.
Is there a function in the C++ standard library that will not shift the elements? Like putting the back element at the removed element and pop back?
There isn't anything built in, but it's trivial to do yourself.
std::vector<int> n = { 3, 5, 6, 7 }; // create vector
n[1] = std::move(n.back()); // move last element to removal location
n.pop_back(); // remove unneeded element.
If you don't want to shift any elements, then in C++20 you can model this with a vector of std::optionals and the ranges library
#include <cstddef>
#include <optional>
#include <ranges>
#include <vector>
template<typename T>
auto remove_element(std::vector<std::optional<T>> &v, size_t i) {
v[i] = std::nullopt;
return v
| std::views::filter(&std::optional<T>::has_value)
| std::views::transform([](auto &&o) {return *o;});
}
#include <iostream>
int main() {
std::vector<std::optional<int>> v{1, 2, 3, 4, 5, 6};
for (int i : remove_element(v, 3))
cout << i << ','; // 1,2,3,5,6,
cout << '\n';
}

What is the type signature of a range from the range-v3 library in C

Given the code below:
// This example demonstrates filtering and transforming a range on the
// fly with view adaptors.
#include <iostream>
#include <string>
#include <vector>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
using std::cout;
int main()
{
std::vector<int> const vi{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
using namespace ranges;
auto rng = vi | views::filter([](int i) { return i % 2 == 0; }) |
views::transform([](int i) { return std::to_string(i); });
// prints: [2,4,6,8,10]
cout << rng << '\n';
}
How do encapsulate the logic above into a specific function that returns a range I can pipe? I'm thinking a function that can take a range and output a range. I will need the type signature of a range and I'm not sure how to find out that type signature or write it out? Is there documentation on specifically how to do this and how do I find this out?

Writing back to iterator while looping over more than one collection

I would like to loop through two collections using iterators, modifying one based on a (sufficiently complex) algorithm involving the other. Consider the following minimal example:
#include <iostream>
#include <vector>
#include <boost/foreach.hpp>
#include <boost/range/combine.hpp>
#include <boost/tuple/tuple.hpp> // tie
using namespace std;
using namespace boost;
int main(void) {
// input data; never mind how these get filled
int aa[] = {2, 3, 5, 8, 13, 21};
int bb[] = {1, 0, 1, 1, 0, 1};
vector<int> a (&aa[0], &aa[sizeof(aa)/sizeof(aa[0])]);
vector<int> b (&bb[0], &bb[sizeof(bb)/sizeof(bb[0])]);
// output storage; assume it has always correct dim.
vector<int> c (a.size());
// iterate through two coll., reading from both
int p, q;
BOOST_FOREACH (tie(p,q), combine(a,b)) { // loop1
cout << p << "*" << q << "=" << p*q << endl;
}
// iterate through one coll., writing to it
BOOST_FOREACH (int& r, c) { // loop2
r = 42;
}
// iterate through two coll., reading from one, writing to the other?
BOOST_FOREACH (??? p, s ???, combine(a,c)) { // loop3
s = p * 2;
}
return 0;
}
How do I declare the part between the ???s (or otherwise change the parameters in loop3)?
The value type of a zip_range is a tuple of references to elements:
#include <iostream>
#include <vector>
#include <boost/range.hpp>
#include <boost/range/combine.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/foreach.hpp>
int main(int ac,char* av[])
{
// input data; never mind how these get filled
int aa[] = {2, 3, 5, 8, 13, 21};
int bb[] = {1, 0, 1, 1, 0, 1};
std::vector<int> a(boost::begin(aa), boost::end(aa));
std::vector<int> const b(boost::begin(bb), boost::end(bb));
// output storage; assume it has always correct dim.
std::vector<int> c (a.size());
typedef boost::tuple<int const&, int&> val_t;
BOOST_FOREACH(val_t const& v, boost::combine(a, c)) {
v.get<1>() = v.get<0>() * 2;
}
}
IMO, you're overusing BOOST_FOREACH to an almost shocking degree. Like std::foreach, this should be one of your last choices of algorithm.
Your third loop should almost certainly be written using std::transform. It's intended to take an input range, transform it, and deposit the result in an output range (or take two input ranges, combine them, and put the result in a third, such as in your first (mis)use of BOOST_FOREACH).
Using this, your third loop comes out something like:
// c[i] = a[i] * 2, i = 0..N-1
std::transform(begin(a), end(a), begin(c), [](int i) { return i * 2; });
As for your second, it looks like you really want std::fill_n.
std::fill_n(begin(c), end(c), 42);
Now, it's certainly true that something based on ranges (e.g., the algorithms in Boost Range) could make this a bit simpler by replacing each begin(X), end(X) pair with a single parameter. Nonetheless, these are already clearly superior to the BOOST_FOREACH versions with miscellaneous ties and combines to try force your square pegs into round holes.

Printing an array in C++?

Is there a way of printing arrays in C++?
I'm trying to make a function that reverses a user-input array and then prints it out. I tried Googling this problem and it seemed like C++ can't print arrays. That can't be true can it?
Just iterate over the elements. Like this:
for (int i = numElements - 1; i >= 0; i--)
cout << array[i];
Note: As Maxim Egorushkin pointed out, this could overflow. See his comment below for a better solution.
Use the STL
#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>
#include <ranges>
int main()
{
std::vector<int> userInput;
// Read until end of input.
// Hit control D
std::copy(std::istream_iterator<int>(std::cin),
std::istream_iterator<int>(),
std::back_inserter(userInput)
);
// ITs 2021 now move this up as probably the best way to do it.
// Range based for is now "probably" the best alternative C++20
// As we have all the range based extension being added to the language
for(auto const& value: userInput)
{
std::cout << value << ",";
}
std::cout << "\n";
// Print the array in reverse using the range based stuff
for(auto const& value: userInput | std::views::reverse)
{
std::cout << value << ",";
}
std::cout << "\n";
// Print in Normal order
std::copy(userInput.begin(),
userInput.end(),
std::ostream_iterator<int>(std::cout,",")
);
std::cout << "\n";
// Print in reverse order:
std::copy(userInput.rbegin(),
userInput.rend(),
std::ostream_iterator<int>(std::cout,",")
);
std::cout << "\n";
}
May I suggest using the fish bone operator?
for (auto x = std::end(a); x != std::begin(a); )
{
std::cout <<*--x<< ' ';
}
(Can you spot it?)
Besides the for-loop based solutions, you can also use an ostream_iterator<>. Here's an example that leverages the sample code in the (now retired) SGI STL reference:
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
short foo[] = { 1, 3, 5, 7 };
using namespace std;
copy(foo,
foo + sizeof(foo) / sizeof(foo[0]),
ostream_iterator<short>(cout, "\n"));
}
This generates the following:
./a.out
1
3
5
7
However, this may be overkill for your needs. A straight for-loop is probably all that you need, although litb's template sugar is quite nice, too.
Edit: Forgot the "printing in reverse" requirement. Here's one way to do it:
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
short foo[] = { 1, 3, 5, 7 };
using namespace std;
reverse_iterator<short *> begin(foo + sizeof(foo) / sizeof(foo[0]));
reverse_iterator<short *> end(foo);
copy(begin,
end,
ostream_iterator<short>(cout, "\n"));
}
and the output:
$ ./a.out
7
5
3
1
Edit: C++14 update that simplifies the above code snippets using array iterator functions like std::begin() and std::rbegin():
#include <iostream>
#include <iterator>
#include <algorithm>
int main()
{
short foo[] = { 1, 3, 5, 7 };
// Generate array iterators using C++14 std::{r}begin()
// and std::{r}end().
// Forward
std::copy(std::begin(foo),
std::end(foo),
std::ostream_iterator<short>(std::cout, "\n"));
// Reverse
std::copy(std::rbegin(foo),
std::rend(foo),
std::ostream_iterator<short>(std::cout, "\n"));
}
There are declared arrays and arrays that are not declared, but otherwise created, particularly using new:
int *p = new int[3];
That array with 3 elements is created dynamically (and that 3 could have been calculated at runtime, too), and a pointer to it which has the size erased from its type is assigned to p. You cannot get the size anymore to print that array. A function that only receives the pointer to it can thus not print that array.
Printing declared arrays is easy. You can use sizeof to get their size and pass that size along to the function including a pointer to that array's elements. But you can also create a template that accepts the array, and deduces its size from its declared type:
template<typename Type, int Size>
void print(Type const(& array)[Size]) {
for(int i=0; i<Size; i++)
std::cout << array[i] << std::endl;
}
The problem with this is that it won't accept pointers (obviously). The easiest solution, I think, is to use std::vector. It is a dynamic, resizable "array" (with the semantics you would expect from a real one), which has a size member function:
void print(std::vector<int> const &v) {
std::vector<int>::size_type i;
for(i = 0; i<v.size(); i++)
std::cout << v[i] << std::endl;
}
You can, of course, also make this a template to accept vectors of other types.
Most of the libraries commonly used in C++ can't print arrays, per se. You'll have to loop through it manually and print out each value.
Printing arrays and dumping many different kinds of objects is a feature of higher level languages.
It certainly is! You'll have to loop through the array and print out each item individually.
This might help
//Printing The Array
for (int i = 0; i < n; i++)
{cout << numbers[i];}
n is the size of the array
std::string ss[] = { "qwerty", "asdfg", "zxcvb" };
for ( auto el : ss ) std::cout << el << '\n';
Works basically like foreach.
My simple answer is:
#include <iostream>
using namespace std;
int main()
{
int data[]{ 1, 2, 7 };
for (int i = sizeof(data) / sizeof(data[0])-1; i >= 0; i--) {
cout << data[i];
}
return 0;
}
You can use reverse iterators to print an array in reverse:
#include <iostream>
int main() {
int x[] = {1,2,3,4,5};
for (auto it = std::rbegin(x); it != std::rend(x); ++it)
std::cout << *it;
}
output
54321
If you already reversed the array, you can replace std::rbegin and std::rend with std::begin/std::end, respectively, to iterate the array in forward direction.
It's quite straightforward to copy the array's elements to a suitable output iterator. For example (using C++20 for the Ranges version):
#include <algorithm>
#include <array>
#include <iostream>
#include <iterator>
template<typename T, std::size_t N>
std::ostream& print_array(std::ostream& os, std::array<T,N> const& arr)
{
std::ranges::copy(arr, std::ostream_iterator<T>(os, ", "));
return os;
}
Quick demo:
int main()
{
std::array example{ "zero", "one", "two", "three", };
print_array(std::cout, example) << '\n';
}
Of course it's more useful if we can output any kind of collection, not only arrays:
#include <algorithm>
#include <iterator>
#include <iosfwd>
#include <ranges>
template<std::ranges::input_range R>
std::ostream& print_array(std::ostream& os, R const& arr)
{
using T = std::ranges::range_value_t<R>;
std::ranges::copy(arr, std::ostream_iterator<T>(os, ", "));
return os;
}
The question mentions reversing the array for printing. That's easily achieved by using a view adapter:
print_array(std::cout, example | std::views::reverse) << '\n';
// Just do this, use a vector with this code and you're good lol -Daniel
#include <Windows.h>
#include <iostream>
#include <vector>
using namespace std;
int main()
{
std::vector<const char*> arry = { "Item 0","Item 1","Item 2","Item 3" ,"Item 4","Yay we at the end of the array"};
if (arry.size() != arry.size() || arry.empty()) {
printf("what happened to the array lol\n ");
system("PAUSE");
}
for (int i = 0; i < arry.size(); i++)
{
if (arry.max_size() == true) {
cout << "Max size of array reached!";
}
cout << "Array Value " << i << " = " << arry.at(i) << endl;
}
}
If you want to make a function that prints every single element in an array;
#include <iostream>
using namespace std;
int myArray[] = {1,2,3,4, 77, 88};
void coutArr(int *arr, int size){
for(int i=0; i<size/4; i++){
cout << arr[i] << endl;
}
}
int main(){
coutArr(myArray, sizeof(myArray));
}
The function above prints every single element in an array only, not commas etc.
You may be wondering "Why sizeoff(arr) divided by 4?". It's because cpp prints 4 if there's only a single element in an array.