Eigen3 (cpp) select 列给定掩码和总和,其中为真

Eigen3 (cpp) select column given mask and sum where true

我有一个 Eigen::Matrix2Xf,其中行是 X 和 Y 位置,列作为列表索引

我想要一些列条件为真的列的总和(按行),这里是一些示例代码:

Eigen::Vector2f computeStuff(Eigen::Matrix2Xf & values, const float max_norm){

    const auto mask = values.colwise().norm().array() < max_norm;

    return mask.select(values.colwise(), Eigen::Vector2f::Zero()).rowwise().sum();
    
}

但是这段代码没有编译抱怨 if/else 矩阵的类型,正确的(并且计算速度更快)的方法是什么?

我也知道有类似的问题和答案,但是他们用给定掩码的过滤值创建了一个新的 Eigen::Matrix2Xf,这段代码是为了 运行 在 #pragma omp parallel for 所以基本思想是不创建新矩阵来保持缓存一致性

谢谢

您的代码的主要问题是 .select( ... ) 至少需要其参数之一具有与掩码相同的形状。参数可以是两个矩阵或一个矩阵和一个标量,反之亦然,但在所有情况下,矩阵的形状都必须像掩码一样。

在您的代码中,mask 是行向量,但 values 是 2 x x 矩阵。处理此问题的一种方法是将行向量复制到两行矩阵中:

#include <Eigen/Dense>
#include <iostream>

Eigen::Vector2f computeStuff(Eigen::Matrix2Xf& values, const float max_norm) {

    auto mask = (values.colwise().norm().array() < max_norm).replicate(2, 1);
    return mask.select(values, 0).rowwise().sum();
}

int main() {

    Eigen::Matrix2Xf mat(2,4);
    mat << 1, 4, 3, 2, 
           1, 2, 4, 3;

    auto val = computeStuff(mat, 5);

    std::cout << val;

    return 0;
}

上面的mask会是:

1 1 0 1
1 1 0 1

1 1 0 1 行重复了一次。然后 mask.select(values, 0) 产生

1 4 0 2
1 2 0 3

所以结果会是

7
6

我想这就是你想要的,如果我理解这个问题的话。