How to access members of thrust::device_vector<struct> [duplicate] - c++

This question already has answers here:
Thrust inside user written kernels
(4 answers)
Closed 4 years ago.
CUDA has some documentation found here: https://docs.nvidia.com/cuda/thrust/index.html#vectors which allows the use of vector in device memory/code. I am trying to create a vector of a struct type to use for general processing. Here is the sample code:
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <iostream>
struct Data
{
double first, second, total;
};
__global__
void add(thrust::device_vector<Data> *d_matrix)
{
&d_matrix[1].total = &d_matrix[1].first + &d_matrix[1].second;
}
int main()
{
thrust::host_vector<Data> matrix;
thrust::device_vector<Data> *d_matrix;
int size = sizeof(thrust::host_vector<Data>);
matrix[1].first = 2100;
matrix[1].second = 100;
cudaMalloc(&d_matrix, size);
cudaMemcpy(d_matrix, &matrix, size, cudaMemcpyHostToDevice);
add<<<1,1>>>(d_matrix);
cudaMemcpy(&matrix, d_matrix, size, cudaMemcpyDeviceToHost);
cudaFree(d_matrix);
std::cout << "The sum is: " << matrix[1].total;
return 0;
}
I get the following error:
gpuAnalysis.cu(13): error: class "thrust::device_vector>" has no member "total"
gpuAnalysis.cu(13): error: class "thrust::device_vector>" has no member "first"
gpuAnalysis.cu(13): error: class "thrust::device_vector>" has no member "second"
3 errors detected in the compilation of
"/tmp/tmpxft_000013c9_00000000-8_gpuAnalysis.cpp1.ii".
According to the documentation provided on the nvidia site, these vectors are able to store all data types as std::vector. Is there a way to fix this error to access the members of the struct with each vector element?

void add(thrust::device_vector<Data> *d_matrix) {
&d_matrix[1].total = &d_matrix[1].first + &d_matrix[1].second;
}
In this code, d_matrix parameter is actually a pointer to an object of type thrust::device_vector<Data>. The expression &d_matrix[1].total is due to C++ operator precedence evaluated such that d_matrix[1] is considered to be the 2nd element of some non-existing array of elements of type thrust::device_vector<Data>, since a pointer can be treated as an array automatically. This (non-existing) 2nd element is then subject of .total member access, which does not exist.
Try (*d_matrix)[1].total = ... instead.
Also I am not sure that your code is correct. For example, you don't specify the size (number of elements, not size of an object) of neither your host_vector nor device_vector. You also cudaMemcpy vector object themselves; does it copy their content as well? Is it even allowed? I have no experience with Thrust, but according this page, there are much simpler way how to create device_vector.

Related

consume element from std::set [duplicate]

This question already has answers here:
Is it possible to move an item out of a std::set?
(2 answers)
Closed 5 months ago.
I try to directly consume elements from a set, which i cannot get to work from the outside getting an error
binding reference of type ‘int&&’ to ‘std::remove_reference<const int&>::type’ {aka ‘const int’} discards qualifiers
Consuming from a vector works perfectly fine.
I really do not understand where syntactic the difference would be between consuming from the set or the vector, as they work similar cocerning their iterators.
I can make a Workaround pops(), however, I do not neccessarily see this as a intuitive solution.
#include <vector>
#include <set>
#include <iostream>
class A {
public:
std::vector<int> intv_{1,2,3};
std::set<int> ints_{1,2,3};
int pops() {
auto rslt = std::move(*ints_.begin());
ints_.erase(ints_.begin());
return rslt;
}
};
using namespace std;
void consume_int(bool dummy, int&& i) {
cout << i << endl;
}
using namespace std;
int main() {
A a;
consume_int(true, std::move( *(a.intv_.begin()) )); //OK!
a.intv_.erase(a.intv_.begin());
consume_int(true, std::move( *a.ints_.begin() )); //FAIL to compile
a.ints_.erase(a.ints_.begin());
consume_int(true, std::move(a.pops())); //Workaround OK!
return 0;
}
The point is: You are not allowed to change the objects within a set, as this would require to move their location within the set. This is why the iterator only returns a const reference even for non-const std::set!
Now r-value references are intended to be used to modify the object (moving the contents away – which would be such an illegal change of the set entry! – at that point the set cannot know that you are going to erase the entry anyway), and you cannot assign const references to, which would open doors to all such illegal modifications (of set members, objects in non-writable memory sections, etc).
Edit: Still you actually can move elements out of a std::set, provided you have at least C++17 available, in this case you can profit from the extract function:
int pops()
{
auto handle = ints_.extract(ints_.begin());
auto rslt = std::move(handle.value()); // for DEMONSTRATION purposes!
return rslt;
}
with the handle getting discarded on exiting the function – though, actually you don't need to explicitly move anything at all, you can simply write:
int pops()
{
auto handle = ints_.extract(ints_.begin());
return handle.value();
// or as a one-liner:
return ints_.extract(ints_.begin()).value();
}

