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

Customise Eigen::Matrix with user-defined type

Tags: c, boost, eigen3 c, boost, eigen3 c, boost, eigen3
(comma "," separated)
dfenucci
Registered Member
Posts
1
Karma
0
I am trying to use boost units as scalar types of eigen3 vectors / arrays (the version of eigen I'm currently using is 3.3.4).
For simplicity, I will use a dummy `my_type` from now on, but the logic is the same.

Following and putting together the indication found in this eigen3 documentation page, and in this answer, I managed to adapt scalar operations (see the sample code below, where I put the product as an example) mixing `my_type` and `Eigen::Matrix/Array`.

Now I am trying to extend it to matrix operation (row-to-column product, coefficient-wise product, etc.), but I'm getting several compilation errors.
Compiling the following sample code:
Code: Select all
    #include <iostream>
    #include <eigen3/Eigen/Core>
   
    class my_type
    {
    public:
        explicit my_type(double a=0) : a_(a) { }
       
        my_type(const my_type& other) { *this = other; }
   
        friend const my_type operator+ (const my_type &lhs, double rhs) { return my_type(lhs.a_+rhs); }
   
        friend const my_type operator+ (double lhs, const my_type &rhs) { return my_type(rhs.a_+lhs); }
   
        friend const my_type operator+ (const my_type &lhs, const my_type &rhs) { return my_type(lhs.a_+rhs.a_); }
   
        friend const my_type operator* (const my_type &lhs, double rhs) { return my_type(lhs.a_*rhs); }
   
        friend const my_type operator* (double lhs, const my_type &rhs) { return my_type(rhs.a_*lhs); }
   
        friend const my_type operator* (const my_type &lhs, const my_type &rhs) { return my_type(lhs.a_*rhs.a_); }
   
        friend std::ostream& operator<<(std::ostream &os, const my_type &rhs)
        {
            os << rhs.a_;
            return os;
        }
   
        operator double() const { return a_; }
    private:
        double a_;
    };
   
   
    my_type log10(const my_type& l)
    {
        return my_type(std::log10(double(l)));
    }
       
    // Eigen customisations for boost::units
    namespace Eigen
    {
        template <>
        struct NumTraits<my_type> : NumTraits<double>
        {
            typedef my_type Real;
            typedef my_type NonInteger;
            typedef my_type Nested;
        };
   
        // Customise sum
        template< typename Scalar >
        struct ScalarBinaryOpTraits< my_type, Scalar, internal::scalar_sum_op< my_type, Scalar> >
        {
            typedef my_type ReturnType;
        };
   
        template< typename Scalar >
        struct ScalarBinaryOpTraits< Scalar, my_type, internal::scalar_sum_op< Scalar, my_type >>
        {
            typedef my_type ReturnType;
        };
   
        template <>
        struct ScalarBinaryOpTraits< my_type, my_type, internal::scalar_sum_op< my_type, my_type >>
        {
            typedef my_type ReturnType;
        };
   
        // Customise product
        template< typename Scalar >
        struct ScalarBinaryOpTraits< my_type, Scalar, internal::scalar_product_op< my_type, Scalar> >
        {
            typedef my_type ReturnType;
        };
   
        template< typename Scalar >
        struct ScalarBinaryOpTraits< Scalar, my_type, internal::scalar_product_op< Scalar, my_type >>
        {
            typedef my_type ReturnType;
        };
   
        template <>
        struct ScalarBinaryOpTraits< my_type, my_type, internal::scalar_product_op< my_type, my_type >>
        {
            typedef my_type ReturnType;
        };
    } // namespace Eigen
   
    int main()
    {
        Eigen::Matrix<my_type, 1, 3> a1;
        a1 << my_type(1.0), my_type(2.0), my_type(3.0);
        Eigen::Matrix<double, 3, 1> d1 = {1,2,3};
        my_type t1(5.0);
   
        std::cout << a1 << std::endl << std::endl;          // Units vector
        std::cout << a1*3.0 << std::endl << std::endl;      // Units vector * scalar
        std::cout << 3.0*a1 << std::endl << std::endl;      // Scalar * units vector
        std::cout << t1*a1 << std::endl << std::endl;       // Units vector * different unit
        std::cout << d1*t1 << std::endl << std::endl;       // Double vector * unit
        //auto s1 = a1*d1;                // ERROR 1
        //auto s1 = a1*a1.transpose();    // ERROR 2
        //auto e1 = s1(0);
    }


with `clang++` v. 6.0.0, I get the following errors (I had to cut them due to the maximum characters number):

**Error 1**
Code: Select all
 In file included from /usr/include/eigen3/Eigen/Core:403:
    /usr/include/eigen3/Eigen/src/Core/functors/BinaryFunctors.h:86:126: error: no viable conversion from returned value of type 'typename internal::enable_if<true, const
          CwiseBinaryOp<internal::scalar_product_op<typename internal::promote_scalar_arg<Scalar, my_type, (Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<my_type, Scalar,
          Eigen::internal::scalar_product_op<my_type, Scalar> > >::value)>::type, typename internal::traits<Matrix<double, 3, 1, 0, 3, 1> >::Scalar>, const typename internal::plain_constant_type<Matrix<double, 3, 1,
          0, 3, 1>, typename internal::promote_scalar_arg<Scalar, my_type, (Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<my_type, Scalar, Eigen::internal::scalar_product_op<my_type, Scalar> >
          >::value)>::type>::type, const Matrix<double, 3, 1, 0, 3, 1> > >::type' (aka 'const Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<my_type, double>, const
          Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<my_type>, const Eigen::Matrix<my_type, 3, 1, 0, 3, 1> >, const Eigen::Matrix<double, 3, 1, 0, 3, 1> >') to function return type 'const
          Eigen::internal::scalar_product_op<my_type, Eigen::Matrix<double, 3, 1, 0, 3, 1> >::result_type' (aka 'const my_type')
      EIGEN_DEVICE_FUNC EIGEN_STRONG_INLINE const result_type operator() (const LhsScalar& a, const RhsScalar& b) const { return a * b; }
                                                                                                                                 ^~~~~
    /usr/include/eigen3/Eigen/src/Core/CoreEvaluators.h:719:12: note: in instantiation of member function 'Eigen::internal::scalar_product_op<my_type, Eigen::Matrix<double, 3, 1, 0, 3, 1> >::operator()' requested
          here
        return m_functor(m_lhsImpl.coeff(index), m_rhsImpl.coeff(index));
               ^
    /usr/include/eigen3/Eigen/src/Core/DenseCoeffsBase.h:144:54: note: in instantiation of member function 'Eigen::internal::binary_evaluator<Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<my_type,
          Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const Eigen::Matrix<my_type, 1, 3, 1, 1, 3>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const
          Eigen::Matrix<Eigen::Matrix<double, 3, 1, 0, 3, 1>, 1, 3, 1, 1, 3> > >, Eigen::internal::IndexBased, Eigen::internal::IndexBased, my_type, Eigen::Matrix<double, 3, 1, 0, 3, 1> >::coeff' requested here
          return internal::evaluator<Derived>(derived()).coeff(index);
                                                         ^
    /usr/include/eigen3/Eigen/src/Core/DenseCoeffsBase.h:181:14: note: in instantiation of member function 'Eigen::DenseCoeffsBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<my_type,
          Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const Eigen::Matrix<my_type, 1, 3, 1, 1, 3>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const
          Eigen::Matrix<Eigen::Matrix<double, 3, 1, 0, 3, 1>, 1, 3, 1, 1, 3> > >, 0>::coeff' requested here
          return coeff(index);
                 ^
    main.cpp:104:17: note: in instantiation of member function 'Eigen::DenseCoeffsBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<my_type, Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const
          Eigen::Matrix<my_type, 1, 3, 1, 1, 3>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<Eigen::Matrix<double, 3, 1, 0, 3, 1> >, const Eigen::Matrix<Eigen::Matrix<double, 3, 1, 0, 3, 1>, 1,
          3, 1, 1, 3> > >, 0>::operator()' requested here
        auto e1 = s1(0);
                    ^
    main.cpp:9:5: note: candidate constructor not viable: no known conversion from 'typename internal::enable_if<true, const CwiseBinaryOp<internal::scalar_product_op<typename internal::promote_scalar_arg<Scalar,
          my_type, (Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<my_type, Scalar, Eigen::internal::scalar_product_op<my_type, Scalar> > >::value)>::type, typename internal::traits<Matrix<double, 3, 1,
          0, 3, 1> >::Scalar>, const typename internal::plain_constant_type<Matrix<double, 3, 1, 0, 3, 1>, typename internal::promote_scalar_arg<Scalar, my_type,
          (Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<my_type, Scalar, Eigen::internal::scalar_product_op<my_type, Scalar> > >::value)>::type>::type, const Matrix<double, 3, 1, 0, 3, 1> > >::type'
          (aka 'const Eigen::CwiseBinaryOp<Eigen::internal::scalar_product_op<my_type, double>, const Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<my_type>, const Eigen::Matrix<my_type, 3, 1, 0, 3, 1>
          >, const Eigen::Matrix<double, 3, 1, 0, 3, 1> >') to 'const my_type &' for 1st argument
        my_type(const my_type& other) { *this = other; }
        ^
    1 warning and 1 error generated.


**Error 2**

Code: Select all
   main.cpp:102:17: error: use of overloaded operator '*' is ambiguous (with operand types 'Eigen::Matrix<my_type, 1, 3>' and 'Eigen::DenseBase<Eigen::Matrix<my_type, 1, 3, 1, 1, 3> >::TransposeReturnType'
          (aka 'Transpose<Eigen::Matrix<my_type, 1, 3, 1, 1, 3> >'))
        auto s1 = a1*a1.transpose();    // ERROR 2
                  ~~^~~~~~~~~~~~~~~
    /usr/include/eigen3/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:50:29: note: candidate function [with T = Eigen::Matrix<my_type, 1, 3, 1, 1, 3>]
    EIGEN_MAKE_SCALAR_BINARY_OP(operator*,product)
                                ^
    /usr/include/eigen3/Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:50:29: note: candidate function [with T = Eigen::Transpose<Eigen::Matrix<my_type, 1, 3, 1, 1, 3> >]
    /usr/include/eigen3/Eigen/src/Core/MatrixBase.h:173:5: note: candidate function [with OtherDerived = Eigen::Transpose<Eigen::Matrix<my_type, 1, 3, 1, 1, 3> >]
        operator*(const MatrixBase<OtherDerived> &other) const;
        ^
    1 error generated.


I found this link that might explain the reason of Error 2, but still I do not understand how to fix or workaround it.

I simplified the question using a dummy type as `Scalar`, reproducing the same errors I had with `boost::units`' types.

Can someone give me a hint on how to fix these issues?
Thank you in advance.


Bookmarks



Who is online

Registered users: bartoloni, Bing [Bot], Google [Bot], Yahoo [Bot]