Eigen中maxCoeff的奇怪错误

时间:2015-11-17 00:49:15

标签: c++ eigen

我有:

VectorXd my_vector;
MatrixXd my_matrix;

和尺寸在下面的表达式中兼容。

我记得在Eigen doc中读到,总是更好地评估表达式而不是评估较小的chuncks然后重新组合结果,因为它为Eigen提供了更多的优化机会。

考虑到这一点,我会使用:

// (1)
int index;
(my_vector.transpose() * my_matrix.leftCols(n_cols+1)).maxCoeff(&index);

而不是:

// (2)
int index;
RowVectorXd temp = my_vector.transpose() * my_matrix.leftCols(n_cols+1);
temp.maxCoeff(&index);

然而(1)当n_cols = 1时崩溃,而使用(2)而不是(1)恰好在同一个地方似乎总是有效。 (请注意,my_matrix有超过1列...)

问题:
为什么(1)在(2)没有时会崩溃 如何防止(1)在保持单个表达式的同时崩溃?

错误来自Eigen的内部机制断言,在我看来,这是因为在(1)中maxCoeff似乎没有意识到它是在行向量上调用的不是一般矩阵 - 如果我错了,请纠正我。

2 个答案:

答案 0 :(得分:3)

作为解决方法,您可以使用.eval()。这实际上与(2)相同,只是没有额外的代码行:

(my_vector.transpose() * my_matrix.leftCols(n_cols + 1)).eval().maxCoeff(&index);

关于Eigen的内部工作原理,当你在案例(1)中调用maxCoeff时,被调用的对象是(如你所明确的那样)一个惰性求值结构(在这种情况下是GeneralProduct<Transpose<..>,Block<...> >)通过致电mat.coeff(0,0)来触发,其中matGeneralProduct。在内部,mat具有(n_cols + 1)列,而不是断言后的行所需的1(Matrix<Scalar,1,1> result = *this;) 这是导致评估的原因,因此我们希望每次只评估一个元素。如果没有断言,尝试将*this分配给result会触发调整大小,导致程序崩溃。

使用临时对象时,该对象为Matrix<double,1,-1,1,1,-1>,因此coeff(i,j)只是对m_storage.data()[colId + rowId * m_storage.cols()]的简单调用。

所有这一切都成为Eigen 3.3中的一个没有实际意义的点,因为整个coeff(i,j)现在是return m_evaluator.coeff(row, col);

TLDR

升级到Eigen 3.3(alpha),问题就消失了。

答案 1 :(得分:2)

要完成Avi的答案,首先要添加要有效评估的产品,无论如何都要将产品评估为临时产品,因此无论Eigen的版本如何,调用.eval()都非常好。

您正在观察的当前断言:

Assertion failed: (this->rows() == 1 && this->cols() == 1), function coeff, file ../eigen3.2/Eigen/src/Core/ProductBase.h, line 148

是为了确保产品表达式不是按系数方式评估的(内部产品除外)。可以在断言消息中添加此解释,以使其更加清晰。

然而,在你的情况下,你没有自己明确地调用coeff()operator(i,j),因此这是Eigen中的一个错误,更准确地说是Eigen::Visitor中应该评估嵌套产品的错误表达给你。这将在3.2.8中修复。

最后,如果您知道n_cols+1my_vector都非常小,那么您可以使用惰性产品来避免这种情况:

my_vector.transpose().lazyProduct(my_matrix.leftCols(n_cols+1)).maxCoeff(&index);
此处记录的

编辑fix