简体   繁体   English

无法使用 glm::vec2 作为矩阵的标量类型并使用线性最小二乘法求解

[英]Unable to use glm::vec2 as the scalar type for a Matrix and solve using Linear Least Squares

I've read https://eigen.tuxfamily.org/dox/structEigen_1_1NumTraits.html and https://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html and written what I think is the appropriate code, but obviously it's not.我已经阅读了https://eigen.tuxfamily.org/dox/structEigen_1_1NumTraits.htmlhttps://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html并编写了我认为合适的代码,但显然不是。 I'm trying to use a glm::vec2 as the scalar type and solve a linear least squares problem, but this is my current error:我正在尝试使用 glm::vec2 作为标量类型并解决线性最小二乘问题,但这是我当前的错误:

[1/4] Automatic MOC for target curves
Generating MOC predefs moc_predefs.h
[2/3] Building CXX object CMakeFiles/curves.dir/src/main.cpp.o
FAILED: CMakeFiles/curves.dir/src/main.cpp.o 
/usr/bin/c++  -DGLM_FORCE_CXX14=1 -DQT_CORE_LIB -DQT_GUI_LIB -DQT_NO_DEBUG -DQT_WIDGETS_LIB -I. -I../ -Icurves_autogen/include -I../glm -I../blaze -isystem /usr/include/qt -isystem /usr/include/qt/QtWidgets -isystem /usr/include/qt/QtGui -isystem /usr/include/qt/QtCore -isystem /usr/lib/qt/mkspecs/linux-g++ -fPIC -std=c++1z -MD -MT CMakeFiles/curves.dir/src/main.cpp.o -MF CMakeFiles/curves.dir/src/main.cpp.o.d -o CMakeFiles/curves.dir/src/main.cpp.o -c ../src/main.cpp
In file included from ../Eigen/SVD:37:0,
                 from ../Eigen/Dense:5,
                 from ../src/lls_solver.hpp:16,
                 from ../src/main.cpp:4:
../Eigen/src/SVD/JacobiSVD.h: In instantiation of ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>& Eigen::JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’:
../Eigen/src/SVD/JacobiSVD.h:548:14:   required from ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>::JacobiSVD(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../Eigen/src/SVD/JacobiSVD.h:799:10:   required from ‘Eigen::JacobiSVD<typename Eigen::DenseBase<Derived>::PlainObject> Eigen::MatrixBase<Derived>::jacobiSvd(unsigned int) const [with Derived = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; typename Eigen::DenseBase<Derived>::PlainObject = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../src/lls_solver.hpp:84:79:   required from ‘vlw::control_points<PointT> vlw::lls_solver(const vlw::control_points<PointT>&, uint32_t, vlw::basis_function_set<PointT>*) [with PointT = glm::vec<2, float, (glm::qualifier)0>; uint32_t = unsigned int]’
../src/main.cpp:180:103:   required from here
../Eigen/src/SVD/JacobiSVD.h:683:29: error: no match for ‘operator/’ (operand types are ‘const MatrixType {aka const Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>}’ and ‘Eigen::JacobiSVD<Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>, 2>::RealScalar {aka float}’)
     m_scaledMatrix = matrix / scale;
                      ~~~~~~~^~~~~~~
In file included from ../Eigen/Core:72:0,
                 from ../src/lls_solver.hpp:15,
                 from ../src/main.cpp:4:
../Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:69:40: note: candidate: template<class T> typename Eigen::internal::enable_if<true, const Eigen::CwiseBinaryOp<Eigen::internal::scalar_quotient_op<typename Eigen::internal::traits<T>::Scalar, typename Eigen::internal::promote_scalar_arg<typename Eigen::internal::traits<T>::Scalar, T, Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<typename Eigen::internal::traits<T>::Scalar, T, Eigen::internal::scalar_quotient_op<typename Eigen::internal::traits<T>::Scalar, T> > >::value>::type>, const Derived, const typename Eigen::internal::plain_constant_type<Derived, typename Eigen::internal::promote_scalar_arg<typename Eigen::internal::traits<T>::Scalar, T, Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<typename Eigen::internal::traits<T>::Scalar, T, Eigen::internal::scalar_quotient_op<typename Eigen::internal::traits<T>::Scalar, T> > >::value>::type>::type> >::type Eigen::MatrixBase<Derived>::operator/(const T&) const [with T = T; Derived = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]
 EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(operator/,quotient)
                                        ^
../Eigen/src/Core/util/Macros.h:941:4: note: in definition of macro ‘EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT’
   (METHOD)(const T& scalar) const { \
    ^~~~~~
../Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:69:40: note:   template argument deduction/substitution failed:
 EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(operator/,quotient)
                                        ^
../Eigen/src/Core/util/Macros.h:941:4: note: in definition of macro ‘EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT’
   (METHOD)(const T& scalar) const { \
    ^~~~~~
../Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h: In substitution of ‘template<class T> typename Eigen::internal::enable_if<true, const Eigen::CwiseBinaryOp<Eigen::internal::scalar_quotient_op<glm::vec<2, float, (glm::qualifier)0>, typename Eigen::internal::promote_scalar_arg<glm::vec<2, float, (glm::qualifier)0>, T, Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<glm::vec<2, float, (glm::qualifier)0>, T, Eigen::internal::scalar_quotient_op<glm::vec<2, float, (glm::qualifier)0>, T> > >::value>::type>, const Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>, const typename Eigen::internal::plain_constant_type<Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>, typename Eigen::internal::promote_scalar_arg<glm::vec<2, float, (glm::qualifier)0>, T, Eigen::internal::has_ReturnType<Eigen::ScalarBinaryOpTraits<glm::vec<2, float, (glm::qualifier)0>, T, Eigen::internal::scalar_quotient_op<glm::vec<2, float, (glm::qualifier)0>, T> > >::value>::type>::type> >::type Eigen::MatrixBase<Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1> >::operator/<T>(const T&) const [with T = float]’:
../Eigen/src/SVD/JacobiSVD.h:683:29:   required from ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>& Eigen::JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../Eigen/src/SVD/JacobiSVD.h:548:14:   required from ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>::JacobiSVD(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../Eigen/src/SVD/JacobiSVD.h:799:10:   required from ‘Eigen::JacobiSVD<typename Eigen::DenseBase<Derived>::PlainObject> Eigen::MatrixBase<Derived>::jacobiSvd(unsigned int) const [with Derived = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; typename Eigen::DenseBase<Derived>::PlainObject = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../src/lls_solver.hpp:84:79:   required from ‘vlw::control_points<PointT> vlw::lls_solver(const vlw::control_points<PointT>&, uint32_t, vlw::basis_function_set<PointT>*) [with PointT = glm::vec<2, float, (glm::qualifier)0>; uint32_t = unsigned int]’
../src/main.cpp:180:103:   required from here
../Eigen/src/Core/../plugins/CommonCwiseBinaryOps.h:69:40: error: no type named ‘type’ in ‘struct Eigen::internal::promote_scalar_arg<glm::vec<2, float, (glm::qualifier)0>, float, false>’
 EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT(operator/,quotient)
                                        ^
../Eigen/src/Core/util/Macros.h:941:4: note: in definition of macro ‘EIGEN_MAKE_SCALAR_BINARY_OP_ONTHERIGHT’
   (METHOD)(const T& scalar) const { \
    ^~~~~~
In file included from /usr/include/qt/QtCore/QMargins:1:0,
                 from /usr/include/qt/QtGui/qwindow.h:46,
                 from /usr/include/qt/QtGui/QWindow:1,
                 from ../src/openglwindow.h:51,
                 from ../src/main.cpp:5:
../Eigen/src/SVD/JacobiSVD.h: In instantiation of ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>& Eigen::JacobiSVD<MatrixType, QRPreconditioner>::compute(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’:
../Eigen/src/SVD/JacobiSVD.h:548:14:   required from ‘Eigen::JacobiSVD<MatrixType, QRPreconditioner>::JacobiSVD(const MatrixType&, unsigned int) [with _MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; int QRPreconditioner = 2; Eigen::JacobiSVD<MatrixType, QRPreconditioner>::MatrixType = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../Eigen/src/SVD/JacobiSVD.h:799:10:   required from ‘Eigen::JacobiSVD<typename Eigen::DenseBase<Derived>::PlainObject> Eigen::MatrixBase<Derived>::jacobiSvd(unsigned int) const [with Derived = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>; typename Eigen::DenseBase<Derived>::PlainObject = Eigen::Matrix<glm::vec<2, float, (glm::qualifier)0>, -1, -1, 1, -1, -1>]’
../src/lls_solver.hpp:84:79:   required from ‘vlw::control_points<PointT> vlw::lls_solver(const vlw::control_points<PointT>&, uint32_t, vlw::basis_function_set<PointT>*) [with PointT = glm::vec<2, float, (glm::qualifier)0>; uint32_t = unsigned int]’
../src/main.cpp:180:103:   required from here

This is the code:这是代码:

#include "basis_function_set.hpp"
#include "control_points.hpp"
#include "knots.hpp"

#include "debug.hpp"

//#include <blaze/Math.h>

#include <cstdint>
#include <iostream>

#include <Eigen/Core>
#include <Eigen/Dense>

namespace Eigen {
template<> struct NumTraits<glm::vec2>
 : NumTraits<double> // permits to get the epsilon, dummy_precision, lowest, highest functions
{
  typedef glm::vec2::value_type Real;
  typedef glm::vec2::value_type NonInteger;
  typedef glm::vec2 Literal;
  typedef glm::vec2 Nested;

  enum {
    IsComplex = 0,
    IsInteger = 0,
    IsSigned = 1,
    RequireInitialization = 1,
    ReadCost = 2,
    AddCost = 2,
    MulCost = 2
  };
};
}
namespace glm {
    inline const vec2& conj(const vec2& x)  { return x; }
    inline const vec2& real(const vec2& x)  { return x; }
    inline vec2 imag(const vec2&)    { return vec2{0.}; }
    inline vec2 abs(const vec2&  x)  { return vec2{fabs(x.x), fabs(x.y)}; }
    inline vec2 abs2(const vec2& x)  { return x*x; }
}


namespace vlw {
    template <typename PointT>
    vlw::control_points<PointT> lls_solver(
        const vlw::control_points<PointT> &data,
        uint32_t cp_size,
        vlw::basis_function_set<PointT> *basis_set
    ) {
        using MatrixVec2 = Eigen::Matrix<PointT, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
        using VectorVec2 = Eigen::Matrix<PointT, Eigen::Dynamic, 1>;
        using ScalarT = typename PointT::value_type;

        const auto N = cp_size;
        const auto M = data.size();
        auto t = uniform_knots<ScalarT>(
            basis_set->get_open_knot_size(cp_size),
            basis_set->get_open_knot_repeated_size(cp_size)
        );
        ScalarT knot_range = ((t[t.size()-1] - t[0])-0.00001);
        MatrixVec2 A( N, M );
        for (uint32_t m = 0; m < M; ++m) {
            for (uint32_t i = 0; i < N; ++i) {
                auto u = static_cast<ScalarT>(m) / (static_cast<ScalarT>(M-1)+0.00001);
                u = (u * knot_range) + t[0];
                auto n = basis_set->get(i)->evaluate(i, u, t);
                PointT p;
                for (uint32_t d = 0; d < PointT::length(); ++d) {
                    p[d] = n;
                }
                A(m, i) = p;
            }
        }
        vlw::control_points<PointT> retval{cp_size, PointT{0.0}};
        VectorVec2 b(M);
        for (uint32_t j = 0; j < data.size(); ++j) {
            b(j) = data[j];
        }
        VectorVec2 x = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
        //MatrixVec2 AtA = A.transpose() * A;
        //VectorVec2 b = A.transpose() * y;
        std::cout << A << std::endl;
        std::cout << "--" << std::endl;
        std::cout << b << std::endl;
        VectorVec2 x = AtA.colPivHouseholderQr().solve(b);
        //std::cout << "--" << std::endl;
        //std::cout << x << std::endl;


        return retval;
    }
}; // end namespace vlw

I waited a full 24 hours before posting the question, and then managed to get it working within hours of posting it.我等了整整 24 小时才发布问题,然后设法在发布后的几个小时内让它工作。 Such is life.这就是人生。 The following solution is slightly different than the original solution in that I've switched to solving the normal equations, rather than using jacobiSVD, but it works.以下解决方案与原始解决方案略有不同,因为我已切换到求解正规方程,而不是使用 jacobiSVD,但它有效。

#include "basis_function_set.hpp"
#include "control_points.hpp"
#include "knots.hpp"

#include "debug.hpp"

//#include <blaze/Math.h>

#include <cstdint>
#include <iostream>

#include <Eigen/Core>
#include <Eigen/Dense>

namespace Eigen {
template<> struct NumTraits<glm::vec2> : GenericNumTraits<glm::vec2>
{
    typedef glm::vec2 ReturnType;
    typedef glm::vec2 Real;
    typedef glm::vec2 NonInteger;
    typedef glm::vec2 Literal;
    typedef glm::vec2 Nested;

    static inline glm::vec2 epsilon() {
        return glm::vec2{
                std::numeric_limits<glm::vec2::value_type>::epsilon(),
                std::numeric_limits<glm::vec2::value_type>::epsilon()
        };
    }
    static inline glm::vec2::value_type digits10() { return std::numeric_limits<glm::vec2::value_type>::digits10; }
    static inline glm::vec2::value_type dummy_precision() { return 0.; }
    static inline glm::vec2 lowest() {
        return glm::vec2{
                std::numeric_limits<glm::vec2::value_type>::min(),
                std::numeric_limits<glm::vec2::value_type>::min()
        };
    }
    static inline glm::vec2 highest() {
        return glm::vec2{
                std::numeric_limits<glm::vec2::value_type>::max(),
                std::numeric_limits<glm::vec2::value_type>::max()
        };
    }
    static inline glm::vec2 infinity() {
        return glm::vec2{
                std::numeric_limits<glm::vec2::value_type>::infinity(),
                std::numeric_limits<glm::vec2::value_type>::infinity()
        };
    }
    static inline glm::vec2 quiet_NaN() {
        return glm::vec2{
                std::numeric_limits<glm::vec2::value_type>::quiet_NaN(),
                std::numeric_limits<glm::vec2::value_type>::quiet_NaN()
        };
    }


    enum {
        IsComplex = 0,
        IsInteger = 0,
        IsSigned = 1,
        RequireInitialization = 1,
        ReadCost = 2,
        AddCost = 2,
        MulCost = 2
    };
};
}
namespace glm {
    inline const vec2& conj(const vec2& x)  { return x; }
    inline const vec2& real(const vec2& x)  { return x; }
    inline vec2::value_type imag(const vec2&)    { return 0.; }
    inline vec2::value_type abs2(const vec2 &x)  { return length2(x)*length2(x); }
    inline vec2 operator/(const vec2 &lhs, float x ) { return vec2{lhs.x/x, lhs.y/x}; }
    inline bool operator<(const vec2 &lhs, const vec2 &rhs) { return length(lhs)<length(rhs); }
    inline bool operator<=(const vec2 &lhs, const vec2 &rhs) { return length(lhs)<=length(rhs); }
    inline bool operator>(const vec2 &lhs, const vec2 &rhs) { return length(lhs)>length(rhs); }
    inline bool operator>= (const vec2 &lhs, const vec2 &rhs) { return length(lhs)>=length(rhs); }
    inline vec2 operator* (long int x, const vec2 &rhs) { return static_cast<glm::vec2::value_type>(x) * rhs; }

}


namespace vlw {
    template <typename PointT>
    vlw::control_points<PointT> lls_solver(
        const vlw::control_points<PointT> &data,
        uint32_t cp_size,
        vlw::basis_function_set<PointT> *basis_set
    ) {
        using MatrixVec2 = Eigen::Matrix<PointT, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor>;
        using VectorVec2 = Eigen::Matrix<PointT, Eigen::Dynamic, 1>;
        using ScalarT = typename PointT::value_type;

        const auto N = cp_size;
        const auto M = data.size();
        auto t = uniform_knots<ScalarT>(
                basis_set->get_open_knot_size(cp_size),
                basis_set->get_open_knot_repeated_size(cp_size)
        );
        ScalarT knot_range = ((t[t.size() - 1] - t[0]) - 0.00001);
        MatrixVec2 A(N, M);
        for (uint32_t m = 0; m < M; ++m) {
            for (uint32_t i = 0; i < N; ++i) {
                auto u = static_cast<ScalarT>(m) / (static_cast<ScalarT>(M - 1) + 0.00001);
                u = (u * knot_range) + t[0];
                auto n = basis_set->get(i)->evaluate(i, u, t);
                PointT p;
                for (uint32_t d = 0; d < PointT::length(); ++d) {
                    p[d] = n;
                }
                A(m, i) = p;
            }
        }
        vlw::control_points<PointT> retval{cp_size, PointT{0.0}};
        VectorVec2 b(M);
        for (uint32_t j = 0; j < data.size(); ++j) {
            b(j) = data[j];
        }
        //VectorVec2 x = A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
        MatrixVec2 AtA = A.transpose() * A;
        b = A.transpose() * b;
//        std::cout << A << std::endl;
//        std::cout << "--" << std::endl;
//        std::cout << b << std::endl;
        VectorVec2 x = AtA.colPivHouseholderQr().solve(b);
        for (uint32_t i = 0; i < x.size(); ++i) {
            PointT cp;
            for (uint32_t d = 0; d < PointT::length(); ++d) {
                cp[d] = x[i][d];
            }
            retval[i] = cp;
        }

        return retval;
    }
}; // end namespace vlw

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM