Ошибка в матричных операциях при настройке Eigen :: Matrix с пользовательским типом - PullRequest
0 голосов
/ 25 марта 2020

Я пытаюсь использовать бустовые единицы в качестве скалярных типов eigen3 векторов / массивов. Для простоты я буду использовать фиктивный my_type с этого момента, но логика c будет такой же.

Следуя и составляя указание, найденное на этой странице документации eigen3 , и в этом ответе мне удалось адаптировать скалярные операции (см. пример кода ниже, где я поставил продукт в качестве примера), смешивая my_type и Eigen::Matrix/Array.

Теперь я я пытаюсь распространить его на матричную операцию (произведение строк на столбцы, произведение на коэффициенты и т. д. c.), но получаю несколько ошибок компиляции. Скомпилировав следующий пример кода:

#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);
}

с clang++ v. 6.0.0, я получаю следующие ошибки (мне пришлось их обрезать из-за максимального количества символов):

Ошибка 1

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.

Ошибка 2

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.

Может кто-нибудь подсказать, как решить эти проблемы?

Заранее спасибо.

РЕДАКТИРОВАТЬ

Я нашел эту ссылку , которая может объяснить причину ошибки 2, но Тем не менее я не понимаю, как исправить или обойти это.

РЕДАКТИРОВАТЬ 2

Я упростил вопрос, используя фиктивный тип как Scalar, воспроизводя те же ошибки, которые я имел с boost::units 'типами.

...