How I can insert an array of floats returned by a lambda into a vector of floats?

I'm trying to make the following code to work
auto createMyArray = []() {
float foo[] = {0.0f, 1.5f, 2.0f};
return foo;
};
auto myArray = createMyArray();
std::vector<float> myVector;
// fatal error: no matching function for call to 'begin'
myVector.insert(myVector.end(), std::begin(myArray), std::end(myArray));
The issue is that createMyArray returns a pointer to the array and I'm not sure if it will be a good idea to try dereference it.
Also I'm getting the following warning
warning: address of stack memory associated with local variable 'foo' returned [-Wreturn-stack-address]
return foo;
Which has sense because I'm not using new to create the array since I want to avoid heap allocations.
The modern C++ way of dealing with such arrays is to use std::array. That should avoid the problems you are facing.
Using a native C array like you do gets you into allocation-related problems which you should avoid. The compiler warning you are seeing is not to be taken lightly (like any warning). It tells you that foo points to memory that falls out-of-scope outside your lambda. It is quite likely to be overwritten by the myVector object you create after the call to createMyArray() and any further reference to foo's elements may give you garbage.
Apart from that see the helpful answers here: How do you copy the contents of an array to a std::vector in C++ without looping?
After exiting the lambda expression the local array will not be alive. So the code has undefined behavior.
But there is no need to use a lambda to insert an initializer list in a vector.
Here is a demonstrative program.
#include <iostream>
#include <vector>
#include <iterator>
int main()
{
std::vector<float> myVector;
myVector.insert( std::end( myVector ), {0.0f, 1.5f, 2.0f} );
for ( const auto &item : myVector ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
The program output is
0 1.5 2
You can use std::back_inserter to copy elements into the vector appending at the end
std::copy(myArray, myArray + 3, std::back_inserter(myVector));
Or
myVector.insert(myVector.end(), myArray, myArray + 3);
By the way the array created in lamba function is stack allocated, which means array will no longer exist after the execution of lamba function, instead use dynamic memory allocation using new or std::array

C++ - How to create a dynamic vector

I am following this example to make an adjacency list. However it seems like the vector size cannot be dynamic.
Visual studio throws an error
expression did not evaluate to a constant
on this line
vector<int> adj[V];
The strange thing is that the same exact code works correctly on codeblocks IDE.
I've tried replacing the above line with vector<int> adj; but then I cannot send the vector as a parameter to addEdge(adj, 0, 1); as it throws another error about pointers which I also don't know how to correct.
What could I do to dynamically create my vector?
C++ - How to create a dynamic vector
You don't need to do that for this example. But if you did need it, you could use std::make_unique.
The linked example program is ill-formed. I recommend to not try to learn from that. The issue that you encountered is that they use a non-const size for an array. But the size of an array must be compile time constant in C++. Simple fix is to declare the variable type as const:
const int V = 5;
I've tried replacing the above line with vector<int> adj;
You can't just replace an array of vectors with a single vector and expect the program to work without making other changes.
I need the size to be dynamic as it will only be known at compile time.
Assuming you meant to say that the size will only be known at runtime, the solution is to use a vector of vectors.
As written by eerorika, the example code isn't a good one, and you should avoid using raw arrays like that. An array in C/C++ is of static size, each vector in this array is dynamic, but the entire array is not!
There are two approaches for such a question. Either use adjacency lists (which is more common):
#include <vector>
#include <stdint.h>
class Vertix
{
public:
Vertix(uint64_t id_) : id(id_) {}
uint64_t get_id() const { return id; }
void add_adj_vertix(uint64_t id) { adj_vertices.push_back(id); }
const std::vector<uint64_t>& get_adj_vertices() const { return adj_vertices; }
private:
uint64_t id;
std::vector<uint64_t> adj_vertices;
};
class Graph
{
public:
void add_vertix(uint64_t id)
{
vertices[id] = Vertix(id);
}
void add_edge(uint64_t v_id, uint64_t u_id)
{
edges.emplace_back(u_id, v_id);
vertices[u_id].add_adj_vertix(v_id);
}
private:
std::vector<Vertix> vertices;
std::vector<std::pair<uint64_t, uint64_t>> edges;
};
or use double vector to represent the edges matrix:
std::vector<std::vector<uint64_t>> edges;
But it isn't a real matrix, and you cannot check if (u, v) is in the graph in O(1), which misses the point of having adjacency matrix. Assuming you know the size of Graph on compile time, you should write something like:
#include <array>
#include <stdint.h>
template <size_t V>
using AdjacencyMatrix = std::array<std::array<bool, V>, V>;
template <size_t V>
void add_edge(AdjacencyMatrix<V>& adj_matrix, uint64_t u, uint64_t v)
{
if (u < V && v < V)
{
adj_matrix[u][v] = true;
}
else
{
// error handling
}
}
Then you can use AdjacencyMatrix<5> instead of what they were using on that example, in O(1) time, and although it has static size, it does work as intended.
There’s no need to use C-style arrays in modern C++. Their equivalent is std::array, taking the size as a template parameter. Obviously that size can’t be a runtime variable: template parameters can be types or constant expressions. The compiler error reflects this: std::array is a zero cost wrapper over an internal, raw “C” array.
If the array is always small, you may wish to use a fixed-maximum-size array, such as provided by boost. You get all performance benefits of fixed size arrays and can still store down to zero items in it.
There are other solutions:
If all vectors have the same size, make a wrapper that takes two indices, and uses N*i1+i2 as the index to an underlying std::vector.
If the vectors have different sizes, use a vector of vectors: std::vector>. If there are lots of vectors and you often add and remove them, you may look into using a std::list of vectors.

Passing a multidimensional array of variable size in function in c++

I have written the following code but it is showing the error
use of parameter outside function body before ‘]’ token
The code is
#include <iostream>
using namespace std;
int n=10;
void a(int s[n][n])
{
cout<<"1";
}
int main()
{
int s[n][n]={0};
a(s);
}
I am trying to pass a multidimensional array of variable size using global variable. I don't want to use vectors in this.
Firstly C++ doesn't have variable-length arrays, So Instead of int s[n][n]={0}; you should use
std::vector<std::vector<int>> s(10,std::vector<int>(10));
Secondly how to pas 2D array to a function,
void a(std::vector<int> **s,int rows, int cols){
cout<<"1";
/* stuff with 2D array */
}
You've already received answers which explain the why. I'm offering this only as a matter of completeness to C++. Personally, though I don't understand why you're avoiding vectors, they do offer a more intuitive or pleasing solution. Inside of your function for handling the vectors, you can always consult std::vector<>.size() to ensure you stay within bounds or std::vector<>.at() and catch the exception that is thrown when accessing out of bounds. Nevertheless, your particular question may also be solved by templates. Below is your code, slightly modified, with comments to illustrate. I tested using gcc 4.8.5:
#include <iostream>
using namespace std;
// Made constant so that the compiler will not complain
// that a non-constant value, at compile time, is being
// used to specify array size.
const int n=10;
// Function template. Please note, however, this template
// will only auto-gen functions for 2D arrays.
template<int lb>
void a(int s[][lb])
{
// output the last element to know we're doing this correctly
// also note that the use of 9 hard-codes this function template
// to 2D arrays where the first dimension is always, at least, 10
// elements long!!!!!!
cout << s[9][lb - 1] << endl;
}
int main()
{
int s[n][1];
s[9][0] = 15;
a<1>(s); // explicitly call template with the size of the last dimension
a(s); // Call the same function generated from the previous call
int t[n][2];
t[9][1] = 17;
a(t); // compiler implicitly determines the type of function to generate
}
You can't. Your function a() needs to know the last dimension, which is the length of each row in the matrix. You need to pass this as an extra parameter to your function.
void a(int * matrix, int rows, int columns) {
int row = ...
int column = ...
if (row < rows && column < columns) {
cout << matrix[row*columns + column];
}
}
int main() {
...
a(&s[0][0], 10);
...

How to pass a vector to another vector push back? (without creating a extra variable to pass)

Well I am questioning myself if there is a way to pass a vector directly in a parameter, with that I mean, like this:
int xPOS = 5, yPOS = 6, zPOS = 2;
//^this is actually a struct but
//I simplified the code to this
std::vector <std::vector<int>> NodePoints;
NodePoints.push_back(
std::vector<int> {xPOS,yPOS,zPOS}
);
This code ofcourse gives an error; typename not allowed, and expected a ')'
I would have used a struct, but I have to pass the data to a Abstract Virtual Machine where I need to access the node positions as Array[index][index] like:
public GPS_WhenRouteIsCalculated(...)
{
for(new i = 0; i < amount_of_nodes; ++i)
{
printf("Point(%d)=NodeID(%d), Position(X;Y;Z):{%f;%f;%f}",i,node_id_array[i],NodePosition[i][0],NodePosition[i][1],NodePosition[i][2]);
}
return 1;
}
Ofcourse I could do it like this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//local
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
or this:
std::vector <std::vector<int>> NodePoints;//global
std::vector<int> x;//global
x.push_back(xPOS);
x.push_back(yPOS);
x.push_back(zPOS);
NodePoints.push_back(x);
x.clear()
but then I'm wondering which of the two would be faster/more efficient/better?
Or is there a way to get my initial code working (first snippet)?
Use C++11, or something from boost for this (also you can use simple v.push_back({1,2,3}), vector will be constructed from initializer_list).
http://liveworkspace.org/code/m4kRJ$0
You can use boost::assign as well, if you have no C++11.
#include <vector>
#include <boost/assign/list_of.hpp>
using namespace boost::assign;
int main()
{
std::vector<std::vector<int>> v;
v.push_back(list_of(1)(2)(3));
}
http://liveworkspace.org/code/m4kRJ$5
and of course you can use old variant
int ptr[1,2,3];
v.push_back(std::vector<int>(ptr, ptr + sizeof(ptr) / sizeof(*ptr));
If you don't have access to either Boost or C++11 then you could consider quite a simple solution based around a class. By wrapping a vector to store your three points within a class with some simple access controls, you can create the flexibility you need. First create the class:
class NodePoint
{
public:
NodePoint( int a, int b, int c )
{
dim_.push_back( a );
dim_.push_back( b );
dim_.push_back( c );
}
int& operator[]( size_t i ){ return dim_[i]; }
private:
vector<int> dim_;
};
The important thing here is to encapsulate the vector as an aggregate of the object. The NodePoint can only be initialised by providing the three points. I've also provided operator[] to allow indexed access to the object. It can be used as follows:
NodePoint a(5, 6, 2);
cout << a[0] << " " << a[1] << " " << a[2] << endl;
Which prints:
5 6 2
Note that this will of course throw if an attempt is made to access an out of bounds index point but that's still better than a fixed array which would most likely seg fault. I don't see this as a perfect solution but it should get you reasonably safely to where you want to be.
If your main goal is to avoid unnecessary copies of vector<> then here how you should deal with it.
C++03
Insert an empty vector into the nested vector (e.g. Nodepoints) and then use std::swap() or std::vector::swap() upon it.
NodePoints.push_back(std::vector<int>()); // add an empty vector
std::swap(x, NodePoints.back()); // swaps contents of `x` and last element of `NodePoints`
So after the swap(), the contents of x will be transferred to NodePoints.back() without any copying.
C++11
Use std::move() to avoid extra copies
NodePoints.push_back(std::move(x)); // #include<utility>
Here is the explanation of std::move and here is an example.
Both of the above solutions have somewhat similar effect.