This forum has been archived. All content is frozen. Please use KDE Discuss instead.

got a compiler error when using EigenSolver

Tags: None
(comma "," separated)
ri_aje
Registered Member
Posts
8
Karma
0
Hi,

I made a simple example to play with eigen's eigen value and eigen vector functionalities.

Code: Select all
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-local-typedefs"

#include <Eigen/Dense>

#pragma GCC diagnostic pop

int main ()
{
 Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>const m;
 Eigen::EigenSolver<typename std::decay<decltype(m)>::type>const es(m);
 auto const ex = es.eigenvectors().real();
 ex.col(0);
}


using g++-4.8.0, I get the following compiler error:
In file included from /home/meng/libs/eigen-eigen-2249f9c22fe8/Eigen/Core:298:0,
from /home/meng/libs/eigen-eigen-2249f9c22fe8/Eigen/Dense:1,
from t.cc:4:
/home/meng/libs/eigen-eigen-2249f9c22fe8/Eigen/src/Core/Block.h: In instantiation of ‘Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel, true>::Block(XprType&, Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel, true>::Index) [with XprType = const Eigen::CwiseUnaryView<Eigen::internal::scalar_real_ref_op<std::complex<double> >, Eigen::Matrix<std::complex<double>, -1, -1> >; int BlockRows = -1; int BlockCols = 1; bool InnerPanel = true; Eigen::Block<XprType, BlockRows, BlockCols, InnerPanel, true>::Index = long int]’:
/home/meng/libs/eigen-eigen-2249f9c22fe8/Eigen/src/Core/../plugins/BlockMethods.h:560:34: required from ‘Eigen::DenseBase<Derived>::ConstColXpr Eigen::DenseBase<Derived>::col(Eigen::DenseBase<Derived>::Index) const [with Derived = Eigen::CwiseUnaryView<Eigen::internal::scalar_real_ref_op<std::complex<double> >, Eigen::Matrix<std::complex<double>, -1, -1> >; Eigen::DenseBase<Derived>::ConstColXpr = const Eigen::Block<const Eigen::CwiseUnaryView<Eigen::internal::scalar_real_ref_op<std::complex<double> >, Eigen::Matrix<std::complex<double>, -1, -1> >, -1, 1, true, true>; Eigen::DenseBase<Derived>::Index = long int]’
t.cc:13:10: required from here
/home/meng/libs/eigen-eigen-2249f9c22fe8/Eigen/src/Core/Block.h:271:39: error: passing ‘const Eigen::CwiseUnaryView<Eigen::internal::scalar_real_ref_op<std::complex<double> >, Eigen::Matrix<std::complex<double>, -1, -1> >’ as ‘this’ argument of ‘Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::Scalar& Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::coeffRef(Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::Index, Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::Index) [with ViewOp = Eigen::internal::scalar_real_ref_op<std::complex<double> >; MatrixType = Eigen::Matrix<std::complex<double>, -1, -1>; Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::Scalar = double; Eigen::CwiseUnaryViewImpl<ViewOp, MatrixType, Eigen::Dense>::Index = long int]’ discards qualifiers [-fpermissive]
: Base(internal::const_cast_ptr(&xpr.coeffRef(

I read the definition of CwiseUnaryViewImpl in eigen-eigen-2249f9c22fe8/Eigen/src/Core/CwiseUnaryView.h and found that
EIGEN_STRONG_INLINE Scalar& coeffRef(Index row, Index col)
does not have a const member overload which caused the error.

I wonder is this intended or an overlook? Thanks. If this is an overlook, then similar problem also exists for the following member
EIGEN_STRONG_INLINE Scalar& coeffRef(Index index)

Best
Meng
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
This is the intended behavior. The problem is that EigenSolver<T> is expecting a non-qualified type for T, so in your case:

EigenSolver<MatrixXd> es(m);

or play with std::remove_const
ri_aje
Registered Member
Posts
8
Karma
0
Thank you.
ri_aje
Registered Member
Posts
8
Karma
0
ggael wrote:This is the intended behavior. The problem is that EigenSolver<T> is expecting a non-qualified type for T, so in your case:

EigenSolver<MatrixXd> es(m);

or play with std::remove_const

I tried this method and it does not work. I also realized it should not work because by standard requirement, std::decay should have already removed any cv-qualifiers from its template argument type, which is to say typename std::decay<decltype(m)>::type is Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> already. To make sure this is the case, I added a static_assert to my sample code
static_assert(std::is_same<typename std::decay<decltype(m)>::type,
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic>>::value,"");
and I did not see it's triggered for a compilation that produced the same error as I posted earlier, i.e., static_assert did not stop the compilation which is later stopped by the coeffRef issue.

I also briefly read EigenSolver's compute method and I found it accepts const-qualified type regardless if the MatrixType is const-qualified, which makes sense to me because (I expect) the solver does not modify its argument. As far as I understand, further in the call chain, HessenbergDecomposition::compute makes a copy of the matrix before doing anything and later computation is based on the copy, which again makes sense to me, but this also suggests the const-qualifier (or absence) of the source type should not affect the solver as long as the solver is instantiated with a non-const qualified type, which is the case in my example.

I think the real issue causing the compiler error in my example is this line
auto const ex = es.eigenvectors().real();
because removing the const keyword in this declaration will make the program compile. However, I think the program should compile even at the presence of the const keyword because when all the related objects are const, it makes sense to expect the eigenvectors are also const types. Moreover, it is also dangerous to use a non-const eigenvectors because we then can accidentally modify its values. Therefore, the fact that CwiseUnaryViewImpl does not provide const overload for coeffRef member functions looks like an overlook to me because we should be able to read a const-qualified object (or expression).

Based on my analysis, can you please reconsider my question? Thanks.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
well, this does compile fine:
Code: Select all
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
int main ()
{
 MatrixXd const  m = MatrixXd::Random(4,4);
 EigenSolver<typename std::remove_const<typename std::decay<decltype(m)>::type >::type> const es(m);
 auto const ex = es.eigenvectors().real();
}

while it fails if you remove the std::remove_const.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
Maybe this a bug of gcc as I cannot reproduce with clang and decay<T>::type should indeed be a simple alias for remove_cv<remove_reference<T>::type>::type
ri_aje
Registered Member
Posts
8
Karma
0
ggael wrote:well, this does compile fine:
Code: Select all
#include <Eigen/Dense>
#include <iostream>
using namespace Eigen;
int main ()
{
 MatrixXd const  m = MatrixXd::Random(4,4);
 EigenSolver<typename std::remove_const<typename std::decay<decltype(m)>::type >::type> const es(m);
 auto const ex = es.eigenvectors().real();
}

while it fails if you remove the std::remove_const.


it compiles because you did not try to access its columns as I did in my example, i.e., this line causes the actual trouble when ex is declared const.
ex.col(0);
because it is in this line where the compiler has to access the data, hence necessitating the use of CwiseUnaryViewImpl::coeffRef.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
ok, forget all the previous confusion. Actually it is very good thing it does not compile because if it would then you'd get random segfaults. Indeed, EigenSolver::eigenvectors returns a temporary MatrixXcd that is stored by reference into the CwiseUnaryView expression (.real()). Therefore, the variable ex is invalid right after its definition line. If you really want to waste time with the auto keyword then do:

Code: Select all
auto const ev = es.eigenvectors();
auto const ex = ev.real();


or

Code: Select all
auto ev = es.eigenvectors();
auto ex = ev.real();


But honestly, with Eigen it is really not recommended to use the auto keyword unless you really know what you are doing. So the best is really to do the following:

Code: Select all
MatrixXd ex = es.eigenvectors().real();
ri_aje
Registered Member
Posts
8
Karma
0
huh, good point and thanks for the clarification. I agree with you that it is generally a bad idea to mix auto with expression template.


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], Sogou [Bot]