I have a 2d vector that looks like this:
a b c
d f g // actual size is 32 x 32
h i j
And I want to shift the rows/columns:
d f g h i j b c a c a b
h i j <-- up a b c <-- down f g d <-- left g d f <-- right
a b c d f g i j h j h i
In python I can accomplish all of those in nifty one liners, such as matrix = [row[-1:] + row[:-1] for row in matrix] to move the columns to the right. But, c++ doesn't use the handy : in list indexes or negative indexes. Well, not negative indexes like in python at least.
Anyway, I'm looking for a good way to do this. I've seen lots of other SO questions about swapping rows, or rotating, but none I have seen have solved my problem.
Here's my first take on moving columns to the right:
vector<vector<string>> matrix{{"a","b","c"}, {"d","e","f"}, {"g","h","i"}};
for (int i = 0; i < matrix.size(); i++)
{
vector<string> col{matrix[i][2], matrix[i][0], matrix[i][1]};
matrix[i] = col;
}
This works, but will be very long once I write all 32 indexes. I was hoping someone could point me to something shorter and more flexible. Thanks!
EDIT: For future viewers (taken from G. Sliepen's answer) :
vector<vector<string>> matrix{{"a","b","c"}, {"d","e","f"}, {"g","h","i"}}; // or can be ints
rotate(matrix.begin(), matrix.begin() + 1, matrix.end()); // move rows up
rotate(matrix.begin(), matrix.begin() + matrix.size() - 1, matrix.end()); // move rows down
for (auto &row: matrix) // move columns to the left
{
rotate(row.begin(), row.begin() + 1, row.end());
}
for (auto &row: matrix) // move columns to the right
{
rotate(row.begin(), row.begin() + row.size() - 1, row.end());
}
There is std::rotate() that can do this for you. To rotate the contents of each row:
vector<vector<string>> matrix{{"a","b","c"}, {"d","e","f"}, {"g","h","i"}};
for (auto &row: matrix)
{
std::rotate(row.begin(), row.begin() + 1, row.end());
}
To rotate the contents of the columns, you just rotate the outer vector:
std::rotate(matrix.begin(), matrix.begin() + 1, matrix.end());
Related
I want to create a matrix B from a matrix A, in C++.
First column of A is distance D1, second column is distance D2. Matrix B copies the same columns (and rows) of A, except when in A it happens that D2-D1=delta exceeds a threshold. In this case, the row of A is break in two rows in B.
I wrote an algorithm, but the problem is that it gives segmentation fault. Someone can help, why it happens?
std::vector<float> newD1(10), newD2(10);
float box=5.;
int j=0;
for(auto i=0;i<D1.size();i++){
float delta=D2[i]-D1[i];
if (delta>box){ //break row i in two rows: j and j+1
//first half of row i goes in row j
newD1[j]=D1[i];
newD2[j]=(D1[i]+D2[i])/2.;
//second half of row i goes in j+1
D1[j+1]=(D1[i]+D2[i])/2.;
D2[j+1]=D2[i];
j=j+2; //we skip two row because we break up the original row in 2 rows
}
else{
newD1[j]=(D1[i]);
newD2[j]=D2[i];
j=j+1; //we skip one row because the original row is unchanged
}
}
Here I give you an example of matrix A and B; I also specify delta beside each line of the matrix.
Matrix A:
#D1 D2 delta
|0 5 | 5
A= |5 15 | 10 }--> exceed the threshold, delta>5. Must break in 2 rows in `B`
|15 17 | 2
B is created breaking the second line in two lines, because delta>5 :
#D1 D2 delta
|0 5 | 5
B= |5 10 | 5 }--> created from row #2 of `A`. `D2` is midpoint between`D1` and `D2` in row #2 in `A`
|10 15 | 5 }--> created from row #2 of `A`. `D1` is midpoint between`D1` and `D2` in row #2 in `A`
|15 17 | 2
EDIT:
What if I want to recursively break up the rows (e.g. suppose that at row #2 in A, delta>3*box, meaning that I need to break up that row in 3 rows in B). Any suggestions?
1.You can use push_back to avoid the size definition
2.You updated D1 and D2 instead of newD1 and newD2
#include <vector>
#include <iostream>
using namespace std;
int main()
{
std::vector<float> D1 = { 0,5,15 };
std::vector<float> D2 = { 5,15,17 };
std::vector<float> newD1, newD2;
float box = 5.;
for (auto i = 0; i < D1.size(); i++) {
float delta = D2[i] - D1[i];
if (delta > box) { //break row i in two rows: j and j+1
//first half of row i goes in row j
newD1.push_back(D1[i]);
newD2.push_back((D1[i] + D2[i]) / 2.);
//second half of row i goes in j+1
newD1.push_back ((D1[i] + D2[i]) / 2.);
newD2.push_back (D2[i]);
}
else {
newD1.push_back(D1[i]);
newD2.push_back(D2[i]);
}
}
}
My code works but I'm just curious to see if someone knows how to do this but properly using Armadillo library.
Thanks for your time :)
arma::mat W = arma::mat(4, 4, arma::fill::ones);
arma::mat D = arma::mat(4, 4, arma::fill::zeros);
for (size_t i = 0; i < W.n_rows; i++)
{
for (size_t j = 0; j < W.n_cols; j++)
{
D(i, i) += W(i, j);
}
}
std::cout<< "W = \n"<< W <<std::endl;
std::cout<< "D = \n"<< D <<std::endl;
It seems you are summing the elements in each row in the W matrix and putting the result in the diagonal of the D matrix. That is, you are summing elements over the "columns" dimension. This is very easy to do in armadillo and does not require any manual loop.
Armadillo has a sum function with a few overloads. One of these overloads receives a second parameter that you can use to specify in which dimension you want to perform the sum. Just specify the second dimension (index 1) and you get the proper result.
However, the result you get from arma::sum(W, 1) will be a vector. It makes sense, since you are summing over one of the dimensions of the matrix. Just pass the result to arma::diagmat and you get the same D matrix as with you original code. Your code can then be replaced by
arma::mat W = arma::mat(4, 4, arma::fill::ones);
arma::mat D = arma::mat(4, 4, arma::fill::zeros);
W.print("W");
arma::diagmat(arma::sum(W, 1)).print("D");
Note: I have used the .print method to print the matrices, in case you don't know about it. It is easier to use than using std::cout;
I'm using Rcpp with Armadillo library. My algorithm has a for-loop where I updates j-th column without j-th element at every step. Therefore, after a cycle, the input matrix will have all off-diagonal elements replaced with new values. To this end, I write Rcpp code like below.
arma::mat submatrix(
arma::mat A,
arma::uvec rowid){
for(int j = 0; j < A.n_rows; j++){
A.submat(rowid, "j") = randu(A.n_rows - 1);
}
return A;
}
However, I'm not sure how the submatrix view will work in the for-loop.
If you replace "j" in the above code with any of below, then this toy example
submatrix(matrix(rnorm(3 * 4), nrow = 3, ncol = 4), c(1:2))
will return an error message.
(uvec) j :
error: Mat::elem(): incompatible matrix dimensions: 2x0 and 2x1
j or (unsigned int) j : no matching member function for call to 'submat'
How could I handle this issue? Any comment would be very appreciated!
I have to confess that you do not fully understand your question -- though I think I get the idea of replace 'all but one' elements of a given row or column.
But your code has a number of problems. The following code is simpliefied (as I replace the full row), but it assigns row by row. You probably want something like this X.submat( first_row, first_col, last_row, last_col ), possibly in two chunks (assign above diagonal, then below). There is a bit more in the Armadillo documentation about indexing, and there is more too at the Rcpp Gallery.
#include <RcppArmadillo.h>
// [[Rcpp::depends(RcppArmadillo)]]
// [[Rcpp::export]]
arma::mat submatrix(arma::mat A, arma::uvec rowid, int k) {
for (arma::uword j = 0; j < A.n_rows; j++) {
A.row(j) = arma::randu(A.n_rows).t();
}
return A;
}
/*** R
M <- matrix(1:16,4,4)
submatrix(M, 1, 1)
*/
I have a vector of size n; n is power of 2. I need to treat this vector as a matrix n = R*C. Then I need to transpose the matrix.
For example, I have vector: [1,2,3,4,5,6,7,8]
I need to find R and C. In this case it would be: 4,2. And treat vector as matrix:
[1,2]
[3,4]
[5,6]
[7,8]
Transpose it to:
[1, 3, 5, 7]
[2, 4, 6, 8]
After transposition vector should be: [1, 3, 5, 7, 2, 4, 6, 8]
Is there existing algorithms to perform in-place non-square matrix transposition? I don't want to reinvent a wheel.
My vector is very big so I don't want to create intermediate matrix. I need an in-place algorithm. Performance is very important.
All modofications should be done in oroginal vector. Ideally algorithm should work with chunks that will fit in CPU cache.
I can't use iterator because of memory locality. So I need real transposition.
It does not matter if matrix would be 2x4 or 4x2
The problem can be divided in two parts. First, find R and C and then, reshape the matrix. Here is something I would try to do:
Since n is a power of 2, i.e. n = 2^k then if k is even, we have: R=C=sqrt(n). And if k is odd, then R = 2^((k+1)/2) and C=2^((k-1)/2).
Note: Since you mentioned you want to avoid using extra memory, I have made some editions to my original answer.
The code to calculate R and C would be something like:
void getRandC(const size_t& n, size_t& R, size_t& C)
{
int k = (int)log2(double(n)),
i, j;
if (k & 1) // k is odd
i = (j = (k + 1) / 2) - 1;
else
i = j = k / 2;
R = (size_t)exp2(i);
C = (size_t)exp2(j);
}
Which needs C++11. For the second part, in case you want to keep the original vector:
void transposeVector(const std::vector<int>& vec, std::vector<int>& mat)
{
size_t R, C;
getRandC(vec.size(), R, C);
// first, reserve the memory
mat.resize(vec.size());
// now, do the transposition directly
for (size_t i = 0; i < R; i++)
{
for (size_t j = 0; j < C; j++)
{
mat[i * C + j] = vec[i + R * j];
}
}
}
And, if you want to modify the original vector and avoid using extra memory, you can write:
void transposeInPlace(std::vector<int>& vec)
{
size_t R, C;
getRandC(vec.size(), R, C);
for (size_t j = 0; R > 1; j += C, R--)
{
for (size_t i = j + R, k = j + 1; i < vec.size(); i += R)
{
vec.insert(vec.begin() + k++, vec[i]);
vec.erase(vec.begin() + i + 1);
}
}
}
See the live example
Since you haven't provided us with any of your code, can I suggest a different approach (that I don't know will work for your particular situation)?
I would use an algorithm based on your matrix to transpose your values into the new matrix yourself. Since performance is an issue this will help even more so since you don't have to create another matrix. If this is applicable for you.
Have a vector
[1, 2, 3, 4, 5, 6, 7, 8]
Create your matrix
[1, 2]
[3, 4]
[5, 6]
[7, 8]
Reorder vector without another matrix
[1, 3, 5, 7, 2, 4, 6, 8]
Overwrite the values in the current matrix (so you don't have to create a new one) and reorder the values based on your current matrix.
Add values in order
R1 and C1 to transposed_vector[0]
R2 and C1 to transposed_vector[1]
R3 and C1 to transposed_vector[2]
R4 and C1 to transposed_vector[3]
R1 and C2 to transposed_vector[4]
And so on.
For non square matrix representation, I think it may be tricky, and not worth the effort to make the transpose of your flat vector without creating another one. Here is a snippet of what I came up with:
chrono::steady_clock::time_point start = chrono::steady_clock::now();
int i, j, p, k;
vector<int> t_matrix(matrix.size());
for(k=0; k< R*C ;++k)
{
i = k/C;
j = k - i*C;
p = j*R + i;
t_matrix[p] = matrix[k];
}
cout << chrono::duration_cast<chrono::milliseconds> chrono::steady_clock::now() - start).count() << endl;
Here, matrix is your flat vector, t_matrix is the "transposed" flat vector, and R and C are, respectively rows and vector you found for your matrix representation.
Ive been recently reading Matrix Tutorials with openGL and stumbled upon an optimized method for Matrix Multiplication that I cannot understand.
//Create an allias type for a Matrix Type
typedef struct Matrix
{
float m[16];
} Matrix;
//default matrix
static const Matrix IDENTITY_MATRIX = { {
1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1
} };
Matrix MultiplyMatrices(const Matrix* m1, const Matrix* m2)
{
Matrix out = IDENTITY_MATRIX;
unsigned int row, column, row_offset;
for (row = 0, row_offset = row * 4; row < 4; ++row, row_offset = row * 4)
for (column = 0; column < 4; ++column)
out.m[row_offset + column] =
(m1->m[row_offset + 0] * m2->m[column + 0]) +
(m1->m[row_offset + 1] * m2->m[column + 4]) +
(m1->m[row_offset + 2] * m2->m[column + 8]) +
(m1->m[row_offset + 3] * m2->m[column + 12]);
return out;
}
These are the questions I have:
In the method MultiplyMatrices why is there a pointer to params m1 and m2? If your just copying their values and returning a new matrix why use a pointer?
Why is the for loop condition identical to its increment?
for (row = 0, row_offset = row * 4; row < 4; ++row, row_offset = row *
4)
The MultiplyMatrices function calculates the product of two matrices. So that's why you need two matrices as the input arguments of this function. Note that the definition of the matrix
typedef struct Matrix
{
float m[16];
} Matrix;
defines a 4 by 4 matrix with a 1-D array. So the offset is 4 for each row. This is just to simulate a 2-D matrix with 1-D array. You need to pass in pointers to two input matrices so that you can get their element values inside the function.
The reason why you see two identical statements in the for loop is:
for (row = 0, row_offset = row * 4; row < 4; ++row, row_offset = row * 4)
Initially the row_offset is set to 0. When the loop is going through each row in the matrix, the row_offset is increasing with row. This is because in the 1-D array representation of 2-D matrix, the a[i][j] element can be written as:
a[i][j] = a[i*num_col+j]
And here num_col is 4. So these two statements are not the same. The first is to initialize. The second is to reset the row_offset when the row index increases by 1.
In the method MultiplyMatrices why is there a pointer to m1 and m2? If your just copying their values why use a pointer?
Maybe I don't understand your question, but how would you propose to do it differently? You're outputting the product into a third memory location out which is the product of m1 and m2. This is the most efficient way..
Why is the for loop condition identical to its increment?
It's not - the ++row increments row before the assignment on each loop. The "condition" is row < 4 which you did not bold - maybe that's the confusion.