I was building a C++ program with capability to interact with python through raw buffer, to be specific, numpy. And I was using eigen library for matrix operations. Then I found this very strange behavior.
As you may know, the ndarray in numpy is row major, so I created a row major matrix map in my C++ program in order to wrap the raw buffer from PyObject of numpy. However, all the functions in my program are using matrices in column major, as a result, those functions are implemented with const reference arguments with type of column major eigen matrix. I noticed that even though I pass the row major matrix map in these kind of functions, the program runs well and the correctness can be guaranteed. Nevertheless, I still want to figure out why this happens
I printed out the data contents inside the raw buffer of both row major matrix map and column major matrix within one function. And I found that the data layout have been changed somehow. So my question is that how does this happen? Is there a memory copy that is responsible for that?
I also wrote a simple C++ program that exactly did what I described above. Anyone can take that as demo of this issue.
#include <Eigen/Dense>
#include <Eigen/Core>
#include <iostream>
using MatMap = Eigen::Map< Eigen::Matrix<int, Eigen::Dynamic,
Eigen::Dynamic, Eigen::RowMajor> >;
using Mat = Eigen::Matrix<int, Eigen::Dynamic,
Eigen::Dynamic, Eigen::ColMajor>;
void Func(const Mat &m, int dim) {
// Print internal raw buffer of m
std::cout << std::endl;
for (int i = 0; i < dim * dim; i++)
std::cout << *(m.data() + i) << std::endl;
std::cout << std::endl;
}
int main() {
int dim = 3;
// Raw buffer
int *raw = new int[dim * dim];
for (int i = 0; i < dim * dim; i++)
raw[i] = i;
// Matrix Map
MatMap mat(nullptr, 0, 0);
// Create
new (&mat) MatMap(raw, dim, dim);
// Print raw buffer of mat
std::cout << std::endl;
for (int i = 0; i < dim * dim; i++)
std::cout << *(mat.data() + i) << std::endl;
std::cout << std::endl;
// Function call
Func(mat, dim);
return 0;
}
The results of above program is like:
0
1
2
3
4
5
6
7
8
0
3
6
1
4
7
2
5
8
This behavior is perfectly expected. When calling void Func(const Mat &m, int dim) with something different than a Mat object for the first argument, then it is copied into a temporary of type Mat. This is possible because the argument is a const reference and there exist an implicit Matrix constructor from any Eigen's expressions. So more precisely, here is what is happening when calling Func(mat, dim);:
Mat tmp(mat);
Func(tmp,dim);
tmp.~Mat();
Both tmp and mat represent the same matrix, but with different storage orders.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With