optimize 2D array in C++ - c++

I'm dealing with a 2D array with the following characteristics:
const int cols = 500;
const int rows = 100;
int arr[rows][cols];
I access array arr in the following manner to do some work:
for(int k = 0; k < T; ++k) { // for each trainee
myscore[k] = 0;
for(int i = 0; i < cols; ++i) { // for each sample
for(int j = 0; j < rows; ++j) { // for each expert
myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
}
}
}
So I am worried about the array 'arr' and not the other one. I need to make this more cache-friendly and also boost the speed. I was thinking perhaps transposing the array but I wasn't sure how to do that. My implementation turns out to only work for square matrices. How would I make it work for non-square matrices?
Also, would mapping the 2D array into a 1D array boost the performance? If so, how would I do that? Finally, any other advice on how else I can optimize this... I've run out of ideas, but I know that arr[j][i] is the place where I need to make changes because I'm accessing columns by columns instead of rows by rows so that is not cache friendly at all.
Thanks,
Hristo

A general in-place matrix transposition is very difficult, but if you're okay with transposing it to another array, then it's pretty simple.
const int cols = 500;
const int rows = 100;
int arr[rows][cols];
// fill arr[][]
int arrT[cols][rows];
for (int r = 0; r < rows; r++) {
for (int c = 0; c < cols; c++) {
arrT[c][r] = arr[r][c];
}
}
Of course, depending on how you're getting arr[][], you can just fill arrT[][] directly instead.
However, there may be a simpler solution of simple swapping the order of the loops.
for(int k = 0; k < T; ++k) { // for each trainee
myscore[k] = 0;
for(int j = 0; j < rows; ++j) { // for each expert
for(int i = 0; i < cols; ++i) { // for each sample
myscore[k] += delta(i, anotherArray[k][i], arr[j][i]);
}
}
}

Yes, 1d should be faster than 2d. C and C++ arrays are always 1d (internally).
When you call something like
array[row][col]
the compiler actually calculates
col + row * maxcols
and uses that as the actual index of a 1d array. You might as well do that yourself. Cycling through an entire array will be way faster, and random access will be equally fast as in a 2d array.

for(int i = 0; i < N; ++i) { // for each sample
for(int j = 0; j < E[i]; ++j) { // for each expert
... arr[j][i] ... // each ++j causes a large stride => poor caching
}
}
transpose the loops:
for(int j = 0; j < E[i]; ++j) { // for each expert
for(int i = 0; i < N; ++i) { // for each sample
... arr[j][i] ... // each ++i looks to the next word in memory => good
}
}
Of course, without seeing everything else in the program, I can't say if that would cause a problem. If delta doesn't have side effects, you should be fine.

You want memory accesses to be adjacent. In your case simply swap I and j when accessing arr.

Related

How to initialize a character or string array using for loop in c++?

I want to make a 2 dimensional array of 13 rows and 6 columns all initialized with character X. to do so I'm doing this.
char myseats[13][5];
for (int i; i < 13; i++)
{
myseats[i] = { 'X' };
for (int j; j < 5; j++)
{
myseats[j] = {'X'};
}
}
}
however this gives me a error and the array wont initialize with X, same is the case with string. How can I achieve my purpose can anyone please help me?
If you want to access fields of two dimensional array, you should use myseats[i][j] (first you specify row, then the column). Also, your for loops are written incorrectly. When you initialize any variable in the body of for loop, you should assign its value (otherwise i and j can have any value that can be saved in int). Your code should look like that:
char myseats[13][5];
for (int i = 0; i < 13; i++)
{
for (int j = 0; j < 5; j++)
{
myseats[i][j] = {'X'};
}
}
Try this:
char myseats[13][5];
for (int i = 0; i < 13; i++)
{
for (int j = 0; j < 5; j++)
{
myseats[i][j] = 'X';
}
}
First, the i and j where not initialized in the loop. You need to define at what index you want them to start.
Second, the correct way to access a two dimensional array is with the syntax array[row_index][column_index] = 'your_desired_value_here'.

Writing a function that adds two matrices

void add_matrices(int matrix_1 [m][n], int matrix_2 [m][n], int matrix_3 [m][n], int num_rows, int num_cols)
{
for (int i = 0; i < num_rows; i++)
{
for (int j = 0; i < num_cols; j++)
{
matrix_3[i][j] = matrix_1[i][j] + matrix_2[i][j];
}
}
} // end of function that adds two matrices
I'm trying to write a function that adds two matrices (2-D arrays). Here is the snippet of code from my program where I define the function. I can post the rest of my code but figured it might be easier to look at.
When I run the code it says "Thread 1: EXC_BAD_ACCESS" on the line that starts with matrix_3. I think the issue lies in the parameters I'm passing to the function. Matrices 1 and 2 are filled in the main and matrix 3 is created in the main but empty.
for (int j = 0; i < num_cols; j++)
This should be:
for (int j = 0; j < num_cols; j++)

