特征库C ++

时间:2016-08-24 02:41:51

标签: c++ matrix eigen access-violation

我已经阅读了很多documentation,但是如果你发现我错过的东西可以解释我的问题,我会很高兴。对于背景,我正在使用3.2.7 Eigen Library在Visual Studio 2015中的x86 Windows 10上进行编译。 3.2.7版本是从5月开始的,虽然从那时起已经发布,但我没有在changelog中看到任何表明我的问题已经解决的内容。

问题似乎只出现在超过一定大小的矩阵上。我不知道这是否是我系统特有的东西或者Eigen固有的东西的副产品。

以下代码在调试和发布模式下都会产生访问冲突。

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
}

我认为系数乘法的赋值是安全的,因为结果应该是aliased

当mx1Rows减少到值254时,此问题变得有趣,然后不会出现访问冲突。这是正确的,256乘254的mx2尺寸会产生问题,但尺寸255乘254不会产生问题。如果我增加列大小,我也可以获得访问冲突,因此问题可能与条目总数有关。即使mx1和mx2填充了值,也会出现问题,不需要填充矩阵来重现问题。

未将topRows()块分配给temp的类似代码不会在发布模式下产生访问冲突。我相信还有更多的东西,因为我最初在代码中发现了这个问题,这个问题要复杂得多,并且只出现在一定数量的循环之后(循环之间的矩阵大小一致)。在我的代码中发生了很多事情,我无法隔离在一定数量的循环之后仅出现访问冲突的条件。

我很想知道的是

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

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

3)这是Eigen库中的一个错误吗?

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

2 个答案:

答案 0 :(得分:2)

问题在于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);

这称为aliasing issue

您可以通过评估临时表达式来解决方法:

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);

答案 1 :(得分:-2)

看起来像一个影响小尺寸的错误。删除错误诱导行中的注释以获得正确的结果。

校正。正如ggael的回答指出的那样,它是混叠。这是通常使用auto来创建一个稍后在同一个对象上使用的temp的类型。

#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