How to remove a certain row or column while using Eigen Library c++
Asked Answered
E

7

15

I am using Eigen library for my project. I am searching how to remove a certain row or column from the given matrix in Eigen. I am not successful.

MatrixXd A = X1 X2 X3 X4
             Y1 Y2 Y3 Y4
             Z1 Z2 Z3 Z4
             A1 A2 A3 A4
MatrixXd Atransform = X1 X2 X4
                      Y1 Y2 Y4
                      Z1 Z2 Z4
                      A1 A2 A4
enter code here

other than iterating through whole matrix or by using block operations on matrix A . Is there a method to do it simply.

Endorsement answered 8/11, 2012 at 13:58 Comment(1)
I don't think there is a method other than using the block operations.Currier
D
20

Using the block functions is a bit cleaner:

void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
{
    unsigned int numRows = matrix.rows()-1;
    unsigned int numCols = matrix.cols();

    if( rowToRemove < numRows )
        matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.block(rowToRemove+1,0,numRows-rowToRemove,numCols);

    matrix.conservativeResize(numRows,numCols);
}

void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
{
    unsigned int numRows = matrix.rows();
    unsigned int numCols = matrix.cols()-1;

    if( colToRemove < numCols )
        matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.block(0,colToRemove+1,numRows,numCols-colToRemove);

    matrix.conservativeResize(numRows,numCols);
}
Desquamate answered 11/1, 2014 at 21:19 Comment(3)
This should generally work, but it is not guaranteed that Eigen will copy blocks from left to right (or top to bottom), thus you could theoretically get aliasing problems.Soprano
@chtz: to avoid this problem use the .eval() function.Gilolo
I'm not sure it is part of the official documentation or an implementation details, but I'm quite sure I have already see this edge-case use somewhere in Eigen itself to avoid copies, so it is very likely to stay like this in the future.Winzler
C
5

You can do it a lot easier and shorter by using Eigen 3.3.0+(released 2016.08):

vector<int> indicesToKeep = vector<int>{ 1, 2, 3 };
VectorXi indicesToKeepVector = VectorXi(indicesToKeep.data(), indicesToKeep.size());
MatrixXf matrix = MatrixXf(); // your data should be here!
matrix = matrix(Eigen::placeholders::all, indicesToKeepVector); // select columns you want to keep(indicesToKeep), discard others
matrix = matrix(indicesToKeepVector, Eigen::placeholders::all); // select rows you want to keep(indicesToKeep), discard others
matrix = matrix(Eigen::seq(5, 10), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seq(5, 10)); // keep columns from 5 to 10
matrix = matrix(Eigen::seqN(5, 5), Eigen::placeholders::all); // keep rows from 5 to 10
matrix = matrix(Eigen::placeholders::all, Eigen::seqN(5, 5)); // keep columns from 5 to 10
Carcassonne answered 17/1, 2019 at 10:21 Comment(0)
W
3

To improve Andrew's answer, use bottomRows/rightCols.

void removeRow(Eigen::MatrixXd& matrix, unsigned int rowToRemove)
{
    unsigned int numRows = matrix.rows()-1;
    unsigned int numCols = matrix.cols();

    if( rowToRemove < numRows )
        matrix.block(rowToRemove,0,numRows-rowToRemove,numCols) = matrix.bottomRows(numRows-rowToRemove);

    matrix.conservativeResize(numRows,numCols);
}

void removeColumn(Eigen::MatrixXd& matrix, unsigned int colToRemove)
{
    unsigned int numRows = matrix.rows();
    unsigned int numCols = matrix.cols()-1;

    if( colToRemove < numCols )
        matrix.block(0,colToRemove,numRows,numCols-colToRemove) = matrix.rightCols(numCols-colToRemove);

    matrix.conservativeResize(numRows,numCols);
}
Whosoever answered 19/9, 2017 at 14:39 Comment(0)
C
2

