Allocate a 2D vector in unified memory CUDA C/C++ - c++

So I need to create a matrix with different row lengths, and this is how it looks like in normal C/C++
int** MpesosT = (int**)malloc(N * sizeof(int*));
for (int i = 0; i < N; i++)
{
MpesosT[i] = (int*)malloc(vecinosT[i] * sizeof(int));
}
However, I don't know how to do this using the CUDA function to allocate memory:
int* Vector; cudaMallocManaged(&Vector, VectorSize* sizeof(int));
I can't just use a vector of size N*N or something, because every row has a different size, so how could I do that?

Took a couple of hours, but I found the way to do it. In case anyone has the same problem:
double** Matrix;
cudaMallocManaged((double***)&Matrix, N * sizeof(double*));
for (i = 0; i < N; i++)
{
cudaMallocManaged((double**)&Matrix[i], rowlength[i] * sizeof(double));
}
This way, every row has a different length

Related

How to delete and reassign a dynamically allocated pointer

I'm taking a c++ programming course (we are still mostly using C) and we just got to dynamic allocation of memory. For one of my homeworks, I'm asked to create a function that transposes any given matrix. This function is given the following arguments as inputs: a pointer, in which are saved the matrix elements, the number of rows and of colunms. I would like this to be a void type function that changes the order of the stored elements without returning any new pointer.
I tried creating a new pointer, in which I save the elemtens in the correct order (using 2 for loops). Then what I would like to do is deallocating the original pointer (using the delete command), assinging it to the new pointer and finally deleting the new pointer.
This unfortunately does not work (some elements turn out to be random numbers), but I don't understand why.
I hope my code is more precise and clear than my explanation:
void Traspose(float *matrix, const int rows, const int cols ){
auto *tras = new float [rows * cols];
int k = 0;
for(int i = 0; i < cols; i++){
for(int j = 0; j < rows * cols; j += cols){
tras[k] = matrix[j + i];
k++;
}
}
delete[] matrix;
matrix = tras;
delete[] tras;
}
All those lines are wrong:
delete[] matrix;
matrix = tras;
delete[] tras;
You didn't allocate matrix so you don't want do delete it.
You assign tras to matrix and then you delete tras, after that, tras points nowhere, nor does matrix.
matrix = tras is pointless anyway, because matrix is a local variable, and any changes to local variables are lost after the function ends.
You're inventing a problem where none should exist.
A matrix AxB in dimension will transpose to a matrix BxA in size. While the dimensional difference is obvious the storage requirements might not be so. Your storage is identical.
Per the function signature, the change must be done in the same memory allocated to matrix. E.g., the results should be stored back into matrix memory. So, don't delete that memory; leave it alone. It is both large enough to hold the transposition, and owned by the caller regardless.
Rather, do this:
void Traspose(float *matrix, const int rows, const int cols)
{
float *tras = new float[ rows * cols ];
int k = 0;
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows * cols; j += cols)
tras[k++] = matrix[j + i];
}
for (int i=0; i<k; ++i)
matrix[i] = tras[i];
delete [] tras;
}
Note this gets quite a bit simpler (and safer) if the option to use the standard library algorithms and containers is on the table:
void Traspose(float *matrix, const int rows, const int cols)
{
std::vector<float> tras;
tras.reserve(rows*cols);
for (int i = 0; i < cols; i++)
{
for (int j = 0; j < rows * cols; j += cols)
tras.emplace_back(matrix[j + i]);
}
std::copy(tras.begin(), tras.end(), matrix);
}
Finally, probably worth investigating in your spare time, there are algorithms to do this, even for non-square matrices, in place without temporary storage using permutation chains. I'll leave researching those as an exercise to the OP.

Define an array which the number of rows(clos) is unknown in C++

