I've read through a lot of the documentation, however if you find something which I've missed that can explain away my issue I'll be pleased. For background, I'm compiling on x86 Windows 10 in Visual Studio 2015 using the 3.2.7 Eigen Library. The 3.2.7 version is from May and while there have been releases since then, I haven't seen anything in the changelog that would indicate my issue has been solved.
The issue seems to only appear for matrices above a certain size. I don't know if this is a byproduct of something specific to my system or something inherent to Eigen.
The following code produces an access violation in both Debug and Release mode.
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
}
The problem is that temp
references the coefficients held by mx2
, but in the last assignment, mx2
is first resized before the expression gets evaluated. Therefore, during the actual evaluation of the expression, temp
references garbage. More precisely, here is what is actually generated (in a simplified manner):
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);
This is called an aliasing issue.
You can workaround by evaluating the expression in a temporary:
mx2 = (temp.array() * mx1.array()).eval();
Another solution is to copy mx2.topRows(.)
into a true MatrixXd
holding its own memory:
MatrixXd temp = mx2.topRows(mx1Rows);
mx2 = temp.array() * mx1.array();
Yet another solution is to evaluate into temp
and resize afterward:
Block<MatrixXd, -1, -1, false> temp = mx2.topRows(mx1Rows);
temp = temp.array() * mx1.array();
mx2.conservativeResize(mx1Rows,cols);