You may find the following static version better for certain uses (and more in-line with the spirit of Eigen's compile-time efficiency). In this case, you will be creating a new matrix without the row. A similar function can be constructed for columns using .leftCols() .rightCols()

template<typename T>
inline constexpr auto removeRow(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& matrix, const int& rowNum)
{
    return (Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>(matrix.rows() - 1, matrix.cols())
        << static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.topRows(rowNum - 1)),
        static_cast<Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>>(matrix.bottomRows(matrix.rows() - rowNum))).finished();
}

Enjoy!

Conjure answered 23/11, 2017 at 16:5 Comment(0)
M
0

I know it is an old question but it seems that Eigen now support creating a submatrix defined by the rows and columns indexed: http://eigen.tuxfamily.org/bz/show_bug.cgi?id=329 http://eigen.tuxfamily.org/dox-devel/classEigen_1_1DenseBase.html#a0b44220621cd59a75cd0f48cc499518f

It is just not in the documentation it seems...

Morita answered 5/4, 2018 at 15:46 Comment(0)
U
0
  inline Eigen::MatrixXd removeMatrixRow(const Eigen::MatrixXd original_matrix, const int row_to_remove)
  {
    // New matrix has one fewer rows
    Eigen::MatrixXd new_matrix(original_matrix.rows()-1, original_matrix.cols());
    // Track rows in new matrix. Skip one at row_to_remove.
    int row_to_fill = 0;
    for (int orig_matrix_row = 0; orig_matrix_row < original_matrix.rows(); ++orig_matrix_row)
    {
      if (orig_matrix_row != row_to_remove)
      {
        new_matrix.row(row_to_fill) = original_matrix.row(orig_matrix_row);
        ++row_to_fill;
      }
    }
    return new_matrix;
  }
Unconventional answered 22/1, 2020 at 17:1 Comment(1)
From Review: Hi, please don't answer just with source code. Try to provide a nice description about how your solution works. See: How do I write a good answer?. ThanksGymnastics
T
-2

I'm very new in c++ but this code works in may application.

It works only for full dynamic matrixs but can adapt it.

If anyone has a better way please show me i really want to learn.

template<typename ScalarType>
void MatrixXdRemoveCol(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int colindex)
{
    Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;

    *auxmat = *mat;

    mat->resize(mat->rows(),mat->cols()-1);

    int rightColsSize = auxmat->cols()-colindex-1;

    mat->leftCols(colindex) = auxmat->leftCols(colindex);
    mat->rightCols(rightColsSize) = auxmat->rightCols(rightColsSize);
}

template<typename ScalarType>
void MatrixXdRemoveCols(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, std::vector<int>* cols)
{
    for(auto iter = cols->rbegin();iter != cols->rend();iter++)
        MatrixXdRemoveCol<ScalarType>(mat,*iter);
}

template<typename ScalarType>
void MatrixXdRemoveRow(Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *mat, int rowindex)
{
    Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> *auxmat = new Eigen::Matrix<ScalarType,-1,-1,0,-1,-1>;

    *auxmat = *mat;

    mat->resize(mat->rows()-1,mat->cols());

    int BottomRowsSize = auxmat->rows()-rowindex-1;

    mat->topRows(rowindex) = auxmat->topRows(rowindex);
    mat->bottomRows(BottomRowsSize) = auxmat->bottomRows(BottomRowsSize);
}
Thompkins answered 11/1, 2013 at 6:25 Comment(2)
I'm unfamiliar with eigen library, but from general c++ standpoint looks like you have memory leaks in your functions: you allocate auxmats but don't delete them.Firewood
Generally, you should avoid new when writing C++ -- unless you really need to and you know what you are doing. Instead just write Eigen::Matrix<ScalarType,-1,-1,0,-1,-1> auxmat = mat (and pass mat by reference and not by pointer)Soprano

© 2022 - 2024 — McMap. All rights reserved.