首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何更有效地获取Eigen3中二进制掩码的索引?

如何更有效地获取Eigen3中二进制掩码的索引?
EN

Stack Overflow用户
提问于 2022-01-31 13:36:09
回答 2查看 399关注 0票数 0

我现在有一个以特征生成的bool掩码矢量。我想使用类似于Python numpy的二进制掩码,根据True值,我得到一个子矩阵或子向量,在那里我可以进一步对它们进行一些计算。

为了在本征中实现这一点,我目前将掩码向量“转换”为包含索引的另一个向量,方法是简单地迭代掩码:

代码语言:javascript
复制
Eigen::Array<bool, Eigen::Dynamic, 1> mask = ... // E.G.: [0, 1, 1, 1, 0, 1];

Eigen::Array<uint32_t, Eigen::Dynamic, 1> mask_idcs(mask.count(), 1);
int z_idx = 0;
for (int z = 0; z < mask.rows(); z++) {
    if (mask(z)) {
        mask_idcs(z_idx++) = z;
     }
}
// do further calculations on vector(mask_idcs)
// E.G.:    vector(mask_idcs)*3 + another_vector

但是,我想进一步优化它,我想知道Eigen3是否为此提供了一个更优雅的解决方案,比如vector(from_bin_mask(mask)),它可能从库优化中受益。

这里已经出现了一些问题,但是似乎没有人回答这个简单的用例(12)。有些人提到了select-function,它返回大小相等的向量/矩阵/数组,但我想通过掩码丢弃元素,只对较小的向量/矩阵/数组进行进一步的工作。

有没有更优雅的方法来做这件事?否则还能进行优化吗?

(我使用的是Eigen::Array-type,因为大多数计算在用例中都是按元素计算的)

EN

回答 2

Stack Overflow用户

发布于 2022-04-23 00:47:04

据我所知,没有使用本征方法的“现成”解决方案。但是,值得注意的是(至少对于大于或等于3.4.0的特征版本),可以使用std::vector<int>进行索引(参见本节)。因此,您编写的代码可以简化为

代码语言:javascript
复制
Eigen::Array<bool, Eigen::Dynamic, 1> mask = ... // E.G.: [0, 1, 1, 1, 0, 1];

std::vector<int> mask_idcs;
for (int z = 0; z < mask.rows(); z++) {
    if (mask(z)) {
        mask_idcs.push_back(z);
    }
}
// do further calculations on vector(mask_idcs)
// E.G.:    vector(mask_idcs)*3 + another_vector

如果使用的是c++20,则可以使用使用std::ranges的替代实现,而无需使用raw for-循环:

代码语言:javascript
复制
int const N = mask.size();
auto c = iota(0, N) | filter([&mask](auto const& i) { return mask[i]; });
auto masked_indices = std::vector(begin(c), end(c));
// ... Use it as vector(masked_indices) ...

我已经在编译器资源管理器中实现了一些最小的示例,以防您想要查看。老实说,我希望有一种更简单的方法从原始范围初始化std::vector,但它目前是不那么简单。因此,我建议您将代码包装到一个助手函数中,例如

代码语言:javascript
复制
auto filtered_indices(auto const& mask) // or as you've suggested from_bin_mask(auto const& mask)
{
    using std::ranges::begin;
    using std::ranges::end;
    using std::views::filter;
    using std::views::iota;

    int const N = mask.size();
    auto c = iota(0, N) | filter([&mask](auto const& i) { return mask[i]; });
    return std::vector(begin(c), end(c));
}

然后用它作为,例如,

代码语言:javascript
复制
Eigen::ArrayXd F(5);
F << 0.0, 1.1548, 0.0, 0.0, 2.333;
auto mask = (F > 1e-15).eval();
auto D = (F(filtered_indices(mask)) + 3).eval();

它不像在numpy中那么干净,但是它是这样的:)

票数 1
EN

Stack Overflow用户

发布于 2022-02-01 09:57:44

我找到了另一种方法,它似乎比比较每个元素(如果它等于0 )更优雅。

代码语言:javascript
复制
Eigen::SparseMatrix<bool> mask_sparse = mask.matrix().sparseView();
for (uint32_t k = 0; k<mask.outerSize(); ++k) {
    for (Eigen::SparseMatrix<bool>::InnerIterator it(mask_sparse, k); it; ++it) {
        std::cout << it.row() << std::endl;   // row index
        std::cout << it.col() << std::endl;   // col index
        // Do Stuff or built up an array
        }
    }

在这里,我们至少可以建立一个向量(或多个向量,如果我们有更多的维数),然后使用它“掩蔽”一个向量或矩阵。(这是取自文档的)。

因此,对于这个特定的应用程序,我们只需:

代码语言:javascript
复制
Eigen::Array<uint32_t, Eigen::Dynamic, 1> mask_idcs(mask.count(), 1);
Eigen::SparseVector<bool> mask_sparse = mask.matrix().sparseView();
int z_idx = 0;
for (Eigen::SparseVector<bool>::InnerIterator it(mask_sparse); it; ++it) {
    mask_idcs(z_idx++) = it.index()
}

// do Stuff like vector(mask_idcs)*3 + another_vector

但是,我不知道哪个版本对于包含数千个元素的大型掩码来说更快。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70926877

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档