我有:
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
似乎没有意识到它是在行向量上调用的不是一般矩阵 - 如果我错了,请纠正我。
答案 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)
来触发,其中mat
是GeneralProduct
。在内部,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);
升级到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+1
和my_vector
都非常小,那么您可以使用惰性产品来避免这种情况:
my_vector.transpose().lazyProduct(my_matrix.leftCols(n_cols+1)).maxCoeff(&index);
此处记录的编辑是fix。