assert() leads to maybe-uninitialized gcc warning - c++

The following code compiles fine, with no warnings/errors:
#include <bitset>
#include <Eigen/Core>
using Array = Eigen::Array<float, -1, 1, 0, 3, 1>;
struct Tree {
Array array;
std::bitset<8> bitset;
};
auto func(Tree* tree) {
int c = tree->array.rows();
int d = tree->bitset.count();
//assert(c==d);
Array e(c);
for (int k = 0; k < d; ++k) e(k) = k;
return e.sum() / (e + 1);
}
int main() {
Tree tree;
func(&tree);
return 0;
}
Compilation cmd:
g++ -O3 -Wall -I anaconda3/envs/dev/include/eigen3/ test.cpp
However, when I uncomment the assert(), I get a maybe-uninitialized warning:
In file included from anaconda3/envs/dev/include/eigen3/Eigen/Core:253,
from test.cpp:2:
In member function ‘Eigen::internal::scalar_sum_op<LhsScalar, RhsScalar>::result_type Eigen::internal::scalar_sum_op<LhsScalar, RhsScalar>::operator()(const LhsScalar&, const RhsScalar&) const [with LhsScalar = float; RhsScalar = float]’,
inlined from ‘static Eigen::internal::redux_impl<Func, Evaluator, 3, 0>::Scalar Eigen::internal::redux_impl<Func, Evaluator, 3, 0>::run(const Evaluator&, const Func&, const XprType&) [with XprType = Eigen::Array<float, -1, 1, 0, 3, 1>; Func = Eigen::internal::scalar_sum_op<float, float>; Evaluator = Eigen::internal::redux_evaluator<Eigen::Array<float, -1, 1, 0, 3, 1> >]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:278:19,
inlined from ‘typename Eigen::internal::traits<T>::Scalar Eigen::DenseBase<Derived>::redux(const Func&) const [with BinaryOp = Eigen::internal::scalar_sum_op<float, float>; Derived = Eigen::Array<float, -1, 1, 0, 3, 1>]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:418:56,
inlined from ‘typename Eigen::internal::traits<T>::Scalar Eigen::DenseBase<Derived>::sum() const [with Derived = Eigen::Array<float, -1, 1, 0, 3, 1>]’ at anaconda3/envs/dev/include/eigen3/Eigen/src/Core/Redux.h:463:25,
inlined from ‘auto func(Tree*)’ at test.cpp:17:15:
anaconda3/envs/dev/include/eigen3/Eigen/src/Core/functors/BinaryFunctors.h:42:122: warning: ‘((const float*)((char*)&e + offsetof(Eigen::Array, Eigen::Array<float, -1, 1, 0, 3, 1>::<unnamed>.Eigen::PlainObjectBase<Eigen::Array<float, -1, 1, 0, 3, 1> >::m_storage)))[3]’ may be used uninitialized [-Wmaybe-uninitialized]
42 | EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a + b; }
| ~~^~~
test.cpp: In function ‘auto func(Tree*)’:
test.cpp:15:9: note: ‘e’ declared here
15 | Array e(c);
| ^
My question is this: why does the presence of the assert() affect whether or not gcc reports a maybe-uninitialized warning?
The example I show happens to use the eigen3 library, but I think my question is more general. How can the inclusion of an assert() that merely compares two int values lead to a compiler warning like this?
I want to note that this code is a minimal reproducible example for this assert-dependent-warning behavior. Removing the for-loop inside func(), for instance, makes the warning appear even without the assert. Replacing e.sum() / (e + 1) with a simpler expression like e + 1 makes the warning disappear with the assert. Replacing the std::bitset with something else also makes the warning disappear with the assert.
I am using gcc-11.3.0 and eigen-3.4.0.

This is apparently due to a gcc bug. The bug is present in gcc-12 or lower, and is fixed in gcc-13. A fix might be coming in gcc-12.
Bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108230

