Eigen how to concatenate matrix along a specific dimension?
Asked Answered
H

3

53

I have two eigen matrices and I would like to concatenate them, like in matlab cat(0, A, B)

Is there anything equivalent in eigen?

Thanks.

Hottempered answered 1/2, 2014 at 9:6 Comment(1)
That matlab code does not work.Gensmer
R
81

You can use the comma initializer syntax for that.

Horizontally:

MatrixXd C(A.rows(), A.cols()+B.cols());
C << A, B;

Vertically:

// eigen uses provided dimensions in declaration to determine
// concatenation direction
MatrixXd D(A.rows()+B.rows(), A.cols()); // <-- D(A.rows() + B.rows(), ...)
D << A, B; // <-- syntax is the same for vertical and horizontal concatenation

For readability, one might format vertical concatenations with whitespace:

D << A,
     B; // <-- But this is for readability only. 
Rutan answered 1/2, 2014 at 9:22 Comment(6)
How does Eigen figure out whether to concatenate the matrices vertically or horizontally? Is it based on the size of the output matrix?Dispenser
yes, you guessed right. (It's not based on the code formatting!)Rutan
Not yet for sparse matrices.Rutan
@Rutan I don't think this "guessing" is very intuitive. It's not very explicit and it also requires quite a lot of "trust" that it really does "the right thing". Wouldn't it be better to handle this more explicitly? (It could be like numpy's concatenate/hstack/vstack or with the comma-initializer, I don't mind, though the numpy-way is used in lots of matrix libraries).Eudy
@Eudy And in the case where A.rows() == A.cols()+B.cols() (i.e. where the matrices could be stacked horizontally or vertically if allowing transposing) then the matrices will not be transposed. So stacking 3 Vector3d will stack them vertically because vectors are single-column matrices in Eigen. Stacking a square number of square matrices is done in the same order as elements are inserted in a matrix with the operator << i.e. top to bottom, left to right.Attenborough
There is no implicit transposition in comma initializer and if the sizes do not match, or if there is not enough to too many elements, then it triggers an assert. hstack/vstack covers slightly different usages than the comma initializer and I agree this would be a welcome feature. IIRC there is some proof-of-concept code hanging somewhere....Rutan
F
8

I'd use Eigen's block indexing in a way similar to this post (which concatenates to an existing matrix).

The block indexing avoids the direction ambiguity in the accepted approach, and is pretty compact syntax. The following is equivalent to C = cat(2, A, B) in MATLAB:

MatrixXd C(A.rows(), A.cols()+B.cols());
C.leftCols(A.cols()) = A;
C.rightCols(B.cols()) = B;
Frigg answered 31/1, 2019 at 18:33 Comment(0)
I
7

I had a slightly different use case: To vertically stack a std::vector of Eigen matrices. Here is how I implemented a function which is more general purpose. Let me know if this can be further improved:

// matrix_eig = Eigen::MatrixXf in RowMajor format
matrix_eig VStack(const std::vector<matrix_eig> &mat_vec) {
  assert(!mat_vec.empty());
  long num_cols = mat_vec[0].cols();
  size_t num_rows = 0;
  for (size_t mat_idx = 0; mat_idx < mat_vec.size(); ++mat_idx) {
    assert(mat_vec[mat_idx].cols() == num_cols);
    num_rows += mat_vec[mat_idx].rows();
  }
  matrix_eig vstacked_mat(num_rows, num_cols);
  size_t row_offset = 0;
  for (size_t mat_idx = 0; mat_idx < mat_vec.size(); ++mat_idx) {
    long cur_rows = mat_vec[mat_idx].rows();
    vstacked_mat.middleRows(row_offset, cur_rows) = mat_vec[mat_idx];
    row_offset +=  cur_rows;
  }
  return vstacked_mat;
}
Inexpert answered 20/6, 2018 at 18:37 Comment(2)
thanks for this dynamic solution in the way that the number of matrices is not known in advance. However, beware of stl containers (i.e. vectors) and eigen eigen.tuxfamily.org/dox/group__TopicStlContainers.htmlMayemayeda
good, thanks for the solution. This can be a feature request!Bittern

© 2022 - 2024 — McMap. All rights reserved.