11

我想知道是否有一种好方法可以使用Google TestGoogle Mock测试两个Eigen矩阵的近似相等性。

以下面的测试用例作为简化示例:我将两个复数值矩阵A和相乘B,并期望得到某个结果C_expect。我使用 Eigen 计算数值结果C_actual = A * B。现在,我想比较C_expectC_actual。现在,对应的代码如下所示:

#include <complex>
#include <Eigen/Dense>
#include <gtest/gtest.h>
#include <gmock/gmock.h>

typedef std::complex<double> Complex;
typedef Eigen::Matrix2cd Matrix;

TEST(Eigen, MatrixMultiplication) {
    Matrix A, B, C_expect, C_actual;

    A << Complex(1, 1), Complex(2, 3),
         Complex(3, 2), Complex(4, 4);
    B << Complex(4, 4), Complex(3, 2),
         Complex(2, 3), Complex(1, 1);
    C_expect << Complex(-5, 20), Complex(0, 10),
                Complex(0, 40), Complex(5, 20);

    C_actual = A * B;

    // !!! These are the lines that bother me.
    for (int j = 0; j < C_actual.cols(); ++j) {
        for (int i = 0; i < C_actual.rows(); ++i) {
            EXPECT_NEAR(C_expect(i, j).real(), C_actual(i, j).real(), 1e-7)
                << "Re(" << i << "," << j << ")";
            EXPECT_NEAR(C_expect(i, j).imag(), C_actual(i, j).imag(), 1e-7)
                << "Im(" << i << "," << j << ")";
        }
    }
}

这有什么问题?好吧,我必须手动遍历矩阵的所有索引,然后分别比较实部和虚部。我更喜欢类似于 Google MockElementsAreArray匹配器的东西。例如

EXPECT_THAT(C_actual, ElementsAreArray(C_expect));
// or
EXPECT_THAT(C_actual, Pointwise(MyComplexNear(1e-7), C_expect));

不幸的是,Google Mock 的内置功能似乎只适用于一维 C 风格或 STL 类型的容器。此外,我需要对矩阵的复数值进行近似比较。

我的问题:您知道是否(以及如何)可以教 Google Mock 迭代多个维度,并将复杂的浮点数与近似相等进行比较?

请注意,我不能只将数据指针作为 C 样式数组处理,因为存储布局可能在C_expect, 和C_actual. 此外,实际上,这些矩阵不仅仅是 2x2 矩阵。即某种循环绝对是必要的。

4

3 回答 3

18

为什么不使用 Eigen Matrix 类型的isApproxorisMuchSmallerThan成员函数?

上述这些函数的文档可在此处获得

因此,对于大多数情况而言ASSERT_TRUE(C_actual.isApprox(C_expect));,这就是您所需要的。您还可以提供一个精度参数作为 isApprox 的第二个参数

于 2014-08-04T20:44:44.590 回答
7

EXPECT_PRED2来自 GoogleTest 可以用于此。

在 C++11 下使用 lambda 可以正常工作,但看起来不合时宜:

  ASSERT_PRED2([](const MatrixXf &lhs, const MatrixXf &rhs) {
                  return lhs.isApprox(rhs, 1e-4);
               },
               C_expect, C_actual);

如果失败,您会得到输入参数的打印输出。

可以像这样定义普通的谓词函数,而不是使用 lambda:

bool MatrixEquality(const MatrixXf &lhs, const MatrixXf &rhs) {
  return lhs.isApprox(rhs, 1e-4);
}

TEST(Eigen, MatrixMultiplication) {
  ...

  ASSERT_PRED2(MatrixEquality, C_expected, C_actual);
}

更高版本也适用于 C++11 之前的版本。

于 2016-08-30T23:57:20.020 回答
3

一个简化的解决方案是将差异的范数与一些 epsilon 进行比较,即

(C_expect - C_actual).norm() < 1e-6 

在向量空间中 || X - Y || == 0 当且仅当 X == Y,并且范数始终为非负(实数)。这样,您不必手动执行循环并逐元素比较(当然,与简单的逐元素比较相比,规范将在后台执行更多计算)

PS:Matrix::norm()在 Eigen 中实现的是 Frobenius 范数,计算速度非常快,请参阅 http://mathworld.wolfram.com/FrobeniusNorm.html

于 2014-08-02T13:04:15.283 回答