Related

c++ eigen static assert confuses enum with float

Here is the code:
#include <Eigen/Dense>
using namespace Eigen;
enum { TWO = 2};
Matrix<float, Dynamic, TWO> m1(42, 2); // good...
Matrix<float, Dynamic, TWO> m2(42, int(TWO)); // good...
Matrix<float, Dynamic, TWO> m3(42, TWO); // error!
When I compile the declaration of m3 is raising an error as if the enum value TWO is a floating point number:
$ g++ -I/usr/include/eigen3 -c bug.cpp
In file included from /usr/include/eigen3/Eigen/Core:366,
from /usr/include/eigen3/Eigen/Dense:1,
from bug.cpp:1:
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h: In instantiation of ‘void Eigen::PlainObjectBase<Derived>::_init2(Eigen::Index, Eigen::Index, typename Eigen::internal::enable_if<(typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 2), T0>::type*) [with T0 = int; T1 = <unnamed enum>; Derived = Eigen::Matrix<float, -1, 2>; Eigen::Index = long int; typename Eigen::internal::enable_if<(typename Eigen::internal::dense_xpr_base<Derived>::type::SizeAtCompileTime != 2), T0>::type = int]’:
/usr/include/eigen3/Eigen/src/Core/Matrix.h:302:35: required from ‘Eigen::Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::Matrix(const T0&, const T1&) [with T0 = int; T1 = <unnamed enum>; _Scalar = float; int _Rows = -1; int _Cols = 2; int _Options = 0; int _MaxRows = -1; int _MaxCols = 2]’
bug.cpp:6:39: required from here
/usr/include/eigen3/Eigen/src/Core/PlainObjectBase.h:740:58: error: static assertion failed: FLOATING_POINT_ARGUMENT_PASSED__INTEGER_WAS_EXPECTED
740 | EIGEN_STATIC_ASSERT(bool(NumTraits<T0>::IsInteger) &&
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
741 | bool(NumTraits<T1>::IsInteger),
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/usr/include/eigen3/Eigen/src/Core/util/StaticAssert.h:33:54: note: in definition of macro ‘EIGEN_STATIC_ASSERT’
33 | #define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
|
The error message is just not chosen well since it always mentions floating points as causing the issue, but the point is that you need to pass an integer type, which an enumeration type is not.
However, with Eigen version 3.3.8 this has been changed and an enumeration type is now accepted as well and will be converted to its underlying integer type, see this issue resulting in this commit. Since that version your code compiles fine, see https://godbolt.org/z/W4jYbKfns.

Tensorflow C++ Placeholder initialization

I was trying to perform image captioning with tensorflow on cpp. I was following the direction on How to import an saved Tensorflow model train using tf.estimator and predict on input data and tried
int main(int argc, char**) {
....
auto x = tf::Tensor(tf::DT_UINT8, tf::TensorShape({height, width, channel}));
auto matrix = x.matrix<char>();
....
}
When I compile the program, the code
> In file included from /usr/local/include/tensorflow/core/framework/tensor.h:26:0,
from /usr/local/include/tensorflow/core/public/session.h:23,
from /usr/local/include/tensorflow/cc/saved_model/loader.h:26,
from server.cpp:22:
/usr/local/include/tensorflow/core/framework/types.h: In instantiation of ‘struct tensorflow::DataTypeToEnum<char>’:
/usr/local/include/tensorflow/core/framework/tensor.h:530:46: required from ‘typename tensorflow::TTypes<T, NDIMS>::Tensor tensorflow::Tensor::tensor() [with T = char; long unsigned int NDIMS = 2ul; typename tensorflow::TTypes<T, NDIMS>::Tensor = Eigen::TensorMap<Eigen::Tensor<char, 2, 1, long int>, 16, Eigen::MakePointer>]’
/usr/local/include/tensorflow/core/framework/tensor.h:240:25: required from ‘typename tensorflow::TTypes<T>::Matrix tensorflow::Tensor::matrix() [with T = char; typename tensorflow::TTypes<T>::Matrix = Eigen::TensorMap<Eigen::Tensor<char, 2, 1, long int>, 16, Eigen::MakePointer>]’
server.cpp:121:34: required from here
/usr/local/include/tensorflow/core/framework/types.h:138:3: error: static assertion failed: Specified Data Type not supported
static_assert(IsValidDataType<T>::value, "Specified Data Type not supported");In file included from /usr/local/include/tensorflow/core/public/session.h:23:0,
from /usr/local/include/tensorflow/cc/saved_model/loader.h:26,
from server.cpp:22:
/usr/local/include/tensorflow/core/framework/tensor.h: In instantiation of ‘typename tensorflow::TTypes<T, NDIMS>::Tensor tensorflow::Tensor::tensor() [with T = char; long unsigned int NDIMS = 2ul; typename tensorflow::TTypes<T, NDIMS>::Tensor = Eigen::TensorMap<Eigen::Tensor<char, 2, 1, long int>, 16, Eigen::MakePointer>]’:
/usr/local/include/tensorflow/core/framework/tensor.h:240:25: required from ‘typename tensorflow::TTypes<T>::Matrix tensorflow::Tensor::matrix() [with T = char; typename tensorflow::TTypes<T>::Matrix = Eigen::TensorMap<Eigen::Tensor<char, 2, 1, long int>, 16, Eigen::MakePointer>]’
server.cpp:121:34: required from here
/usr/local/include/tensorflow/core/framework/tensor.h:530:46: error: ‘v’ is not a member of ‘tensorflow::DataTypeToEnum<char>’
CheckTypeAndIsAligned(DataTypeToEnum<T>::v());
Did anybody came across the same problem?
Found a solution. It seems like two issues were present.
(1) DT_UINT8 is uchar in c++
(2) use tensor instead of matrix
I changed the code to
auto x = tf::Tensor(tf::DT_UINT8, tf::TensorShape(
{height, width,3}));
auto matrix = x.tensor<uchar, 3>();
and worked. Got the idea from https://github.com/tensorflow/tensorflow/issues/19909
Even though you declare your TensorShape with an initialization list, you should still specify the number of dimensions of your matrix, as it cannot be deduced at compilation time in C++.
auto x = tf::Tensor(tf::DT_UINT8, tf::TensorShape({height, width, channel}));
auto matrix = x.matrix<char, 3>();

Eigen, function of RowXpr

I am using Eigen, and am currently trying to write a function to operate on rows of a matrix. I've followed the guidelines in the docs but nothing I try compiles (with either clang or g++); I'm at my wits end. How should one actually write functions which will take a RowXpr?
For reference, here is what I have tried so far:
#include <iostream>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
#define FUNC 3
#if FUNC == 1
vect_t func(const vect_t& f)
{
return f;
}
#elif FUNC == 2
vect_t func(const Ref<vect_t>& f)
{
return f;
}
#elif FUNC == 3
template<class D> vect_t func(const MatrixBase<D>& f)
{
return f;
}
#endif
int main()
{
matr_t M = matr_t::Random(5,3);
cout << M << endl;
cout << func( M.row(2) ) << endl;
return 0;
}
Thanks!
Edit:
With clang (version 3.8.0-2ubuntu4) the error I get is as below. The error is comparable with g++.
dan#dan-laptop:~/workspace/scratch$ clang++ eigen_func_test.cpp -I /home/dan/Downloads/eigen_3.3.3/ --std=c++11 && ./a.out
In file included from eigen_func_test.cpp:2:
In file included from /home/dan/Downloads/eigen_3.3.3/Eigen/Core:436:
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
...EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/util/StaticAssert.h:32:40: note: expanded from macro
'EIGEN_STATIC_ASSERT'
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
^ ~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:535:7: note: in instantiation of member function
'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3> >::_check_template_params' requested here
_check_template_params();
^
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/Matrix.h:379:9: note: in instantiation of function template
specialization 'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3>
>::PlainObjectBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
: Base(other.derived())
^
eigen_func_test.cpp:32:9: note: in instantiation of function template specialization 'Eigen::Matrix<double, 1, 3, 0,
1, 3>::Matrix<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
return f;
^
eigen_func_test.cpp:41:10: note: in instantiation of function template specialization
'func<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
cout << func( M.row(2) ) << endl;
^
1 error generated.
If you read the part highlighted by clang
EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
you see that, if a matrix has one row at compile time and more than one column, it must be RowMajor. That means, if you set Order = RowMajor or just leave out the , Order in
using vect_t = Matrix<double, 1, 3, Order>;
your code should compile fine (it looks like everything else are just follow-up errors).
Not exactly sure what is causing your compiler error directly but from what you have shown in your source code as well as your compiler errors. This is the part of the compiler error message that I'm basing this off of.
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
So when looking at the source code you are trying to use the #define func3
that you have declared as such:
template<class D> vect_t func(const MatrixBase<D>& f) {
return f;
}
with the using directives that you have declared as:
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
So let's expand this to the full form to see what the compiler is trying to parse or deduce as your parameters and return type.
template<class D>
Matrix<double, 1, 3, constexpr Eigen::StorageOptions Order = ColMajor>
func( const MatrixBase<D>& f ) {
return f;
}
Then in your main you use this with:
int main() {
// matr_t M = matr_t::Random(5,3);
Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor> M
= Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3);
// Then you call your function passing it this:
std::cout << func( M.row(2) ) << std::endl;
return 0;
}
func() is returning Matrix<double, 1, 3, Order>;
and it takes const MatrixBase<D>&
however it appears you are passing it: M.row(2)
that is constructed from: Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3)
In the function itself you are returning f which happens to be
the function's const ref of MatrixBase<D> parameter yet the declaration is expecting to return a Matrix<double, 1, 3, Order>
So I think the compiler is having a hard time trying to convert a
Matrix<double, Dynamic, 3, Order> to a Matrix<double, 1, 3, Order>
Maybe this will help you to understand the compiler error a little better; as you can see when you look at the rest of the compilation error message you can tell that this is evident when it is trying to do the specializations of this template.

