gpt4 book ai didi

c++ - Eigen ConditionType数组:一种有效的广播方式,而不是循环

转载 作者:行者123 更新时间:2023-12-02 10:11:28 24 4
gpt4 key购买 nike

我有一段对性能至关重要的代码,我需要检查一个数组中低于阈值的值,然后有条件地设置其他两个数组的值。我的代码如下所示:

#include <Eigen/Dense>

int main(){
Eigen::ArrayXXd
a (1, 100),
b (2, 100),
c (3, 100);

a.setRandom();
b.setRandom();
c.setRandom();

constexpr double minVal { 1e-8 };

/* the code segment in question */
/* option 1 */
for ( int i=0; i<2; ++i ){
b.row(i) = (a < minVal).select( 0, c.row(i+1) / a );
c.row(i+1) = (a < minVal).select( 0, c.row(i+1) );
}
/* option 2, which is slower */
b = (a < minVal).replicate(2,1).select( 0, c.bottomRows(2) / a.replicate(2,1) );
c.bottomRows(2) = (a < minVal).replicate(2,1).select( 0, c.bottomRows(2) );

return 0;
}
数组 a(其值经过检查是否达到阈值 minVal)具有一行并且具有动态列数。其他两个数组 bc分别具有两行和三行,并且列数与 a相同。
现在,我想以一种更多 eigen的方式来执行上述逻辑,而在选项1中不使用该循环,因为通常, eigen会欺骗其性能,在编写原始循环时,我永远都希望匹配。
但是,我唯一想到的方法是选项2,它明显比选项1慢。
什么是正确而有效的方法来完成上述任务?还是循环已经是我最好的选择?

最佳答案

您可以尝试以下操作:

  • 用固定的行数和动态的列数定义数组类型,即,您可以将 Eigen::ArrayXXd 替换为 Eigen::Array
  • 使用固定大小的块操作(请参阅https://eigen.tuxfamily.org/dox/group__TutorialBlockOperations.html),即,您可以将 bottomRows(N)替换为 bottomRows () ,类似地将plicate(2,1)替换为reply <2, 1>()

  • 我已经更改了代码中的数组类型,并添加了第三个选项,并提到了可能的改进:
    #include <Eigen/Dense>

    #include <iostream>
    #include <chrono>

    constexpr int numberOfTrials = 1000000;
    constexpr double minVal{ 1e-8 };

    typedef Eigen::Array<double, 1, Eigen::Dynamic> Array1Xd;
    typedef Eigen::Array<double, 2, Eigen::Dynamic> Array2Xd;
    typedef Eigen::Array<double, 3, Eigen::Dynamic> Array3Xd;

    inline void option1(const Array1Xd& a, Array2Xd& b, Array3Xd& c)
    {
    for (int i = 0; i < 2; ++i) {
    b.row(i) = (a < minVal).select(0, c.row(i + 1) / a);
    c.row(i + 1) = (a < minVal).select(0, c.row(i + 1));
    }
    }

    inline void option2(const Array1Xd& a, Array2Xd& b, Array3Xd& c)
    {
    b = (a < minVal).replicate(2, 1).select(0, c.bottomRows(2) / a.replicate(2, 1));
    c.bottomRows(2) = (a < minVal).replicate(2, 1).select(0, c.bottomRows(2));
    }

    inline void option3(const Array1Xd& a, Array2Xd& b, Array3Xd& c)
    {
    b = (a < minVal).replicate<2, 1>().select(0, c.bottomRows<2>() / a.replicate<2, 1>());
    c.bottomRows<2>() = (a < minVal).replicate<2, 1>().select(0, c.bottomRows<2>());
    }

    int main() {
    Array1Xd a(1, 100);
    Array2Xd b(2, 100);
    Array3Xd c(3, 100);

    a.setRandom();
    b.setRandom();
    c.setRandom();

    auto tpBegin1 = std::chrono::steady_clock::now();
    for (int i = 0; i < numberOfTrials; i++)
    option1(a, b, c);
    auto tpEnd1 = std::chrono::steady_clock::now();

    auto tpBegin2 = std::chrono::steady_clock::now();
    for (int i = 0; i < numberOfTrials; i++)
    option2(a, b, c);
    auto tpEnd2 = std::chrono::steady_clock::now();

    auto tpBegin3 = std::chrono::steady_clock::now();
    for (int i = 0; i < numberOfTrials; i++)
    option3(a, b, c);
    auto tpEnd3 = std::chrono::steady_clock::now();

    std::cout << "(Option 1) Average execution time: " << std::chrono::duration_cast<std::chrono::microseconds>(tpEnd1 - tpBegin1).count() / (long double)(numberOfTrials) << " us" << std::endl;
    std::cout << "(Option 2) Average execution time: " << std::chrono::duration_cast<std::chrono::microseconds>(tpEnd2 - tpBegin2).count() / (long double)(numberOfTrials) << " us" << std::endl;
    std::cout << "(Option 3) Average execution time: " << std::chrono::duration_cast<std::chrono::microseconds>(tpEnd3 - tpBegin3).count() / (long double)(numberOfTrials) << " us" << std::endl;

    return 0;
    }
    我获得的平均执行时间如下(i7-9700K,msvc2019,启用优化和NDEBUG):
    (Option 1) Average execution time: 0.527717 us
    (Option 2) Average execution time: 3.25618 us
    (Option 3) Average execution time: 0.512029 us
    并启用AVX2 + OpenMP:
    (Option 1) Average execution time: 0.374309 us
    (Option 2) Average execution time: 3.31356 us
    (Option 3) Average execution time: 0.260551 us
    我不确定这是否是最“本征”的方式,但我希望它能有所帮助!

    关于c++ - Eigen ConditionType数组:一种有效的广播方式,而不是循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63375963/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com