say you have a matrix of dimensions x per y (per z) defined like:
int** tab = new int*[x];
for(int i=0; i<x; ++i) tab[i] = new int[y];
or
int*** tab = new int**[x];
for(int i=0; i<x; ++i) {
tab[i] = new int*[y];
for(int j=0; j<y; ++y) tab[i][j] = new int[z];
}
is there any smart way to access sub-matrix (get int**(*) without data copying, plain C++) which will have top-left(-front) corner [a,b(,c)] and size of [A, B(,C)]?
Here are (better or worse) graphical examples of the problem.
You are using what is called a jagged array. It is an array of arrays, where nothing besides runtime enforces that the sub arrays are the same size. Hence jagged, because you could have the subarrays vary in size.
In order to have a submatrix that is also a jagged array, you need for there to exist a jagged array of pointers pointing at the subarrays of the submatrix. These don't exist in general, so no, you cannot do this "without copying" at least some arrays of pointers to subarrays.
Had your matrix been not jagged array based, but instead single array with stride, then views of subarrays could be created without allocating new subarray pointer arrays. Also it would be more cache friendly.
To write the non-jagged matrix, start by writing an array view or span class that handles one dimension.
For two dimensions, you augment the span class to store a tuple of dimension sizes or strides. [] instead of returning a reference to the calculated element, creates a one-dimension-lower span instance pointing at the calculated position, until the dimension 0 case where you return a reference.
This will be highly efficient, permit efficient subarrays, but requires a few dozen or 100 lines of code to get right.
Related
I am very new to C++, but I have the task of translating a section of C++ code into python.
Going through the file, I found this section of code, which confuses me:
int n_a=(e.g 10)
int n_b=n_a-1;
int l_b[2*n_b];
int l_c[3*n_b];
int l_d[4*n_b];
for (int i=0; i<n_b; i++){
for (int j=0; j<2; j++) l_b[i*2+j]=0;
for (int j=0; j<3; j++) l_c[i*3+j]=0;
for (int j=0; j<4; j++) l_d[i*4+j]=0;
I know that it creates 3 arrays, the length of each defined by the action on the n_b variable, and sets all the elements to zero, but I do not understand what exactly this matrix is supposed to look like, e.g. if written on paper.
A common way to store a matrix with R rows and C columns is to store all elements in a vector of size R * C. Then when you need element (i, j) you just index the vector with i*C + j. This is not the only way your "matrix" could be stored in memory, but it is a common one.
In this code there are 3 C arrays that declared and initialized with zeros. The l_b array seems to be storage for a n_a x 2 matrix, the l_c array for a n_a x 3 matrix and the l_d array for a n_a x 4 matrix.
Of course, this is only an impression since to be sure we would need to see how these arrays are used later.
As in the comments, if you are going to convert this to python then you should probably use numpy for the matrices. In fact, the numpy arrays will store the elements in memory exactly like indexing I mentioned (by default, but you can also choose an alternative way passing an extra argument). You could do the same of this C++ code in oython with just
import numpy as np
n_a = (e.g 10)
l_b = np.zeros(shape=(n_a, 2))
l_c = np.zeros(shape=(n_a, 3))
l_d = np.zeros(shape=(n_a, 4))
These variables in numpy are 2D arrays and you can index them as usual.
Ex:
l_d[2, 1] = 15.5
We can also have a nice syntax for working with vector, matrices and linear algebra in C++ by using one of the available libraries. One such library is armadillo. We can create the three previous matrices of zeros using armadillo as
#include <armadillo>
int main(int argc, char *argv[]) {
unsigned int n_a = 10;
// A 10 x 3 matrix of doubles with all elements being zero
// The 'arma::fill::zeros' argument is optional and without it the matrix
// elements will not be initialized
arma::mat l_b(n_a, 2, arma::fill::zeros);
arma::mat l_c(n_a, 3, arma::fill::zeros);
arma::mat l_d(n_a, 4, arma::fill::zeros);
// We use parenthesis for index, since "[]" can only receive one element in C/C++
l_b(2, 1) = 15.5;
// A nice function for printing, but it also works with operator<<
l_b.print("The 'l_b' matrix is");
return 0;
}
If you inspect armadillo types in gdb you will see that it has a mem atribute which is a pointer. This is in fact a C array for the internal elements of the matrix and when you index the matrix in armadillo it will translate the indexes into the proper index in this internal 1D array.
You can print the elements in this internal arry in gdb. For instance, print l_b.mem[0] will print the first element, print l_b.mem[1] will print the second element, and so one.
I would like to copy the 2 matrices. With a copy element by element through 2 for loops (row and column), after several mathematical operations and copies the final result is correct while using "memcpy" the final result is wrong in the decimal places. The code is as follows.
double **L_original;
double **L;
int nF,nU;
L = new double*[nU]();
L_original = new double*[nU]();
for(int i=0; i<nU; i++){
L_original[i] = new double[nF]();
L[i] = new double[nF]();
}
// copy element to element
/*for(int i=0; i<nU; i++)
for(int j=0; j<nF; j++)
L[i][j] = L_original[i][j];*/
memcpy(L, L_original, sizeof(L_original));
This is the correct result:Matrix Correct
This is the output: output when using memcpy
your L and L_original are 2D matrices, made of an array of pointers to separately allocated 1D vectors. These memory addresses may not be in a contiguous memory space. So you can't use a single memcpy to copy all subvectors.
you will have to use a for loop to apply memcpy between each L[i] and L_original[i].
also, your sizeof() operator is used incorrectly. what you need to copy is the byte length of the data (of the 1D subvector), not the length of the pointer. You need something like
for(int i=0; i<nU; i++)
memcpy(L[i],L_original[i], sizeof(double)*nF);
I read in C++ book, that
"Even though C++ enables us to model multidimensional arrays, the memory where the array is contained is one-dimensional. So the compiler maps the multidimensional array into the memory space, which expands only one direction."
And I thought, if I want to change n-dimension Array to 1-dimension Array(in order of Ascending) why just I call n-d array memory address(which is stored in 1-d format) and just put into new 1-d Array??
(usually I used for statement to change n-d array into 1-d array)
Is it possible?? and if it possible it would be thankful to provide simple example code.
A pointer to the first item in the array is also a pointer to the complete array considered as a one-dimensional array. The guarantee that the items are stored contiguously in memory comes from the sizeof requirements, that the size of an array of n items is n times the size of the item, also when the item is itself an array.
Yes, it is possible to convert an n-dimensional array to 1-d array.
Let me show by taking an example of 2-d array:
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
b[i * n + j] = a[i][j];
}
}
I am trying to understand this code. The first thing that's confusing to me is that in the second line of code I believe they are creating an array of pointers and the plan is that those pointers are going to point to arrays.
I know that the computer doesn't care but to me, it's most logical to have the array of pointers be horizontal and then each array can drop down from the points on that horizontal line.
So, is it reasonable to have "dynamicArray = new int *[COLUMNS];" instead?
int **dynamicArray = 0;
//memory allocated for elements of rows.
dynamicArray = new int *[ROWS] ;
//memory allocated for elements of each column.
for( int i = 0 ; i < ROWS ; i++ )
dynamicArray[i] = new int[COLUMNS];
//free the allocated memory
for( int i = 0 ; i < ROWS ; i++ )
delete [] dynamicArray[i] ;
delete [] dynamicArray ;
EDIT: I thought about this more and the thing that I am getting tripped up on a lot is that I think about the rows and columns in the wrong way.
dynamicArray = new int *[ROWS];
I understand this to be an array of pointers and each pointer is pointing to a column. The number of elements in each column is equal to the number of rows (columns have one vertical element for each row in our 2D array).
Am I understanding this right?
I also get tripped up a lot when I need to use nested for loops to initialize a 2 D array.
Rows/columns are symmetric/interchangeable, and as you say, "the computer doesn't care". Having said that, why do you think "it's most logical to have the array of pointers be horizontal and then each array can drop down from the points on that horizontal line"?
I would think the other way. I would find it much easier to "visualize" rows of horizontal objects (after all, we write horizontally (say, an array of chars), and the lines/rows go top to bottom (say, an array of arrays)). I think the code is more natural (to me) than what you suggest.
The point is, we all think differently, and at the end of the day, ROWS/COLUMNS are just variables, which could have been easily written as X/Y or V/H or W/H or whatever.
How do you fill with 0 a dynamic matrix, in C++? I mean, without:
for(int i=0;i<n;i++)for(int j=0;j<n;j++)a[i][j]=0;
I need it in O(n), not O(n*m) or O(n^2).
Thanks.
For the specific case where your array is going to to be large and sparse and you want to zero it at allocation time then you can get some benefit from using calloc - on most platforms this will result in lazy allocation with zero pages, e.g.
int **a = malloc(n * sizeof(a[0]); // allocate row pointers
int *b = calloc(n * n, sizeof(b[0]); // allocate n x n array (zeroed)
a[0] = b; // initialise row pointers
for (int i = 1; i < n; ++i)
{
a[i] = a[i - 1] + n;
}
Note that this is, of course, premature optimisation. It is also C-style coding rather than C++. You should only use this optimisation if you have established that performance is a bottleneck in your application and there is no better solution.
From your code:
for(int i=0;i<n;i++)for(int j=0;j<n;j++)a[i][j]=0;
I assume, that your matrix is two dimensional array declared as either
int matrix[a][b];
or
int** matrix;
In first case, change this for loop to a single call to memset():
memset(matrix, 0, sizeof(int) * a * b);
In second case, you will to do it this way:
for(int n = 0; n < a; ++n)
memset(matrix[n], 0, sizeof(int) * b);
On most platforms, a call to memset() will be replaced with proper compiler intrinsic.
every nested loop is not considered as O(n2)
the following code is a O(n),
No 1
for(int i=0;i<n;i++)for(int j=0;j<n;j++)a[i][j]=0;
imagine that you had all of the cells in matrix a copied into a one dimentional flat array and set zero for all of its elements by just one loop, what would be the order then? ofcouse you will say thats a O(n)
No 2 for(int i=0;i<n*m;i++) b[i]=0;
Now lets compare them, No 2 with No 1, ask the following questions from yourselves :
Does this code traverse matrix a cells more than once?
If I can measure the time will there be a difference?
Both answers are NO.
Both codes are O(n), A multi-tier nested loop on a multi-dimentional array produces a O(n) order.