Eigen Boolean Array Slicing

Eigen boolean array slicing

As pointed out in the answer to an similar question here: Submatrices and indices using Eigen, libigl adds this functionality to Eigen.

igl::slice(A,indices,B);

Is equivalent to

B = A(indices)

Eigen3 select rows out based on column conditions

The selection of the relevant rows can be done in a single line, by storing the result of the comparison of all the elements in the last column into a boolean array, which can be cast into a VectorXi.

VectorXi is_selected = (mat.col(last_col).array() > 0.3).cast<int>();

This information can then be used to prepare a new matrix which contains only the selected rows. An entire code using this method is shown below.

#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;

int main() {
const int nr = 10;
const int nc = 5;
MatrixXd mat = MatrixXd::Random(nr,nc);
std::cout << "original:\n" << mat << std::endl;
int last_col = mat.cols() - 1;

VectorXi is_selected = (mat.col(last_col).array() > 0.3).cast<int>();

MatrixXd mat_sel(is_selected.sum(), mat.cols());
int rownew = 0;
for (int i = 0; i < mat.rows(); ++i) {
if (is_selected[i]) {
mat_sel.row(rownew) = mat.row(i);
rownew++;
}
}
std::cout << "selected:\n" << mat_sel << std::endl;
}

Demo: https://godbolt.org/z/f0_fC0

Edit: Using new feature (Eigen 3.4 or 3.3.90 development branch)

The development branch of Eigen provides a new overload of the MatrixX constructor that allows for the direct subsetting of a given matrix.

MatrixXd mat_sel = mat(keep_rows, keep_cols); 

The columns and rows that should be kept are stored in an Eigen::VectorXi or in a std::vector<int>:

#include <Eigen/Dense>
#include <iostream>
#include <vector>
using namespace Eigen;

int main() {
MatrixXd mat = MatrixXd::Random(10,5);
std::cout << "original:\n" << mat << std::endl;
std::vector<int> keep_rows;
for (int i = 0; i < mat.rows(); ++i) {
if (mat(i,mat.cols() - 1) > 0.3) {
keep_rows.push_back(i);
}
}
VectorXi keep_cols = VectorXi::LinSpaced(mat.cols(), 0, mat.cols());
MatrixXd mat_sel = mat(keep_rows, keep_cols);
std::cout << "selected:\n" << mat_sel << std::endl;
}

Demo: https://godbolt.org/z/Ag7g7f

Is there a better way to implement matlab's Logical Indexing using Eigen/C++?

This is an old one but....Eigen 3.4 makes it way cleaner to do this. Sadly I can't speak to the performance. I'm mainly interested readability. I made this:

class logical
{
private:
const Index new_size;
Array<Index, Dynamic, 1> old_inds;

public:
logical(const Array<bool, Dynamic, 1> &keep) : new_size(keep.count()), old_inds(new_size)
{
for (Index i = 0, j = 0; i < keep.size(); i++)
if (keep(i))
old_inds(j++) = i;
}
Index size() const { return new_size; }
Index operator[](Index new_ind) const { return old_inds(new_ind); }
};

Which is used like:

logical inds(ind_to_keep);
Y_slice = Y(inds); // vector
H_slice = H(inds, all); // remove some rows
R_slice = R(inds, inds); // remove the same rows as columns

Eigen help is at the bottom of this page:
https://eigen.tuxfamily.org/dox-devel/group__TutorialSlicingIndexing.html

Eigen: select function on complex matrix

As in the example you linked to, you need to compare the .array() (.real()?) to > 1e-8 and use Eigens functions (or unaryExpr) to manipulate the values of the matrix:

v = (v.array().real() 
// ^^^
// can't compare complex numbers

> 1e-8)
// ^^^
// Actually compare the number
.select(v.cwiseSqrt().cwiseInverse(), v);
// ^^^
// Use Eigens functions or alternatively unaryExpr

// In one line:
v = (v.array().real() > 1e-8).select(v.cwiseSqrt().cwiseInverse(), v);

Submatrices and indices using Eigen

There currently is a feature request for selecting sub-matrices by indexing filed at the Eigen BugTracker system. Therefore, I doubt it will be possible that way.

The only workaround I could think of is to copy the data manually. Not very nice though.



Related Topics



Leave a reply



Submit