3

我正在尝试将 Boost.Units 与 Eigen 3.3.1 一起使用,但是在按照此处的说明以及在周围找到的一些信息之后,我仍然无法弄清楚如何使 norm() 工作。

这是我到目前为止所拥有的(对于长代码块感到抱歉):

#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),并出现类似错误

无法转换“boost::units::sqrt...(一些无法解读的模板错误)”

无法转换“Eigen::internal::abs2_impl ...(一些晦涩的模板错误)”

4

1 回答 1

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

如上所示,Eigen3norm()函数利用squaredNorm(). 但是,squaredNorm()要求返回类型的声明应该与矩阵元素类型相同Derived,这意味着返回值单位应该与矩阵元素单位相同。例如,一个米单位的位移向量,它的squaredNorm应该返回一个以meter_squared为单位的值,这与声明冲突。因此,在不改变 Eigen 的实现的情况下,可能无法使用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

于 2018-02-13T16:30:42.930 回答