Using Boost::odeint with Eigen::Matrix as state vector

I'm trying to utilize the ODE integration capabilities of Boost using the Matrix class from Eigen 3 as my state vector, but I'm running into problems deep into Boost that I don't understand how to address.
A minimal example of what I'm trying to do:
#include <Eigen/Core>
#include <boost/numeric/odeint/stepper/runge_kutta_dopri5.hpp>
#include <iostream>
using namespace Eigen;
using namespace boost::numeric::odeint;
template<size_t N>
using vector = Matrix<double, N, 1>;
typedef vector<3> state;
int main() {
state X0;
X0 << 1., 2., 3.;
state xout = X0;
runge_kutta_dopri5<state> stepper;
// If I remove these lines, everything compiles fine
stepper.do_step([](const state x, state dxdt, const double t) -> void {
dxdt = x;
}, X0, 0.0, xout, 0.01);
std::cout << xout << std::endl;
}
If I coment out the call to stepper.do_step everything compiles and runs just fine, but of course doesn't do anything interesting. If I don't, Boost vomits compile errors over my terminal, the first of which is
In file included from /usr/include/boost/mpl/aux_/begin_end_impl.hpp:20:0,
from /usr/include/boost/mpl/begin_end.hpp:18,
from /usr/include/boost/mpl/is_sequence.hpp:19,
from /usr/include/boost/fusion/support/detail/is_mpl_sequence.hpp:12,
from /usr/include/boost/fusion/support/tag_of.hpp:13,
from /usr/include/boost/fusion/support/is_sequence.hpp:11,
from /usr/include/boost/fusion/sequence/intrinsic_fwd.hpp:12,
from /usr/include/boost/fusion/sequence/intrinsic/front.hpp:10,
from /usr/include/boost/fusion/include/front.hpp:10,
from /usr/include/boost/numeric/odeint/util/is_resizeable.hpp:26,
from /usr/include/boost/numeric/odeint/util/state_wrapper.hpp:25,
from /usr/include/boost/numeric/odeint/stepper/base/explicit_error_stepper_fsal_base.hpp:27,
from /usr/include/boost/numeric/odeint/stepper/runge_kutta_dopri5.hpp:24,
from /home/tlycken/exjobb/Code/alpha-orbit-follower/test/algebra/algebra-tests.cpp:2:
/usr/include/boost/mpl/eval_if.hpp: In instantiation of ‘struct boost::mpl::eval_if_c<true, boost::range_const_iterator<Eigen::Matrix<double, 3, 1> >, boost::range_mutable_iterator<const Eigen::Matrix<double, 3, 1> > >’:
/usr/include/boost/range/iterator.hpp:63:63: required from ‘struct boost::range_iterator<const Eigen::Matrix<double, 3, 1> >’
/usr/include/boost/range/begin.hpp:112:61: required by substitution of ‘template<class T> typename boost::range_iterator<const T>::type boost::range_adl_barrier::begin(const T&) [with T = Eigen::Matrix<double, 3, 1>]’
/usr/include/boost/numeric/odeint/algebra/range_algebra.hpp:52:45: required from ‘static void boost::numeric::odeint::range_algebra::for_each3(S1&, S2&, S3&, Op) [with S1 = Eigen::Matrix<double, 3, 1>; S2 = const Eigen::Matrix<double, 3, 1>; S3 = const Eigen::Matrix<double, 3, 1>; Op = boost::numeric::odeint::default_operations::scale_sum2<double, double>]’
/usr/include/boost/numeric/odeint/stepper/runge_kutta_dopri5.hpp:128:9: required from ‘void boost::numeric::odeint::runge_kutta_dopri5<State, Value, Deriv, Time, Algebra, Operations, Resizer>::do_step_impl(System, const StateIn&, const DerivIn&, boost::numeric::odeint::runge_kutta_dopri5<State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type, StateOut&, DerivOut&, boost::numeric::odeint::runge_kutta_dopri5<State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type) [with System = main()::__lambda0; StateIn = Eigen::Matrix<double, 3, 1>; DerivIn = Eigen::Matrix<double, 3, 1>; StateOut = Eigen::Matrix<double, 3, 1>; DerivOut = Eigen::Matrix<double, 3, 1>; State = Eigen::Matrix<double, 3, 1>; Value = double; Deriv = Eigen::Matrix<double, 3, 1>; Time = double; Algebra = boost::numeric::odeint::range_algebra; Operations = boost::numeric::odeint::default_operations; Resizer = boost::numeric::odeint::initially_resizer; boost::numeric::odeint::runge_kutta_dopri5<State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type = double]’
/usr/include/boost/numeric/odeint/stepper/base/explicit_error_stepper_fsal_base.hpp:167:9: required from ‘typename boost::disable_if<boost::is_same<StateInOut, Time>, void>::type boost::numeric::odeint::explicit_error_stepper_fsal_base<Stepper, Order, StepperOrder, ErrorOrder, State, Value, Deriv, Time, Algebra, Operations, Resizer>::do_step(System, const StateIn&, boost::numeric::odeint::explicit_error_stepper_fsal_base<Stepper, Order, StepperOrder, ErrorOrder, State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type, StateOut&, boost::numeric::odeint::explicit_error_stepper_fsal_base<Stepper, Order, StepperOrder, ErrorOrder, State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type) [with System = main()::__lambda0; StateIn = Eigen::Matrix<double, 3, 1>; StateOut = Eigen::Matrix<double, 3, 1>; Stepper = boost::numeric::odeint::runge_kutta_dopri5<Eigen::Matrix<double, 3, 1> >; short unsigned int Order = 5u; short unsigned int StepperOrder = 5u; short unsigned int ErrorOrder = 4u; State = Eigen::Matrix<double, 3, 1>; Value = double; Deriv = Eigen::Matrix<double, 3, 1>; Time = double; Algebra = boost::numeric::odeint::range_algebra; Operations = boost::numeric::odeint::default_operations; Resizer = boost::numeric::odeint::initially_resizer; typename boost::disable_if<boost::is_same<StateInOut, Time>, void>::type = void; boost::numeric::odeint::explicit_error_stepper_fsal_base<Stepper, Order, StepperOrder, ErrorOrder, State, Value, Deriv, Time, Algebra, Operations, Resizer>::time_type = double]’
/home/tlycken/exjobb/Code/alpha-orbit-follower/test/algebra/algebra-tests.cpp:21:137: required from here
/usr/include/boost/mpl/eval_if.hpp:60:31: error: no type named ‘type’ in ‘boost::mpl::eval_if_c<true, boost::range_const_iterator<Eigen::Matrix<double, 3, 1> >, boost::range_mutable_iterator<const Eigen::Matrix<double, 3, 1> > >::f_ {aka struct boost::range_const_iterator<Eigen::Matrix<double, 3, 1> >}’
typedef typename f_::type type;
I tried to dig into the Boost header where the error occurs, but I didn't understand enough of what's going on to be able to fix my code. Since the odeint library documentation clearly states
The main focus of odeint is to provide numerical methods implemented in a way where the algorithm is completely independent on the data structure used to represent the state x.
I believe this shouldn't be too hard to get working even if odeint doesn't support Eigen natively.
You only need to replace the definition of the stepper by
runge_kutta_dopri5<state,double,state,double,vector_space_algebra> stepper;
Eigen should work out of the Box with the vector_space_algebra but you need to specify them manually. In the next odeint version we have a mechanism for automatically detecting the algebra.
Btw. youe definition of the ODE is not correct, you need a reference for the derivatve
stepper.do_step([](const state &x, state &dxdt, const double t) -> void {
dxdt = x;
}, X0, 0.0, xout, 0.01);
This solution does not seem to work for adaptive integrator
typedef runge_kutta_dopri5<state,double,state,double,vector_space_algebra> stepper_type;
auto rhs = [](const state &x, state &dxdt, const double t) -> void { dxdt = x;}
integrate_adaptive( make_controlled<stepper_type>( 1E-12 , 1E-12 ), rhs , X0 , 0. , xout , 0.01;)

