我已经阅读了很多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库中的一个错误吗?
通过将块分配给临时矩阵而不是块来解决这个问题是很容易的,即使它效率很低,所以我对此没有兴趣。
答案 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