具有用户定义数据类型的特征矩阵赋值运算符

Eigen Matrix Assignment Operator with User-Defined Data Types

我正在使用 Eigen 矩阵库来处理 std::complex<T> 数据类型的矩阵,其中 Tdouble 类型或 ceres::Jet<double,...> 类型。 Eigen 文档指出 << 是用于赋值的正确运算符,但似乎 << 没有为用户定义数据类型的矩阵重载。是否有其他方法可用于初始化适用于两种数据类型的特征矩阵?

你的代码的问题不是 Eigen 没有为用户定义类型的矩阵重载(它是)而是你有一个 嵌套模板参数 Eigen::Matrix<std::complex<T>, Eigen::Dynamic, Eigen::Dynamic>(其中 T 类似于 ceres::Jet<double> 导致 Eigen::Matrix<std::complex<ceres::Jet<double>>, Eigen::Dynamic, Eigen::Dynamic>)。在使用流运算符 <<.

之前,您必须 显式构造嵌套类型 T 的元素
Eigen::Matrix<std::complex<T>, 3, 1> mat;
mat << T{1.0}, T{2.0}, T{3.0};

更详细的解释

为了进一步解释这一点,让我们从一个简单的 class 开始,我们将使用元素类型

class SomeClass {
  public:
    constexpr SomeClass(double const& some_data = 0.0) noexcept
      : some_data{some_data} {
      return;
    }

  private:
    double some_data;
};

此用户定义类型的矩阵可以成功分配:

Eigen::Matrix<SomeClass, 3, 1> mat;
mat << 1.0, 2.0, 3.0;

仅当您将其应用于 std::complex<SomeClass> 等嵌套元素类型时才会出现此问题。我们想使用 following overload:

CommaInitializer<Derived> Eigen::DenseBase<Derived>::operator<<(const Scalar& s)

其中 Scalar is the type of the matrix coefficients(元素类型,例如 Derived = Eigen::Matrix<std::complex<T>, 3, 1>Scalar = std::complex<T>):

Eigen::DenseBase<Derived>::Scalar

因此在编译GCC时会告诉你它不能匹配模板:

note: candidate: Eigen::CommaInitializer<Derived> Eigen::DenseBase<Derived>::operator<<(const Scalar&) [with Derived = Eigen::Matrix<std::complex<SomeClass>, 3, 1>; Eigen::DenseBase<Derived>::Scalar = std::complex<SomeClass>
inline CommaInitializer<Derived> DenseBase<Derived>::operator<< (const Scalar& s)

note: no known conversion for argument 1 from ‘double’ to ‘const Scalar& {aka const std::complex<SomeClass>&}’

要使其编译,您需要做的是构造具有可以转换为Scalar类型的元素,然后可以调用相应的流运算符如下:

mat << std::complex<SomeClass>{SomeClass{1.0}}, std::complex<SomeClass>{SomeClass{2.0}}, std::complex<SomeClass>{SomeClass{3.0}};

mat << std::complex<SomeClass>{1.0}, std::complex<SomeClass>{2.0}, std::complex<SomeClass>{3.0};

mat << SomeClass{1.0}, SomeClass{2.0}, SomeClass{3.0};

这应该可以通过将特征库更改为类似

的东西来避免
CommaInitializer<Derived> Eigen::DenseBase<Derived>::operator<<(Elem const& s)

并要求 std::enable_if_t, static_assert or C++20 concepts that Scalar can be constructed 类型为 Elem:

的元素
std::is_constructible_v<Scalar, Elem>

如果你真的需要你可以尝试自己写一个重载来确保 std::is_constructible_v<Scalar, Elem>!std::is_same_v<Scalar, Elem> 但我个人认为将这样的功能添加到自己现有的图书馆。其他人复制您的代码片段并期望它们能够工作可能最终导致代码无法工作。


作业的替代选项

作为 << 分配的替代方法,您可以

对于前两个选项,您必须使用与上一段中讨论的相同的逻辑或使用 双括号

Eigen::Matrix<std::complex<SomeClass>, 3, 1> mat = { {1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0} };

std::vector<std::complex<SomeClass>> vec = { {1.0, 2.0}, {2.0, 3.0}, {3.0, 4.0} };
Eigen::Matrix<std::complex<SomeClass>, 3, 1> mat{vec.data()};

而像

mat(0,0) = 1.0;

mat(0,0) = {1.0, 2.0};

将创建一个具有实部 1.0 和虚部 0.02.0 类型 SomeClass 的复杂元素,而无需调用构造函数 SomeClass{} 明确地。