Compilation Error Using template programming with Eigen C++ library

I downloaded Eigen (3) library and started using it. I wrote a template function and declared a local variable of 'template type' inside the function. I am getting the following compilation error.
$ g++ EigenTest.cpp
EigenTest.cpp: In instantiation of ‘void myFunc(Eigen::MatrixBase<Derived>&) [with Type1 = Eigen::Matrix<double, -1, -1>]’:
EigenTest.cpp:24:10: required from here
EigenTest.cpp:16:26: error: conversion from ‘Eigen::DenseCoeffsBase<Eigen::Matrix<double, -1, -1>, 1>::Scalar {aka double}’ to non-scalar type ‘Eigen::Matrix<double, -1, -1>’ requested
Type1 tmp = matrix(0, 0);
"EigenTest.cpp" is given below.
#include "Eigen/Dense"
#include <iostream>
template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
int i=matrix.rows();
Type1 tmp = matrix(0, 0); // getting compiler error here
std::cout<<"tmp is ->"<<tmp<<std::endl;
}
int main()
{
Eigen::MatrixXd m(2,2);
m.setConstant(100);
myFunc(m);
return 0;
}
I also tried using 'typename Type1 tmp = matrix(0, 0);'
This also didn't work!
How to fix this?
In normal C++ template programming (without Eigen), I can define a local variable inside a template function as 'Type1 tmp;"
In Eigen::MatrixBase<Type1>, Type1 is not a scalar type but the type of the actual expression. In your example it will be MatrixXd but if myFunc is called on, e.g., m.block(...), then Type1 will be a Block<...>. To obtain the scalar type, you can use Type1::Scalar:
template<typename Type1>
void myFunc(Eigen::MatrixBase<Type1>& matrix)
{
typename Type1::Scalar Scalar;
Scalar tmp = matrix(0, 0);
}
And if you need a matrix type that is similar to Type1, use Type1::PlainObject, e.g.:
typename Type1::PlainObject mat = 2 * matrix * matrix.transpose();
It looks like MatrixBase uses the "CRTP" (see here), the template argument is actually the type deriving from it. Thus in your use of the method myFunc(), Type1 is actually representing Eigen::MatrixXd, and I think that you think Type1 is a double. So, this line:
Type1 tmp = matrix(0, 0);
In the documnetation for this library (see here) the typedef for MatrixXd is a matrix of doubles, so I guess the return from matrix(0, 0) is a double, and as tmp is of Type1 which is Eigen::MatrixXd, the one will not go into the other.
Scanning the docummentation I think it MIGHT be better for your function to take a Matrix as an argument, that way the scalar type should be available. Something like this:
template<class T, int rows, int cols, int opts, int maxR, int maxC >
void myFunc( Eigen::Matrix<T, rows, cols, opts, maxR, maxC>& matrix )
{
T tmp = matrix(0, 0);
}
(Looks dreadful though!!! ;-) )
In your code, Type1 is deduced to be double (because Eigen::MatrixXd is defined that way).
You are then trying to do
Type1 tmp = matrix(0, 0);
And I'm afraid my Eigen knowledge isn't enough, so I ran it through Clang 3.3, and got this error:
test.cpp:9:7: error: no viable conversion from 'Scalar' (aka 'double') to
'Eigen::Matrix<double, -1, -1, 0, -1, -1>'
Type1 tmp = matrix(0, 0); // getting compiler error here
^ ~~~~~~~~~~~~
test.cpp:17:1: note: in instantiation of function template specialization
'myFunc<Eigen::Matrix<double, -1, -1, 0, -1, -1> >' requested here
myFunc(m);
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:210:5: note: candidate constructor not viable:
no known conversion from 'Scalar' (aka 'double') to
'internal::constructor_without_unaligned_array_assert' for 1st argument
Matrix(internal::constructor_without_unaligned_array_assert)
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:284:25: note: candidate constructor not
viable: no known conversion from 'Scalar' (aka 'double') to 'const
Eigen::Matrix<double, -1, -1, 0, -1, -1> &' for 1st argument
EIGEN_STRONG_INLINE Matrix(const Matrix& other)
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:272:25: note: candidate template ignored:
could not match 'MatrixBase<type-parameter-0-0>' against 'double'
EIGEN_STRONG_INLINE Matrix(const MatrixBase<OtherDerived>& other)
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:292:25: note: candidate template ignored:
could not match 'ReturnByValue<type-parameter-0-0>' against 'double'
EIGEN_STRONG_INLINE Matrix(const ReturnByValue<OtherDerived>& other)
^
/usr/include/eigen3/Eigen/src/Core/Matrix.h:303:25: note: candidate template ignored:
could not match 'EigenBase<type-parameter-0-0>' against 'double'
EIGEN_STRONG_INLINE Matrix(const EigenBase<OtherDerived> &other)
^
1 error generated.
which is telling me you cannot call matrix like that, with two 0's as arguments. It's also weird syntax because the MatrixBase class does not have an operator() which you seem to be trying to calling.