1

问题:我并不总是知道要使用 Levenberg Marquardt 的雅可比或函数向量的确切大小。因此,我需要在编译时设置它们的尺寸。

预期:在我声明 MyFunctorDense 的一个实例之后。我可以将“InputsAtCompileTime”设置为我的输入大小,并将“ValuesAtCompileTime”设置为我的值大小。然后我的雅可比矩阵 aFjac 应该有维度 tValues x tInputs,而我的函数向量 aH 应该有维度 tValues x 1。

观察到在此处输入图像描述

.h 文件

 #pragma once

 #include "stdafx.h"
 #include <iostream>

 #include <unsupported/Eigen/LevenbergMarquardt>
 #include <unsupported/Eigen/NumericalDiff>


 //Generic functor
 template <typename _Scalar, typename _Index>
 struct MySparseFunctor
 {
    typedef _Scalar Scalar;
    typedef _Index Index;
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> InputType;
    typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> ValueType;
    typedef Eigen::SparseMatrix<Scalar, Eigen::ColMajor, Index> 
  JacobianType;
     typedef Eigen::SparseQR<JacobianType, Eigen::COLAMDOrdering<int> > 
  QRSolver;
    enum {
       InputsAtCompileTime = Eigen::Dynamic,
       ValuesAtCompileTime = Eigen::Dynamic
     };

    MySparseFunctor(int inputs, int values) : m_inputs(inputs), 
m_values(values) {}

    int inputs() const { return m_inputs; }
    int values() const { return m_values; }

    const int m_inputs, m_values;


};

template <typename _Scalar, int NX=Eigen::Dynamic, int NY=Eigen::Dynamic>
struct MyDenseFunctor
{
  typedef _Scalar Scalar;
  enum {
    InputsAtCompileTime = NX,
    ValuesAtCompileTime = NY
  };
  typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
  typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> 
JacobianType;
   typedef Eigen::ColPivHouseholderQR<JacobianType> QRSolver;
  const int m_inputs, m_values;

   MyDenseFunctor() : m_inputs(InputsAtCompileTime), 
 m_values(ValuesAtCompileTime) {}
  MyDenseFunctor(int inputs, int values) : m_inputs(inputs), 
m_values(values) {}

  int inputs() const { return m_inputs; }
  int values() const { return m_values; }

};


 struct MyFunctorSparse : MySparseFunctor<double, int>
 {
    MyFunctorSparse(void) : MySparseFunctor<double, int>(2 , 2) {}

   int operator()(const Eigen::VectorXd &aX,  //Input 
              Eigen::VectorXd &aF) const; //Output 
   int df(const InputType &aF, JacobianType& aFjac);
};


struct MyFunctorDense : MyDenseFunctor<double>
 {
   MyFunctorDense(void) : MyDenseFunctor<double>( Eigen::Dynamic , 
Eigen::Dynamic) {}

   int operator()(const InputType &aX,  //Input 
              ValueType &aF) const; //Output 

   int df(const InputType &aX, JacobianType& aFjac);
 };

.cpp 文件 #pragma once #include "stdafx.h" #include "Main.h"

int MyFunctorSparse::operator()(const Eigen::VectorXd &aX,        //Input 
                            Eigen::VectorXd &aF) const        //Output 
{
         //F = aX0^2 + aX1^2  
     aF(0) = aX(0)*aX(0) +  aX(1)*aX(1);
     aF(1) = 0;

  return 0;
 }

int MyFunctorDense::operator()(const InputType &aX,        //Input 
                            ValueType &aF) const       //Output 
 {
//F = aX0^2 + aX1^2
for (int i = 0; i < aF.size(); i++)
{
  aF(i) = i*aX(0)*aX(0) + i*(aX(1)-1)*(aX(1)-1);
}


  return 0;
}


 int MyFunctorSparse::df(const InputType &aX, JacobianType& aFjac)
 {
   aFjac.coeffRef(0, 0) = 2*aX(0);
   aFjac.coeffRef(0, 1) = 2*aX(1);
   aFjac.coeffRef(1, 0) = 0.0;
   aFjac.coeffRef(1, 1) = 0.0;

   return 0;
}

 int MyFunctorDense::df(const InputType &aX, JacobianType& aFjac)
{
   for(int i = 0; i< aFjac.size(); i++)
   {
   aFjac(i, 0) = 2*i*aX(0);
   aFjac(i, 1) = 2*i*(aX(1)-1);
   }
   return 0; 
}

int main(int argc, char *argv[])
{
   int input;
   std::cout << "Enter 1 to run LM with DenseFunctor, Enter 2 to run LM with 
SparseFunctor: " << std::endl;
std::cin >> input;

   Eigen::VectorXd tX(2);
   tX(0) = 10;
   tX(1) = 0.5;
   int tInputs = tX.rows();
   int tValues = 60928;

   std::cout << "tX: " << tX << std::endl;

   if (input == 1)
   {
  MyFunctorDense myDenseFunctor;
  tInputs = myDenseFunctor.inputs();
  tValues = myDenseFunctor.values();

  std::cout << "tInputs  : " << tInputs << std::endl;
  std::cout << "tValues  : " << tValues << std::endl;

  Eigen::LevenbergMarquardt<MyFunctorDense> lm(myDenseFunctor);
  lm.setMaxfev(30);
  lm.setXtol(1e-5);
  lm.minimize(tX);
   }

  if (input == 2)
  {
  MyFunctorSparse myFunctorSparse;
  //Eigen::NumericalDiff<MyFunctor> numDiff(myFunctor);
  //Eigen::LevenbergMarquardt<Eigen::NumericalDiff<MyFunctor>,double> 
  lm(numDiff);

  Eigen::LevenbergMarquardt<MyFunctorSparse> lm(myFunctorSparse);
  lm.setMaxfev(2000);
  lm.setXtol(1e-10);

  lm.minimize(tX);
  }

   std::cout << "tX minimzed: " << tX << std::endl;

   return 0;
}
4

1 回答 1

1

解决方案:我发现了我的问题。我更换了:

const int m_inputs, m_values;

int m_inputs, m_values;

在“.h”文件中,这使得 struct MyFunctorDense 的成员变量可修改。所以,然后在“.cpp”下面的行

std::cout << "tX: " << tX << std::endl;

我补充说:

 Eigen::VectorXd tF(60928);

因为这是一个维度为 60928x1 的测试函数向量。因此,我可以放入任意 nx1 维度。

然后在该行下方:

MyFunctorDense myDenseFunctor; 

我补充说:

  myDenseFunctor.m_inputs = tX.rows();
  myDenseFunctor.m_values = tF.rows();

现在我得到结果:

在此处输入图像描述

于 2017-12-27T19:53:07.133 回答