I encountered an error when creating a copy of a matrixxf which I used to get the rowwise average. It seems to generate exceedingly large values in debug, and a value of zero in release. In both cases, the answer is wrong as it the average is 0.5. If I don't use an extra line where I create a copy of inputs, the error disappears and the output is as expected. Why does this occur?
I have created a minimal example in cpp. I compile it in vs2022 using cl.exe with cmake.
int main() {
auto startTime = std::chrono::high_resolution_clock::now();
#ifdef NDEBUG
std::cout << "Release Build" << std::endl;
#else
std::cout << "Debug Build" << std::endl;
#endif
std::cout << "Eigen world version: " << EIGEN_WORLD_VERSION << "\n";
std::cout << "Eigen major version: " << EIGEN_MAJOR_VERSION << "\n";
std::cout << "Eigen minor version: " << EIGEN_MINOR_VERSION << "\n";
std::cout << "cpp version: " << __cplusplus << "\n";
Eigen::setNbThreads(1);
std::cout << "Eigen threads: " << Eigen::nbThreads() << "\n";
Eigen::MatrixXf inputs(2, 4);
inputs <<
1, 0, 1, 0,
1, 1, 0, 0;
Eigen::MatrixXf calcNextLine = inputs;
calcNextLine = calcNextLine.rowwise().mean();
Eigen::MatrixXf calcSameLine = inputs.rowwise().mean();
std::cout << "\ninputs = \n" << inputs << "\n";
std::cout << "\ncalcNextLine = \n" << calcNextLine << "\n";
std::cout << "\ncalcSameLine = \n" << calcSameLine << "\n";
auto currentTime = std::chrono::high_resolution_clock::now();
auto deltaTime = std::chrono::duration_cast<std::chrono::nanoseconds>(currentTime - startTime).count();
std::cout << "\nFinished in " << (deltaTime / 1.0e6) << " milliseconds.\n";
return 0;
}
Console output in debug:
Debug Build
Eigen world version: 3
Eigen major version: 4
Eigen minor version: 0
cpp version: 199711
Eigen threads: 1
inputs =
1 0 1 0
1 1 0 0
calcNextLine =
-1.07901e+08
-1.07901e+08
calcSameLine =
0.5
0.5
Finished in 4.2896 milliseconds.
Console output in release:
Release Build
Eigen world version: 3
Eigen major version: 4
Eigen minor version: 0
cpp version: 199711
Eigen threads: 1
inputs =
1 0 1 0
1 1 0 0
calcNextLine =
0
0
calcSameLine =
0.5
0.5
Finished in 3.6746 milliseconds.
If I don't use an extra line where I create a copy of inputs, the error disappears and the output is as expected. Why does this occur?
Here is what's happening in this particular line:
calcNextLine = calcNextLine.rowwise().mean();
rowwise().mean()
creates an object representing the partial reduction which references the calcNextLine
matrix.calcNextLine
itself, invoking its assignment operatorI'm pretty sure the Eigen documentation page on aliasing issues explains this stuff but the website is unavailable at the moment (again). In general, having an alias between the left and right side of an assignment in Eigen is only okay if:
left_side.noalias() = right_side
, of coursea = a + b
. This is not okay: a.topRows(N) = a.middleRows(1, N) + b
Anyway, how do you fix this? Two options:
eval()
to create a new vector before assigning it to its inputcalcNextLine = calcNextLine.rowwise().mean().eval();