Reputation: 1488
I would like to write the (row-major ordered) data into a row of an Eigen::Matrix
. I found a way, but to me it looks inefficient. Is there a faster/more concise way?
// 24 x 16 D Matrix
Eigen::Matrix<double, JOINT_NUM, 16> Mat;
// 4 x 4 D Matrix, stored in row major order to paste data correctly
Eigen::Matrix<double, 4, 4, Eigen::RowMajor> row0_rowMajor = row0;
// copy data from row major Matrix into first row of Mat
Mat.row(0) = Eigen::Map<Eigen::RowVectorXd>(row0_rowMajor.data(), row0_rowMajor.size());
Thanks!
Edit:
Here is a minimal working example, you can compile it with g++ -I/usr/include/eigen3 file.cpp
and run with ./a.out
:
#include <Eigen/Core>
#include <iostream>
int main(int argc, const char* argv[]) {
// 24 x 16 D Matrix
Eigen::Matrix<double, 2, 16> Mat_rowMajor;
Eigen::Matrix<double, 2, 16> Mat;
Mat.setZero();
Mat_rowMajor.setZero();
Eigen::Matrix4d row0;
row0 << 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
// 4 x 4 D Matrix, stored in row major order to paste data correctly
Eigen::Matrix<double, 4, 4, Eigen::RowMajor> row0_rowMajor = row0;
// copy data from row major Matrix into first row of Mat
Mat.row(0) = Eigen::Map<Eigen::RowVectorXd>(row0.data(), row0.size());
Mat_rowMajor.row(0) = Eigen::Map<Eigen::RowVectorXd>(row0_rowMajor.data(), row0_rowMajor.size());
std::cout << "row0:\n" << row0 << std::endl;
std::cout << "Matrix:\n" << Mat << std::endl;
std::cout << "Matrix Row-Major:\n" << Mat_rowMajor << std::endl;
return 1;
}
My aim is to get rid of the copying into the Eigen::Matrix<double, 4, 4, Eigen::RowMajor>
, and work directly with row0
, and remove the Eigen::Map...
by just a simple copy if possible. It just makes the code much more readable, concise, and less prone to errors. Also, the copying is slow for larger matrices, which I'd like to avoid.
Upvotes: 0
Views: 1908
Reputation: 18807
With Eigen 3.4 you can simply use the reshaped<>()
mechanism:
Mat.row(0) = row0.reshaped<Eigen::RowMajor>();
Prior to Eigen 3.4, you can manually create a map (onto the data of Mat.row(0)
), but you need to manually calculate some strides. E.g., if Mat
is a column-major matrix, the index difference between two columns would be Mat.rows()
(which would correspond to the "outer stride"), the difference between two rows would be 4*Mat.rows()
(corresponding to the "inner stride"):
Eigen::Matrix4d::Map(Mat.row(0).data(), // address of first element
Eigen::Stride<Eigen::Dynamic,Eigen::Dynamic> // stride object
(Mat.rows(), // column-stride/"outer stride"
4*Mat.rows()) // row-stride/"inner stride"
) = row0; // end of `Map()` and assignment of a 4x4 matrix `row0`
Alternatively, you could create a Map
from a row-major 4x4 matrix, which would switch the meaning of inner and outer stride.
Overall, if you intend to store matrices in rows of Mat
you should also consider making Mat
itself row-major. In that case, each row of Mat
would be stored in 16 consecutive bytes making the Map
easier to create (and having memory locality is often advantageous anyway).
Upvotes: 1
Reputation: 13295
Eigen doesn't come with a vector-like view of a matrix, as far as I know. So the approach of using a Map is already pretty good. However, it is also very brittle.
Since your ultimate goal is to store into a row of a column-major matrix, vectorization is out of the question. That's why I don't think you can improve performance by doing something fancy. So you can go for something simple instead. Like this:
Eigen::Matrix<double, JOINT_NUM, 16> Mat;
const Eigen::Matrix4d row0 = ...;
auto out_row = Mat.row(0);
for(Eigen::Index i = 0; i < row0.rows(); ++i)
out_row.segment(i * row0.cols(), row0.cols()) = row0.row(i);
At least this makes it clear what is going on.
Side note: The reason why Eigen doesn't have a convenient view is likely that this keeps you stuck between a rock and a hard place when you want to support the general case:
Practically all methods should work on both block expressions and full matrices. In a block expression, the Map approach doesn't work because there is a gap between consecutive columns (in a column-major matrix).
So instead you would need a custom view type to translate indices. However, now you are translating from a 1D index to a 2D index, which requires a costly division on every access.
Other linear algebra packages like Numpy have the same issue. However, Numpy for example is more liberal in its memory allocations and would create a copy if it needs to. The only Eigen type that does copies if required, is Eigen::Ref and that comes with its own set of problems.
Upvotes: 1