I want to use automatic differentiation mechanism provided by
CppAD inside Eigen linear algebra. An example type is
Eigen::Matrix< CppAD::AD,-1,-1>. As CppAD::AD is a custom numeric type
the NumTraits for this type have to be provided. CppAD provides
those in the file cppad/example/cppad_eigen.hpp. This makes the
following minimal example compile:
#include <cppad/cppad.hpp>
#include <cppad/example/cppad_eigen.hpp>
int main() {
typedef double Scalar;
typedef CppAD::AD<Scalar> AD;
// independent variable vector
Eigen::Matrix<AD,Eigen::Dynamic,1> x(4);
CppAD::Independent(x);
// dependent variable vector
Eigen::Matrix<AD,Eigen::Dynamic,1> y(4);
Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> m(4,4);
m.setIdentity();
y = 1. * x;
// THIS DOES NOT WORK
// y = m * x;
CppAD::ADFun<Scalar> fun(x, y);
}
As soon as some more complex expression is used, e.g. the
mentioned
y = m * x;
the code fails to compile:
PATH/Eigen/latest/include/Eigen/src/Core/Product.h:29:116: error:
no type named 'ReturnType' in 'Eigen::ScalarBinaryOpTraits<double, CppAD::AD<double>,
Eigen::internal::scalar_product_op<double, CppAD::AD<double> > >'
...typename ScalarBinaryOpTraits<typename traits<LhsCleaned>::Scalar, typename traits<RhsCleaned>::Scalar>::ReturnType...
If i manually cast the double Matrix to AD, it works. However this
is not a solution because the type promotion is virtually used
everywhere in Eigen.
It looks to me as if the NumTraits provided by CppAD are not sufficient for this case. This is supported by a followup error message:
PATH/Eigen/latest/include/Eigen/src/Core/Product.h:155:5: error:
no type named 'CoeffReturnType' in
'Eigen::internal::dense_product_base<Eigen::Matrix<double, -1, -1, 0, -1, -1>,
Eigen::Matrix<CppAD::AD<double>, -1, 1, 0, -1, 1>, 0, 7>'
EIGEN_DENSE_PUBLIC_INTERFACE(Derived)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Other use cases lead to error messages like:
PATH/Eigen/src/Core/functors/Binary
Functors.h:78:92: error: no type named ‘ReturnType’ in ‘struct Eigen::ScalarBinaryOpTraits<dou
ble, CppAD::AD<double>, Eigen::internal::scalar_product_op<double, CppAD::AD<double> > >’
Can anybody point me in the correct direction? It is possible that the NumTraits are for old Eigen Versions. I'm using 3.3.2 and CppAD from the
current master branch.
If you want to multiply a Matrix<CppAD::AD<double>, ...> by a Matrix<double, ...> you also need to specialize the corresponding ScalarBinaryOpTraits:
namespace Eigen {
template<typename X, typename BinOp>
struct ScalarBinaryOpTraits<CppAD::AD<X>,X,BinOp>
{
typedef CppAD::AD<X> ReturnType;
};
template<typename X, typename BinOp>
struct ScalarBinaryOpTraits<X,CppAD::AD<X>,BinOp>
{
typedef CppAD::AD<X> ReturnType;
};
} // namespace Eigen
This requires that CppAD::AD<X>() * X() is implemented.
Alternatively, you need to cast your matrix m to AD:
// should work:
y = m.cast<CppAD::AD<double> >() * x;
Related
This is my code:
struct Base
{
float value;
};
struct Metre
{
Base base;
};
struct Distance
{
std::array<Metre, 4> distances;
};
std::array<float, 4> values{10.0, 11.23, 12.34, 23.45 };
Distance dist;
std::copy(std::cbegin(values), std::cend(values), std::begin(dist.distances)->base.value);
Need to copy values into dist.distances[]->base.value and also from dist.distances[]->base.value to values
Getting compiler error:
/usr/include/c++/7/bits/stl_algobase.h:377:57: error: no type named ‘value_type’ in ‘struct std::iterator_traits<float>’
typedef typename iterator_traits<_II>::value_type _ValueTypeI;
^~~~~~~~~~~
/usr/include/c++/7/bits/stl_algobase.h:379:64: error: no type named ‘iterator_category’ in ‘struct std::iterator_traits<float>’
typedef typename iterator_traits<_II>::iterator_category _Category;
I suppose your intention is copy the values from the values array in the dist.distances array.
A possible solution pass through std::transform()
std::transform(values.cbegin(), values.cend(), dist.distances.begin(),
[](float f){ return Metre{ Base{f} }; });
-- EDIT --
The OP asks
how to copy from dist.distances to values?
Again: with std::transform()
std::transform(dist.distances.cbegin(), dist.distances.cend(), values.begin(),
[](Metre const & m){ return m.base.value; });
I have a templated matrix library called CMatrix which interfaces with Eigen library for some functions. In order to switch between libraries I have a simple function:
template <typename T>
MatrixXd CMatrix<T>::ToMatrixXd()
{
const int nrow=m_row;
const int ncol=m_column;
MatrixXd matrixXd(nrow,ncol);
for(unsigned int i=0;i<nrow;i++)
for(unsigned int j=0;j<ncol;j++)
matrixXd(i,j)=GetCellValue(i,j);
return matrixXd;
}
Here the typename T is atomic types such as double, float...
I call this function in another function as:
MatrixXd eigMat=m.ToMatrixXd();
I get the following error message:
const math::CMatrix <double> as 'this' argument of 'Eigen::MatrixXd math::CMatrix<T>::ToMatrixXd() [with T = double; Eigen::MatrixXd = Eigen::Matrix <double, -1, -1>] discards qualifiers [-fpermissive]
It seems that number of rows and columns stay as negative which does not make sense. I tried:
MatrixXd eigMat(nrow,ncolumn) //both nrow and ncolumn positive
eigMat=m.ToMatrixXd();
I still get the above-mentioned error message. What could be going on wrong?
**const** math::CMatrix <double> as 'this' argument
It seems that the m in MatrixXd eigMat=m.ToMatrixXd(); is const but
template <typename T> MatrixXd CMatrix<T>::ToMatrixXd() is not a const method.
I am having an issue using an incomplete templated type. I have searched quite a while for a solution but every answer I have found has tended to be along the lines of "include the header," "forward declare," or "you can't do that with STL." I have a feeling that I am looking for the wrong thing or that the first dozen pages of Google are flooded
While I definitely am looking for a fix, I would very much appreciate an explanation, or perhaps a link to a good guide. I am fairly new to heavily templated OOP and would love to learn what is wrong, how it is wrong and why.
So I am going to attempt to include AS MUCH code as possible without giving you guys multiple 500 line files. Ellipses are where I removed code that has nothing to do with this issue (or where I removed other direction iterations and larger stencils). Also, SpatialOps is the library we use for spatial operations. Everything links fine, everything compiles fine via CMake, etc, if I remove the code that I am posting here.
Starting with the error message:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
struct OneSidedOpTypeBuilder;
Here is the offending header file in LBMS (our code base). Operators.h =>
#ifndef LBMSOperators_h
#define LBMSOperators_h
#include <spatialops/structured/stencil/FVStaggeredBCOp.h>
#include <spatialops/structured/stencil/FVStaggeredOperatorTypes.h>
#include <spatialops/structured/stencil/OneSidedOperatorTypes.h>
...
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>
/**
* \file Operators.h
* \brief Defines operators for use in LBMS.
*/
namespace SpatialOps{
class OperatorDatabase; // forward declaration
}
namespace SpatialOps{
...
typedef SpatialOps::OneSidedStencil2< SpatialOps::UnitTriplet<SpatialOps::XDIR>::type > X2PlusT;
typedef SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, X2PlusT, LBMS::XVolField> X2PosX;
...
} // namespace SpatialOps
#endif // LBMSOperators_h
And its corresponding cpp file. Operators.cpp =>
#include "Operators.h"
...
//--- SpatialOps Headers ---//
#include <spatialops/OperatorDatabase.h>
#include <spatialops/structured/stencil/StencilBuilder.h>
#include <spatialops/Nebo.h>
using namespace SpatialOps;
...
namespace LBMS{
...
void
build_operators( const BundlePtr& bundle )
{
SpatialOps::OperatorDatabase& opDB = bundle->operator_database();
const double dx = bundle->spacing(XDIR);
NeboStencilCoefCollection<2> coefHalfDx2Plus = build_two_point_coef_collection( -1.0/dx, 1.0/dx );
...
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
...
}
} // namespace LBMS
This is the header from the library that contains the operators that I am trying to utilize (again, in LBMS). OneSidedOperatorTypes.h =>
#ifndef SpatialOps_structured_OneSidedOpTypes_h
#define SpatialOps_structured_OneSidedOpTypes_h
#include <spatialops/SpatialOpsDefs.h>
#include <spatialops/Nebo.h>
namespace SpatialOps{
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
class OneSidedOpTypeBuilder; // forward declaration
}
/**
* \struct OneSidedStencil2
* \brief Support for one-sided stencils.
* \tparam OpDir the unit vector (a IndexTriplet) that indicates the direction of offset for the stencil.
* \tparam Offset (optional) the offset for the stencil. <0,0,0> (default) results in a
* one-sided stencil that computes into the first stencil point.
* <1,0,0> would offset the stencil so that it effectively computes
* into the <-1,0,0> point.
*
* \par Example:
* This code describes a 2-point stencil oriented in the (+x) direction.
* \code{.cpp}
* OneSidedStencil2< IndexTriplet<1,0,0> >
* \endcode
* It would look something like this:
* \verbatim
1 2 3
Read : o o o
Write: o
\endverbatim
*
* \par Example:
* This code describes a 2-point stencil oriented in the (-x) direction that
* is offset in the (-x) direction.
* \code{.cpp}
* OneSidedStencil2< IndexTriplet<-1,0,0>, IndexTriplet<-1,0,0> >
* \endcode
* It would look something like this:
* \verbatim
n-2 n-1 n
Read : o o
Write: o
\endverbatim
*/
template<typename OpDir, typename Offset=IndexTriplet<0,0,0> >
struct OneSidedStencil2{
typedef OpDir DirT; ///< The orientation of the stencil (IndexTriplet)
typedef typename Add<Offset,OpDir>::result Point2;
typedef NEBO_FIRST_POINT(Offset)::NEBO_ADD_POINT(Point2) StPtCollection;
};
...
/**
* \struct OneSidedOpTypeBuilder
* \ingroup optypes
* \brief Builds OneSidedDiv operator type from field type.
*
* \tparam Op the basic operator type (e.g., Gradient, Interpolant)
* \tparam StencilT the stencil structure (e.g., OneSidedStencil3<IndexTriplet<0,-1,0>)
* \tparam FieldT the field that the operator applies to (e.g., SVolField)
* \tparam Offset the offset for the stencil. <0,0,0> (default) results in a
* one-sided stencil that computes into the first stencil point.
* <1,0,0> would offset the stencil so that it effectively computes
* into the <-1,0,0> point.
*
* \par Example Usage
* The following obtains the full type for a two-point, one-sided stencil
* shifted in the (-z) direction:
* \code
* typedef UnitTriplet<ZDIR>::type::Negate ZMinus;
* typedef OneSidedOpTypeBuilder<Gradient,OneSidedStencil2<ZMinus>,SVolField>::type OneSidedDiv2Z;
* \endcode
*
* Note that we only provide fully specialized versions of this template
* so that unsupported operator types cannot be inadvertently formed.
*/
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
struct OneSidedOpTypeBuilder;
#define BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, StencilT, FieldT ) \
template<> struct OneSidedOpTypeBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >,FieldT>{ \
typedef NeboStencilBuilder<Op,StencilT<IndexTriplet<I1,I2,I3> >::StPtCollection, FieldT, FieldT> type; \
};
#define ONE_SIDED_OP_BUILDERS( Op, I1, I2, I3, FieldT ) \
BUILD_ONE_SIDED_OP_ACROSS_DIRS( Op, I1, I2, I3, OneSidedStencil2, FieldT ) \
...
#define BUILD_ONE_SIDED_STENCILS( FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 1, 0, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, -1, 0, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 1, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0,-1, 0, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 0, 1, FieldT ) \
ONE_SIDED_OP_BUILDERS( Gradient, 0, 0,-1, FieldT )
...
BUILD_ONE_SIDED_STENCILS( XVolField )
...
} // namespace SpatialOps
#endif // SpatialOps_structured_OneSidedOpTypes_h
If I forward declare in the Operators.h, such as
namespace SpatialOps{
template<typename Op, typename StencilT, typename FieldT>
struct OneSidedOpTypeBuilder; // forward declaration
}
then I see the following error message:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:9: error: redefinition of default argument for ‘class Offset’
class OneSidedOpTypeBuilder; // forward declaration
Or if I include the default template argument in the forward declare in Operators.h,
I get the following error:
[ 30%] Building CXX object src/CMakeFiles/lbms.dir/lbms/ProblemSolver.cpp.o
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/transport/TransportEquationBase.h:40:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:38,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:28:10: error: redefinition of default argument for ‘class Offset’
struct OneSidedOpTypeBuilder; // forward declaration
^
In file included from /scratch/local/prism_large/dac/debugging/nscbcbuild/include/nscbc/NSCBCToolsAndDefs.h:18:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/BCOptions.h:43,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.h:30,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/lbms/ProblemSolver.cpp:29:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:114:61: note: original definition appeared here
template<typename Op, typename StencilT, typename FieldT, typename Offset=IndexTriplet<0,0,0> >
Or if I do not include the default template argument, I am back to the beginning with:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp: In function ‘void LBMS::build_operators(const BundlePtr&)’:
/scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:154:96: error: invalid use of incomplete type ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
opDB.register_new_operator<SpatialOps::X2PosX>( new SpatialOps::X2PosX( coefHalfDx2Plus ) );
^
In file included from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.h:6:0,
from /scratch/local/prism_large/dac/debugging/LBMS2/src/operators/Operators.cpp:1:
/scratch/local/prism_large/dac/debugging/spatialopsbuild/include/spatialops/structured/stencil/OneSidedOperatorTypes.h:115:10: error: declaration of ‘SpatialOps::X2PosX {aka struct SpatialOps::OneSidedOpTypeBuilder<SpatialOps::Gradient, SpatialOps::OneSidedStencil2<SpatialOps::IndexTriplet<1, 0, 0> >, SpatialOps::SpatialField<LBMS::XVol, double> >}’
struct OneSidedOpTypeBuilder;
^
Please let me know if there is anything else I should include. On one hand, I very well understand the importance of including everything but on the other, some of these libraries are quite large.
Thanks a bunch!
Searching on the web for your OneSidedOpTypeBuilder class I found the header file where it's defined. If you look in that file you'll see below the forward reference that there is a preprocessor macro for creating template specializations.
#define ONE_SIDED_OP_BUILDER( OP, STYLE, FIELD ) \
template<> \
struct OneSidedOpTypeBuilder<OP,FIELD>{ \
typedef NeboStencilBuilder<OP, \
STYLE<OP,FIELD>::StPtCollection, \
FIELD, \
FIELD> \
type; \
};
I believe you're using OneSidedOpTypeBuilder incorrectly and need to do something like
ONE_SIDED_OP_BUILDER(SpatialOps::Gradient, X2PlusT, LBMS::XVolField);
before the typedef for your X2PosX type.
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;)
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.