簡體   English   中英

無法使用 glm::vec2 作為矩陣的標量類型並使用線性最小二乘法求解

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

我已經閱讀了https://eigen.tuxfamily.org/dox/structEigen_1_1NumTraits.htmlhttps://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html並編寫了我認為合適的代碼,但顯然不是。 我正在嘗試使用 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

這是代碼:

#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

我等了整整 24 小時才發布問題,然后設法在發布后的幾個小時內讓它工作。 這就是人生。 以下解決方案與原始解決方案略有不同,因為我已切換到求解正規方程,而不是使用 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