Copying values of 2D array into another

I have a 2D array that I want to assign the values of another array. I'm making a game of life simulator and have everything else working but this. My code is this:
for(int i = 0; i < ROWS; i++) {
for (int j = 0; i < COLS; j++) {
current[i][j] = next[i][j];
}
}
current and next are both bool's. I keep getting the error code EXC_BAD_ACCESS in X-Code. I'm unsure what I'm doing wrong
To re-iterate my comment, the innerloop compares i with COL rather than j. So
for(int i = 0; i < ROWS; i++) {
for (int j = 0; j < COLS; j++) {
current[i][j] = next[i][j];
}
}
should solve the issue

Multiplying Matrices using 2d Vectors in C++

I'm trying to design a program that creates a matrix using vectors of vectors of integers, and then multiplyies it with another matrix. I know how to multiply matrices on paper, but when I try to implement it in my program, I'm not getting it to work. I know that both matrices are entered correctly and are passed correctly as I have the the output of those functions so that I can debug. The program works incorrectly when I try to multiply them. The answer and the number of elements are not right. I know I'm missing something but can't figure out what.
Matrix Matrix::operator*(Matrix m){
vector<int> mRow = m.getRow(0);
vector<int> mCol = m.getCol(0);
vector<int> newElem;
int product = 0;
//adds the contents of the 2nd matrix to the 2d vector
vector< vector<int> > m2(mRow.size(), vector<int>(mCol.size()));
for (int i = 0; i < mRow.size(); i++){
mRow.clear();
mRow = m.getRow(i);
for (int j = 0; j < mCol.size(); j++){
m2[j][i] = mRow[j];
}
}
//Multiplies the matrices using the 2d matrix**THIS IS WHERE IT GOES WRONG**
for (int i = 0; i < row; i++){
for (int j = 0; j < column; j++){
product += matrix[i][j]*m2[j][i];
}
newElem.insert(newElem.begin()+i,product);
product = 0;
}
//displays the products so that i can see if its working
for (int i = 0; i < newElem.size(); i++){
cout << " "<<newElem[i]<<endl;
}
//adds the new product vector to a new Matrix object and returns it
Matrix newM(row, mCol.size());
vector<int> temp;
for (int i = 0; i < row; i++){
for (int j = 0; j < mCol.size(); j++){
temp.insert(temp.begin()+j, newElem[0]);
newElem.erase(newElem.begin());
}
newM.setRow(temp,i);
temp.clear();
}
return newM;
}
Although I don't know whether this helps, I'm using this site as a reference for multiplying 2 matrices together.
Your matrix representation has nothing to do with your mistake. You need to have more nested iterations. Think of a result matrix and iterate through that to calculate it's every element. In a pseudocode:
for i in result column
for j in result row
res[i, j] = multiply(m1, m2, i, j)
where multiply function is the nested loop, something like this:
multiply(m1, m2, i, j)
{
val = 0;
for k in row
val += m1[i, k] * m2[k, j]
return val
}
Here is an implementation of the outer loops. Mind you, there are no error checking in the code.
vector<vector<int> > ml;
vector<vector<int> > mr;
// fill in ml and mr
...
// result matrix
vector<vector<int> > res;
// allocate the result matrix
res.resize(ml.size());
for( it = res.begin(); it != res.end(); ++it)
it->resize(ml[0].size());
// loop through the result matrix and fill it in
for( int i = 0; i < res.size(); ++i)
for( int j = 0; j < res[0].size(); ++j)
res[i][j] = multiply(ml, mr, i, j);
Leaving a proper implementation of multiply() function to you.

Convert Mat to <vector<vector>> C++

How to convert Mat in 2d vector (vector of vector) in C++?
I tried this, and got error in Mat.at function.
vector<vector<double>> dctm(300, vector<double>(300,0));
for (int i = 0; i < 300; i++) {
for (int j = 0; j < 300; j++) {
dctm[i][j] = img.at<double>(i, j);
}
}
You can fill the vector by iterating over values and pushing them one by one, but in general this is not considered a good practice. Much better solution is to use range functions provided to you by stl. This is true not only for vector but for any other stl structure.
Cleaner (from stl point view) and faster solution should be like this:
for(int i=0; i<300; i++)
{
Mat r = img.row(i);
dctm.push_back(vector<double>(r.begin<unsigned char>(), r.end<unsigned char>()));
}
Much faster way would be
vector<vector<double>> dctm(300, vector<double>(300,0));
for (int i = 0; i < 300; i++) {
uchar *rowPtr = img.ptr<uchar>(i);
for (int j = 0; j < 300; j++) {
dctm[i][j] = *rowPtr[j];
}
}
See How to scan images, lookup tables and time measurement with OpenCV