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

C++ 无法使用glm::vec2作为矩阵的标量类型,无法使用线性最小二乘法进行求解,c++,eigen,C++,Eigen,我已经阅读并编写了我认为合适的代码,但显然不是。我试图使用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

我已经阅读并编写了我认为合适的代码,但显然不是。我试图使用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
[1/4]目标曲线的自动MOC
生成MOC predefs MOC_predefs.h
[2/3]构建CXX对象CMakeFiles/curves.dir/src/main.cpp.o
失败:cmakfiles/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./-Icurves_autogen/include-I../glm-I../blaze-isystem/usr/include/qt/qt/qt WIDGETS-isystem/usr/include/qt/qt/qt/qt-GUI-isystem/usr/include/qt/qt/qt/QtCore-isystem/usr/usr/include/qt/qt/qt/qt/QtCore-isystem/usr/usr/usr/qCMakeFiles/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
在../Eigen/SVD:37:0中包含的文件中,
from../Eigen/Dense:5,
来自../src/lls_solver.hpp:16,
from../src/main.cpp:4:
../Eigen/src/SVD/JacobiSVD.h:在“Eigen::JacobiSVD&Eigen::JacobiSVD::compute(const MatrixType&,unsigned int)”的实例化中,[使用_MatrixType=Eigen::Matrix;int qr预处理器=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]:
../Eigen/src/SVD/JacobiSVD.h:548:14:来自“Eigen::JacobiSVD::JacobiSVD(const MatrixType&,unsigned int)[with _MatrixType=Eigen::Matrix;int qr预条件=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]”的必填项
../Eigen/src/SVD/JacobiSVD.h:799:10:来自“Eigen::JacobiSVD Eigen::MatrixBase::JacobiSVD(unsigned int)const[with Derived=Eigen::Matrix;typename Eigen::DenseBase::PlainObject=Eigen::Matrix]的必填项
../src/lls_solver.hpp:84:79:从“vlw::control_points vlw::lls_solver(常量vlw::control_points&,uint32_t,vlw::basis_function_set*)[带点t=glm::vec;uint32_t=unsigned int]中需要
../src/main.cpp:180:103:此处为必填项
../eigent/src/SVD/JacobiSVD.h:683:29:错误:与“运算符/”不匹配(操作数类型为“常量矩阵类型{aka const eigent::Matrix}”和“eigent::JacobiSVD::RealScalar{aka float}”)
m_scaledMatrix=矩阵/比例;
~~~~~~~^~~~~~~
在../Eigen/Core:72:0中包含的文件中,
来自../src/lls_solver.hpp:15,
from../src/main.cpp:4:
../Eigen/src/Core/。/plugins/CommonCwiseBinaryOps.h:69:40:注:候选:模板typename Eigen::internal::enable_if::type Eigen::MatrixBase::operator/(const T&)const[带T=T;派生=Eigen::Matrix]
本征值(运算符/,商)
^
../Eigen/src/Core/util/Macros.h:941:4:注意:在宏“Eigen\u MAKE\u SCALAR\u BINARY\u OP\u ONTHERIGHT”的定义中
(方法)(常数T和标量)常数{\
^~~~~~
../Eigen/src/Core/。/plugins/CommonCwiseBinaryOps.h:69:40:注意:模板参数推导/替换失败:
本征值(运算符/,商)
^
../Eigen/src/Core/util/Macros.h:941:4:注意:在宏“Eigen\u MAKE\u SCALAR\u BINARY\u OP\u ONTHERIGHT”的定义中
(方法)(常数T和标量)常数{\
^~~~~~
../Eigen/src/Core/。/plugins/CommonCwiseBinaryOps.h:替换“模板类型名称Eigen::internal::enable_if::type Eigen::MatrixBase::operator/(const T&)const[with T=float]:
../Eigen/src/SVD/JacobiSVD.h:683:29:需要自“Eigen::JacobiSVD&Eigen::JacobiSVD::compute(const MatrixType&,unsigned int)[with _MatrixType=Eigen::Matrix;int qr预处理程序=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]”
../Eigen/src/SVD/JacobiSVD.h:548:14:来自“Eigen::JacobiSVD::JacobiSVD(const MatrixType&,unsigned int)[with _MatrixType=Eigen::Matrix;int qr预条件=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]”的必填项
../Eigen/src/SVD/JacobiSVD.h:799:10:来自“Eigen::JacobiSVD Eigen::MatrixBase::JacobiSVD(unsigned int)const[with Derived=Eigen::Matrix;typename Eigen::DenseBase::PlainObject=Eigen::Matrix]的必填项
../src/lls_solver.hpp:84:79:从“vlw::control_points vlw::lls_solver(常量vlw::control_points&,uint32_t,vlw::basis_function_set*)[带点t=glm::vec;uint32_t=unsigned int]中需要
../src/main.cpp:180:103:此处为必填项
../Eigen/src/Core/。/plugins/CommonCwiseBinaryOps.h:69:40:错误:在“struct Eigen::internal::promote\u scalar\u arg”中没有名为“type”的类型
本征值(运算符/,商)
^
../Eigen/src/Core/util/Macros.h:941:4:注意:在宏“Eigen\u MAKE\u SCALAR\u BINARY\u OP\u ONTHERIGHT”的定义中
(方法)(常数T和标量)常数{\
^~~~~~
在/usr/include/qt/QtCore/QMargins:1:0中包含的文件中,
从/usr/include/qt/QtGui/qwindow.h:46,
从/usr/include/qt/QtGui/QWindow:1,
从../src/openglwindow.h:51,
从../src/main.cpp:5:
../Eigen/src/SVD/JacobiSVD.h:在“Eigen::JacobiSVD&Eigen::JacobiSVD::compute(const MatrixType&,unsigned int)”的实例化中,[使用_MatrixType=Eigen::Matrix;int qr预处理器=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]:
../Eigen/src/SVD/JacobiSVD.h:548:14:来自“Eigen::JacobiSVD::JacobiSVD(const MatrixType&,unsigned int)[with _MatrixType=Eigen::Matrix;int qr预条件=2;Eigen::JacobiSVD::MatrixType=Eigen::Matrix]”的必填项
../Eigen/src/SVD/JacobiSVD.h:799:10:来自“Eigen::JacobiSVD Eigen::MatrixBase::JacobiSVD(unsigned int)const[with Derived=Eigen::Matrix;typename Eigen::DenseBase::PlainObject=Eigen::Matrix]的必填项
../src/lls_solver.hpp:84:79:从“vlw::control_points vlw::lls_solver(常量vlw::control_points&,uint32_t,vlw::basis_function_set*)[带点t=glm::vec;uint32_t=unsigned int]中需要
..
#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
#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