大块系数明智的乘法在特征库c++中失败

Large block coefficient-wise multiplication fails in Eigen library C++

本文关键字:特征 c++ 失败      更新时间:2023-10-16

我已经阅读了很多文档,但是如果你发现一些我错过的东西,可以解释我的问题,我会很高兴。作为背景,我在Visual Studio 2015中使用3.2.7 Eigen Library在x86 Windows 10上编译。3.2.7版本是从5月开始的,虽然从那以后有过发布,但我在更新日志中没有看到任何表明我的问题已经解决的内容。

这个问题似乎只出现在大于一定大小的矩阵上。我不知道这是系统特有的副产品还是本征固有的东西。

下面的代码在Debug和Release模式下都会产生访问冲突。

int mx1Rows = 255, cols = 254;
{//this has an access violation at the assignment of mx2
        Eigen::MatrixXd mx1(mx1Rows, cols);
        Eigen::MatrixXd mx2(mx1Rows + 1, cols);
        Eigen::Block<Eigen::MatrixXd, -1, -1, false> temp = mx2.topRows(mx1Rows);
        mx2 = temp.array() * mx1.array();//error
}

我相信系数明智乘法的赋值是安全的,因为结果应该被别名。

当mx1Rows减少到254时,这个问题变得有趣,然后访问冲突就不会出现。没错,256 × 254的mx2维度会产生这个问题但是255 × 254的维度不会。如果我增加列的大小,我也会得到访问冲突,所以问题可能与条目的总数有关。即使mx1和mx2填充了值,也会出现问题,没有必要填充矩阵来重现问题。

不将topRows()块赋值给temp的类似代码在Release模式下不会产生访问冲突。我相信还有更多的事情要做,因为我最初在代码中发现了这个问题,这个问题相当复杂,它只出现在一定数量的循环之后(循环之间的矩阵大小是一致的)。我的代码中有太多的内容,以至于我无法隔离访问冲突只在一定数量的循环之后出现的条件。

我想知道的是

1)我是否以某种明显错误的方式使用了Eigen ?

2)你能重现这个问题吗?(你的环境特点是什么?)

3)这是特征库中的错误吗?

通过将块分配给临时矩阵而不是块来解决这个问题很容易,即使它效率低下,所以我对听到这个不感兴趣。

问题是temp引用了mx2持有的系数,但在最后一次赋值中,mx2在表达式得到评估之前首先调整了大小。因此,在表达式的实际求值期间,temp引用垃圾。更准确地说,下面是实际生成的内容(以简化的方式):

double* temp_data = mx2.data;
free(mx2.data);
mx2.data = malloc(sizeof(double)*mx1Rows*cols);
for(j=0;j<cols;++j)
  for(i=0;i<mx1Rows;++i)
    mx2(i,j) = temp_data[i+j*(mw1Rows+1)] * mx1(i,j);

这就是所谓的混叠问题。

您可以通过在临时表达式中求值来解决:

mx2 = (temp.array() * mx1.array()).eval();

另一个解决方案是将mx2.topRows(.)复制到拥有自己内存的真正MatrixXd中:

MatrixXd temp = mx2.topRows(mx1Rows);
mx2 = temp.array() * mx1.array();

另一个解决方案是计算为temp,然后调整大小:

Block<MatrixXd, -1, -1, false> temp = mx2.topRows(mx1Rows);
temp = temp.array() * mx1.array();
mx2.conservativeResize(mx1Rows,cols);

看起来像一个影响小维度的bug。删除引起错误的行中的注释以获得正确的结果。

修正。正如迦勒的回答所指出的,这是一种混叠。它是使用auto创建一个稍后在同一对象上使用的临时值时经常遇到的类型。

#include <iostream>
#include <Eigen/Dense>
int main()
{//this has an access violation at the assignment of mx2
    //const int mx1Rows = 255, cols = 254;
    const int mx1Rows = 3, cols = 2;
    Eigen::MatrixXd mx1(mx1Rows, cols);
    int value = 0;
    for (int j = 0; j < cols; j++)
        for (int i = 0; i < mx1Rows; i++)
            mx1(i,j)=value++;
    Eigen::MatrixXd mx2(mx1Rows + 1, cols);
    for (int j = 0; j < cols; j++)
        for (int i = 0; i < mx1Rows+1; i++)
            mx2(i,j)=value++;
    Eigen::Block<Eigen::MatrixXd, -1, -1> temp = mx2.topRows(mx1Rows);
    mx2 = temp.array()/*.eval().array()*/ * mx1.array();r
    std::cout << mx2.array() << std::endl;
}
// with /*.eval().array()*/ uncommented
//0 30
//7 44
//16 60
// Original showing bug
//-0 -4.37045e+144
//-1.45682e+144 -5.82726e+144
//-2.91363e+144 -7.28408e+144