I have a 2048x2048 matrix of grayscale image,i want to find some points which value are > 0 ,and store its position into an array of 2 columns and n rows (n is also the number of founded points) Here is my algorithm :
int icount;
icount = 0;
for (int i = 0; i < 2048; i++)
{
for (int j = 0; j < 2048; j++)
{
if (iout.at<double>(i, j) > 0)
{
icount++;
temp[icount][1] = i;
temp[icount][2] = j;
}
}
}
I have 2 problems :
temp is an array which the number of rows is unknown 'cause after each loop the number of rows increases ,so how can i define the temp array ? I need the exact number of rows for another implementation later so i can't give some random number for it.
My algorithm above doesn't work,the results is
temp[1][1]=0 , temp[1][2]=0 , temp[2][1]=262 , temp[2][2]=655
which is completely wrong,the right one is :
temp[1][1]=1779 , temp[1][2]=149 , temp[2][1]=1780 , temp[2][2]=149
i got the right result because i implemented it in Matlab, it is
[a,b]=find(iout>0);
How about a std::vector of std::pair:
std::vector<std::pair<int, int>> temp;
Then add (i, j) pairs to it using push_back. No size needed to be known in advance:
temp.push_back(make_pair(i, j));
We'll need to know more about your problem and your code to be able to tell what's wrong with the algorithm.
When you define a variable of pointer type, you need to allocate memory and have the pointer point to that memory address. In your case, you have a multidimensional pointer so it requires multiple allocations. For example:
int **temp = new int *[100]; // This means you have room for 100 arrays (in the 2nd dimension)
int icount = 0;
for(int i = 0; i < 2048; i++) {
for(int j = 0; j < 2048; j++) {
if(iout.at<double>(i, j) > 0) {
temp[icount] = new int[2]; // only 2 variables needed at this dimension
temp[icount][1] = i;
temp[icount][2] = j;
icount++;
}
}
}
This will work for you, but it's only good if you know for sure you're not going to need any more than the pre-allocated array size (100 in this example). If you know exactly how much you need, this method is ok. If you know the maximum possible, it's also ok, but could be wasteful. If you have no idea what size you need in the first dimension, you have to use a dynamic collection, for example std::vector as suggested by IVlad. In case you do use the method I suggested, don't forget to free the allocated memory using delete []temp[i]; and delete []temp;

cpp two dimensional dynamic array

