Eigen Indices of Dense Matrix meeting Condition

老子叫甜甜 提交于 2021-01-28 08:03:24

问题


I'm looking to get the row/column indices from a dense matrix which meet a condition. In my case the result is likely to be very sparse. For example, with matrix

1 5 2
7 6 3
2 3 8

I'd like to get the indicies where the coeff is greater than 4, or

(0,1), (1,0), (1,1), (2,2)

My initial thoughts include using either select or coefficientwise operations to build a bool/int matrix

0 1 0
1 1 0
0 0 1

and then convert it to a sparse matrix

(0,1,1), (1,0,1), (1,1,1), (2,2,1)

then remove the coeff values

(0,1), (1,0), (1,1), (2,2)

However, that requires two passes over matrices the size of the original matrix, which may be very large.

Alternatively a naive double loop over the original matrix akin to pseudocode

for (int i; i < mat.cols(); i++) {
    for (int j; j < mat.rows(); j++) {
        if(cond(mat(j, i))) {
            add_index(i, j, index_list)
        }
    }
}

but that only takes the compilers optimizations and none of Eigen's optimizations/vectorizations.

Is there a more efficient way that I am missing? In my case the conditions are simple comparisons.

Thanks for any help


回答1:


There is not much to vectorize here, but to avoid writing the two loops (which might better be reversed for a row-major storage), the best tool would be a visitor:

mat.visit(some_visitor);

Sadly, the visitor cannot be a simple lambda as visit calls the method init(val,0,0) for the first element. This is useful for reduction-like visitors but not always. In order to make visit accepts a simple lambda, you can use the following helper:

template<typename Func>
struct lambda_as_visitor_wrapper : Func {
    lambda_as_visitor_wrapper(const Func& f) : Func(f) {}
    template<typename S,typename I>
    void init(const S& v, I i, I j) { return Func::operator()(v,i,j); }
};

template<typename Mat, typename Func>
void visit_lambda(const Mat& m, const Func& f)
{
    lambda_as_visitor_wrapper<Func> visitor(f);
    m.visit(visitor);
}

In your case, you can then write:

int main() {
    int n = 5;
    double th = 0.5;
    Eigen::MatrixXd M = Eigen::MatrixXd::Random(n,n);

    std::vector<std::pair<int,int>> indices;
    visit_lambda(M,
        [&indices,th](double v, int i, int j) {
            if(v>th)
                indices.push_back(std::make_pair(i,j));
        });


    std::cout << M << "\n\n";

    for(auto p:indices)
        std::cout << '(' << p.first << ',' << p.second << ") ";
    std::cout << '\n';

    return 0;
}


来源:https://stackoverflow.com/questions/50027494/eigen-indices-of-dense-matrix-meeting-condition

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!