2017-01-07 3 views
1

Я пытаюсь использовать Boost.Units с Eigen 3.3.1, но после выполнения инструкций here и некоторых информационных данных found around, я до сих пор не могу понять, как сделать норму() Работа.Eigen norm() с Boost.Units

Вот то, что я до сих пор (извините за длинный код блока):

#include <boost/units/quantity.hpp> 
#include <boost/units/systems/si/length.hpp> 
#include <boost/units/systems/si/area.hpp> 
#include <boost/units/cmath.hpp> 
#include <Eigen/Geometry> 

namespace Eigen { 

//specialization of numeric traits 
using boost::units::quantity; 
template <typename Unit, typename Scalar> 
struct NumTraits<quantity<Unit, Scalar>> 
     : GenericNumTraits<quantity<Unit, Scalar>> 
{ 
    typedef quantity<Unit, Scalar> Real; 
    typedef quantity<Unit, Scalar> NonInteger; 
    typedef quantity<Unit, Scalar> Nested; 
    typedef quantity<Unit, Scalar> Literal; 

    static inline Real epsilon() { return quantity<Unit, Scalar>(0); } 
    static inline Real dummy_precision() { return quantity<Unit, Scalar>(1e-6 * Unit()); } 
    static inline Real digits10() { return quantity<Unit, Scalar>(0); } 

    enum { 
     IsComplex = 0, 
     IsInteger = 0, 
     IsSigned = 1, 
     RequireInitialization = 1, 
     ReadCost = 1, 
     AddCost = 3, 
     MulCost = 3 
    }; 
}; 

//specialization of sum operator 
template <typename Unit, typename Scalar> 
struct ScalarBinaryOpTraits<quantity<Unit, Scalar>, quantity<Unit, Scalar>, internal::scalar_sum_op<quantity<Unit, Scalar>, quantity<Unit, Scalar>>> { 
    typedef typename boost::units::add_typeof_helper<quantity<Unit, Scalar>, quantity<Unit, Scalar>>::type ReturnType; 
}; 

//specialization of product operator 
template <typename Unit, typename Scalar> 
struct ScalarBinaryOpTraits<Scalar, quantity<Unit, Scalar>,internal::scalar_product_op<Scalar, quantity<Unit, Scalar>>> { 
    typedef Scalar X; 
    typedef quantity<Unit, Scalar> Y; 
    typedef typename boost::units::multiply_typeof_helper<X, Y>::type ReturnType; 
}; 
template <typename Unit, typename Scalar> 
struct ScalarBinaryOpTraits<quantity<Unit, Scalar>, Scalar, internal::scalar_product_op<quantity<Unit, Scalar>, Scalar>> { 
    typedef quantity<Unit, Scalar> X; 
    typedef Scalar Y; 
    typedef typename boost::units::multiply_typeof_helper<X, Y>::type ReturnType; 
}; 
template <typename Unit, typename Scalar> 
struct ScalarBinaryOpTraits<quantity<Unit, Scalar>, quantity<Unit, Scalar>, internal::scalar_product_op<quantity<Unit, Scalar>, quantity<Unit, Scalar>>> { 
    typedef quantity<Unit, Scalar> X; 
    typedef quantity<Unit, Scalar> Y; 
    typedef typename boost::units::multiply_typeof_helper<X, Y>::type ReturnType; 
}; 

namespace internal { 

//specialization for abs2() 
template<typename Unit, typename Scalar> 
struct abs2_impl<quantity<Unit, Scalar>> 
{ 
    typedef quantity<Unit, Scalar> X; 
    typedef quantity<Unit, Scalar> Y; 
    typedef typename boost::units::multiply_typeof_helper<X, Y>::type ReturnType; 

    EIGEN_DEVICE_FUNC 
    static inline ReturnType run(const quantity<Unit, Scalar>& x) 
    { 
     return x * x; 
    } 
}; 


} // namespace internal 

} // namespace Eigen 

namespace boost { 

namespace units { 

//required functions 
using namespace boost::units::si; 
inline quantity<area, double> abs2(const quantity<length, double>& x) { return x * x; } 

} // namespace units 

} // namespace boost 

int main(int /*argc*/, char** /*argv[]*/) 
{ 
    //unit typedefs 
    using namespace boost::units; 
    using namespace boost::units::si; 
    using Length = quantity<length, double>; 
    using Area = quantity<area, double>; 

    //eigen typedefs 
    using LengthVector = Eigen::Matrix<Length, 3, 1>; 
    using AreaVector = Eigen::Matrix<Area, 3, 1>; 
    using LengthMatrix = Eigen::Matrix<Length, 3, 3>; 

    //test norm 
    LengthVector vector1; 
    Length result4 = vector1.norm(); 
} 

Но это не удается скомпилировать (GCC 5.4.0) с ошибкой, как

не мог преобразовать "повышение :: единиц :: SQRT ... (некоторая расшифровка ошибок шаблона)"

и

не удалось преобразовать "Эйген :: внутренний :: abs2_impl ... (какой-то неясной ошибки шаблон)"

+0

Это потребовало бы несколько нетривиальных реорганизаций внутри Эйгеном. Прежде всего, 'Eigen :: numext :: sqrt' в настоящее время всегда возвращает тот же тип, что и в качестве аргумента (я думаю, это одна из самых простых вещей для исправления). – chtz

ответ

1
template<typename Derived> 
EIGEN_STRONG_INLINE 
typename NumTraits<typename internal::traits<Derived>::Scalar>::Real 
MatrixBase<Derived>::squaredNorm() const 
{ 
    return numext::real((*this).cwiseAbs2().sum()); 
} 

template<typename Derived> 
inline typename NumTraits<typename internal::traits<Derived>::Scalar>::Real 
MatrixBase<Derived>::norm() const 
{ 
    return numext::sqrt(squaredNorm()); 
} 

Как показано выше, Eigen3 norm() функция использует squaredNorm(). Однако в заявлении squaredNorm() требуется, чтобы тип возврата был таким же, как у элемента Matrix типа Derived, что означает, что единицы возвращаемого значения должны быть одинаковыми с элементами матричного элемента. Например, вектор перемещения единиц измерения, его squaredNorm должен возвращать значение с единицей meter_squared, что противоречит объявлению. Таким образом, может быть невозможно использовать squaredNorm() или norm() непосредственно без изменения реализации Eigen.

Моя идея заключается в том, чтобы написать функцию полезности вне Эйгена для реализации squaredNorm(), norm() и normalized():

template<typename T, int Row, int Col> 
EIGEN_STRONG_INLINE 
static T norm(const Eigen::Matrix<T, Row, Col>& m) 
{ 
    return Eigen::numext::sqrt(squared_norm(m)); 
} 

https://github.com/iastate-robotics/eigen3-units

Смежные вопросы