I'm using c++ and I want to use two dimensional dynamic array. I tried this:
#include<iostream.h>
using namespace std;
void main(){
int const w=2;
int size;
cout<<"enter number of vertex:\n";
cin>>size;
int a[size][w];
for(int i=0; i<size; i++)
for(int j=0; j<w; j++){
cin>>a[i][j];
}
}
but not worded.
and I tried this:
int *a = new a[size][w];
instead of
int a[size][w];
but not worked!
could you help me plz.
thanks a lot.
The correct approach here would be to encapsulate some of the standard containers, that will manage memory for you, inside a class that provides a good interface. The common approach there would be an overload of operator() taking two arguments that determine the row and column in the matrix.
That aside, what you are trying to create manually is an array of dynamic size of arrays of constant size 2. With the aid of typedef you can write that in a simple to understand manner:
const int w = 2;
typedef int array2int[w];
int size = some_dynamic_value();
array2int *p = new array2int[size];
Without the typedef, the syntax is a bit more convoluted, but doable:
int (*p)[w] = new int [size][w];
In both cases you would release memory with the same simple statement:
delete [] p;
The difference with the approaches doing double pointers (int **) is that the memory layout of the array is really that of an array of two dimensions, rather than a jump table into multiple separately allocated unidimensional arrays, providing better locality of data. The number of allocations is lower: one allocation vs. size + 1 allocations, reducing the memory fragmentation. It also reduces the potential from memory leaks (a single pointer is allocated, either you leak everything or you don't leak at all).
For a dynamic sized array you must dynamically allocate it. Instead of
int *a = new a[size][w];
Use
int** a = new int*[size];
for(int i = 0; i < size; i++)
a[i] = new int[w];
OP is saying he wants to create a 2 dimensional array where one dimension is already known and constant and the other dimension is dynamic.. Not sure if I got it right but here goes:
int main() {
const int w = 2;
int size = 10;
int* arr[w];
for (int i = 0; i < w; ++i)
arr[i] = new int[size];
//do whatever with arr..
//std::cout<<arr[0][0];
for (int i = 0; i < w; ++i)
for (int j = 0; j < size; ++j)
std::cout<<arr[i][j];
for (int i = 0; i < w; ++i)
delete[] arr[i];
return 0;
}
You can not do that in c++, please read about dynamic memory allocation
the code below should work
int* twoDimentionalArray = new [size*w]

2D pointer pointing 2D array in C

How to make a 2d pointer like **check point a 2d array like
mycheck[][]?
How to convert a 1d like check[16], to 2d array like mycheck[4][4]?
My attempt
float (*mycheck)[4] = (float (*)[4]) check;
But if second time I want to use mycheck again for some other 1d array, how can I do? My attempt:
float (*mycheck)[4] = (float (*)[4]) other1darray;
this will definitely give a re-declaration error.
The answer to the first question is that you cannot do that. All you can do is allocate some memory and copy the data over.
The answer to the second question is very simple
mycheck = (float (*)[4]) other1darray;
You only have to declare variables once, after that just use the variable name.
Array a[] decays to a pointer to the first element when you drop the []. This does not happen recursively, in other words, it doesn't work for a[][].
Secondly, you can't assign arrays in C. You can ONLY initialize them. You will have to set each member yourself.
You can create a 2D array in C like this.
Use a typedef to make it easier.
typedef int **matrix;
matrix create2Darray(int row, int col)
{
int idx;
matrix m = malloc(row * sizeof(int*));
for (idx = 0; idx < row; ++idx)
{
m[idx] = malloc(col * sizeof(int));
}
return m;
}
And then call this in another function;
matrix check = create2Darray(2, 2);
To assign a 1D array to a 2D array you can assign the pointers to the right position in the array. An example below. It also show how to create a 2D array dynamically, but I commented it out, since it is not needed for the example.
#include <stdio.h>
#include <stdlib.h>
int main()
{
float **matrix;
float *array;
array = (float *) malloc(16 * sizeof(float));
for (size_t idx = 0; idx != 16; ++idx)
{
array[idx] = idx;
}
matrix = (float **) malloc(4 * sizeof(float *));
for (size_t idx = 0; idx != 4; ++idx)
{
// matrix[idx] = malloc(4 * sizeof(int));
matrix[idx] = &array[idx * 4];
}
for (size_t row = 0; row != 4; ++row)
{
for (size_t col = 0; col != 4; ++col)
{
printf("%.1f ", matrix[row][col]);
}
printf("\n");
}
}
Note: this makes the 1D array and 2D array point to the same memory. If you change something in the 1D it also changes in the 2D and vice-versa. If you don't want this, first copy the array.

Vector of vectors to 1D array

I was wondering if there is a clever way of presenting the information in a vector as a 1D array. Example:
Let's create a vector of vectors of 5x3 int elements
vector< vector<int>> iVector;
ivector.resize( 5 );
for(i = 0; i < 5; i++){
iVector[i].resize(3);
}
But now I want this structure to be converted into a 1D array:
int* myArray = new int[5*3];
So I could access each element which I want as follows:
for (i =0;i < 5; i++)
for(j =0; j< 3; j++)
myArray[i*3+j] = ...
I know I could just copy the vector to the array element by element, but I was wondering if there is a method that directly addresses the vector to array conversion. I also know that the vector can me addressed as iVector[i][j] , but unfortunately it needs to be an array as it will be sent to a GPU and GPUs dont understand vectors.
Just use std::copy 5 times.
int* ptrArray = myArray;
for (i =0;i < 5; i++) {
std::copy(iVector[i].begin(), iVector[i].end(), ptrArray);
ptrArray += iVector[i].size();
}
There's really nothing you can do here except copy it into an array. The GPU will not understand any abstraction you create any more than it can understand std::vector. All you can do is make an array and copy it over.
Vectors supposed to store the elements in a linear fashion, so in theory you can refer to the entire underlying vector (only a single vector):
std::vector<int> numbers;
int data[4] = &(numbers[0]);
Similarily, perhaps you can try the same approach for the 2D version.
However in your place I would consider to use a class that is specifically designed to handle matrices (it is easy to write one similar to std::vector().
Or you can use plain old C.
You first initialize the array size to be the number of rows * the number of columns your vector of vectors has. Then you use memcpy to copy each vector to the array.
vector<vector<int> > v = { {1,2},{3,4},{5,6} }; //v is 3 by 2 matrix
int *arr = (int*)malloc( (3*2) * sizeof(int)); // arr has size 3*2 = 6
for (int i = 0; i < 3; i++)
memcpy(arr + v[i].size() * i, &(v[i][0]), v[i].size() * sizeof(int));
Here's a function that I wrote that does this for you:
template<typename T>
T *vectorToArray(vector<vector<T> > const &v) {
T *rv = (T*)malloc((v.size()*v[0].size()) * sizeof(T)); //Assuming all rows have the same size
for (unsigned i = 0; i < v.size(); i++)
memcpy(rv + v[i].size() * i, &(v[i][0]), v[i].size() * sizeof(T));
return rv;
}
So now you can do something like this:
vector<vector<int> > v = { {1,2},{3,4},{5,6} }; //v is 3 by 2 matrix
int *arr = vectorToArray(v);
I hope this helps