【问题标题】:"aliasing detected during transposition" in EigenEigen 中的“在转置期间检测到混叠”
【发布时间】:2016-07-21 03:57:43
【问题描述】:

我有以下代码:

template <typename T>
using Arr = Array<T, Dynamic, 1>;

template <typename T>
using Arr2 = Array<T, Dynamic, Dynamic>;

template <typename T>
Arr2<typename T::Scalar> reshape (const ArrayBase<T> & A, const uint n, const uint m) {
    return Map<const Arr2<typename T::Scalar>>(A.eval().data(), n, m);
}

Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
auto w = reshape(v, 4, 4).transpose();
std::cout << w << std::endl;

产生错误

静态 void Eigen::internal::checkTransposeAliasing_impl::run(const Derived&, const OtherDerived&) [with Derived = Eigen::Array; OtherDerived = Eigen::Transpose >; bool MightHaveTransposeAliasing = true]:断言 `(!check_transpose_aliasing_run_time_selector ::IsTransposed,OtherDerived> ::run(extract_data(dst), other)) && "期间检测到混叠 转置,使用 transposeInPlace() " "或将 rhs 评估为 临时使用 .eval()"' 失败。

添加eval 确实解决了这个问题:

auto w = reshape(v, 4, 4).transpose().eval();

(但添加它会像 &lt;&lt; w.eval() &lt;&lt; 那样执行打印行)。

我想更好地了解正在发生的事情,并了解是否有其他方法可以解决此问题。

谢谢

【问题讨论】:

    标签: c++ eigen


    【解决方案1】:

    基本上,您只能创建现有对象的表达式/引用。当对象超出范围时,表达式/引用无效/未定义。

    使用auto w,您正在创建一个临时Arr2 对象的表达式,该对象的生命在此行之后结束,使w 无效。您看到的断言有助于检查这种情况。当您在return 行将Map 对象转换为Arr2 对象时,将创建此临时对象,这涉及从输入向量到临时Arr2 对象的不希望的数据复制。这恰好是the situations that you should not use auto 之一。如果您愿意再接受一份副本,则以下代码将起作用。相当于你在原始代码中添加.eval()

    #include <Eigen/Eigen>
    #include <iostream>
    using namespace Eigen;
    
    template<typename T>
    using Arr = Array<T, Dynamic, 1>;
    template<typename T>
    using Arr2 = Array<T, Dynamic, Dynamic>;
    
    template<typename T>
    Arr2<typename T::Scalar> reshape(const ArrayBase<T> & A, const uint n,
                                     const uint m) {
      return Map<const Arr2<typename T::Scalar>>(A.eval().data(), n, m);
    }
    
    int main() {
      Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
      Arr2<double> w = reshape(v, 4, 4).transpose();
      std::cout << w << std::endl;
      return 0;
    }
    

    或者,将返回类型更改为Map&lt;const Arr2&lt;typename T::Scalar&gt;&gt; 是避免上述两个副本的更好方法,您仍然可以使用auto 来保留w 作为表达式。以下代码是更好的工作版本。

    #include <Eigen/Eigen>
    #include <iostream>
    using namespace Eigen;
    
    template<typename T>
    using Arr = Array<T, Dynamic, 1>;
    template<typename T>
    using Arr2 = Array<T, Dynamic, Dynamic>;
    
    template<typename T>
    Map<const Arr2<typename T::Scalar>> reshape(const ArrayBase<T> & A,
                                                const uint n, const uint m) {
      return Map<const Arr2<typename T::Scalar>>(A.eval().data(), n, m);
    }
    
    int main() {
      Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
      auto w = reshape(v, 4, 4).transpose();
      std::cout << w << std::endl;
      return 0;
    }
    

    另一方面,当 A 是表达式时,我认为您的 reshape 仍然是错误的,因为 A.eval().data() 是一个临时对象,其生命周期在函数调用后结束。你的reshape API 会让不知道这个限制的人感到困惑。

    实际上创建一个重塑函数是不必要的,因为构建一个Map 对象本身在语义上意味着在一个连续的内存空间中重塑一些数据。我会推荐以下表格。它只比“reshape”这个词长一点,不涉及临时缓冲区/数据复制,auto w 仍然是一个表达式对象。

    #include <Eigen/Eigen>
    #include <iostream>
    using namespace Eigen;
    
    template<typename T>
    using Arr = Array<T, Dynamic, 1>;
    template<typename T>
    using Arr2 = Array<T, Dynamic, Dynamic>;
    
    int main() {
      Arr<double> v = Arr<double>::LinSpaced(16, 0, 15);
      auto w = Map<Arr2<double>>(v.data(), 4, 4).transpose();
      std::cout << w << std::endl;
      return 0;
    }
    

    【讨论】:

    • 那么你将如何“重塑”一个表达式?
    • eval() 到一个名为 Array 的对象,然后是 Map
    猜你喜欢
    • 1970-01-01
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 2012-10-10
    相关资源
    最近更新 更多