"在换位期间检测到混叠"在Eigen

时间:2016-07-21 03:57:43

标签: c++ 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);
}

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

产生错误

  

static void Eigen :: internal :: checkTransposeAliasing_impl :: run(const Derived&amp;,const   OtherDerived&amp;)[with Derived = Eigen :: Array; OtherDerived = Eigen :: Transpose&gt ;; bool MightHaveTransposeAliasing = true]:断言   `(!check_transpose_aliasing_run_time_selector :: IsTransposed,OtherDerived&gt;   :: run(extract_data(dst),other))&amp;&amp; &#34;期间检测到别名   换位,使用transposeInPlace()&#34; &#34;或将rhs评估为a   暂时使用.eval()&#34;&#39;失败。

添加eval确实解决了问题:

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

(但添加它作为<< w.eval() <<的打印行不会。

我希望更好地了解正在发生的事情,并找出是否有另一种解决方法。

谢谢

1 个答案:

答案 0 :(得分:0)

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

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

Arr2

或者,将返回类型更改为.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<const Arr2<typename T::Scalar>>保留为表达式。以下代码是更好的工作版本。

auto

另一方面,我认为当A是表达式时,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; } 是一个临时对象,其生命在函数调用之后结束。您的reshape API会让那些不了解此限制的人感到困惑。

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

Map