2017-01-07 6 views
1

Ich versuche, Boost.Units mit Eigen 3.3.1, aber nach der Befolgung der Anweisungen here, und einige Informationen found around, ich kann immer noch nicht herausfinden, wie man norm() Arbeit. HierEigen Norm() mit Boost.Units

ist, was ich bisher (sorry für den langen Code-Block) haben:

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

Aber dies nicht kompilieren (gcc 5.4.0) mit einem Fehler wie

konnte nicht konvertieren "boost :: Einheiten :: sqrt ... (einig undecipherable Vorlage Fehler)"

und

nicht "Eigen :: internal :: abs2_impl ... (einige obskure Vorlage Fehler)" umwandeln könnte

+0

Dies würde mehrere nicht-triviale Refactorings innerhalb Eigen erfordern. Zuallererst gibt 'Eigen :: numext :: sqrt' zur Zeit immer den gleichen Typ zurück, wie er als Argument erhalten wird (ich denke, das ist eines der einfacheren Dinge, die zu beheben sind). – chtz

Antwort

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

Wie oben macht Eigen3 gezeigt norm() Funktion Gebrauch des squaredNorm(). Die Deklaration von squaredNorm() erfordert jedoch, dass der Rückgabetyp für den Matrixelementtyp Derived derselbe sein sollte, was bedeutet, dass die Rückgabewerteinheiten für die Matrixelementeinheiten identisch sein sollten. Zum Beispiel sollte ein Verschiebungsvektor von Metereinheiten seine quadrierteNorm einen Wert mit der Einheit Meter_squared zurückgeben, der mit der Deklaration in Konflikt steht. Daher ist es möglicherweise nicht möglich, squaredNorm() oder norm() direkt zu verwenden, ohne die Implementierung von Eigen zu ändern.

Meine Idee ist es, eine Hilfsfunktion zu schreiben außerhalb von Eigen squaredNorm() zu implementieren, norm() und 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