Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does eigen raw buffer change even when reference is passed to a function

Tags:

c++

matrix

eigen

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
like image 361
doody1986 Avatar asked Dec 14 '25 07:12

doody1986


1 Answers

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.

like image 200
ggael Avatar answered Dec 15 '25 21:12

ggael



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!