Skip to content

Commit c396b56

Browse files
committed
ADD: 添加eigen LM算法拟合直线示例
1 parent 902c954 commit c396b56

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

eigen/CMakeLists.txt

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
cmake_minimum_required(VERSION 3.10.0)
2+
project(HELLO)
3+
4+
set(CMAKE_BUILD_TYPE "Debug" CACHE STRING "set build type to debug")
5+
set(CMAKE_CXX_FLAGS "-std=c++11")
6+
# set(CMAKE_BUILD_TYPE "Debug")
7+
# SET(CMAKE_CXX_FLAGS_DEBUG "-O0 -Wall")
8+
9+
# eigen
10+
find_package(Eigen3 REQUIRED)
11+
include_directories(${EIGEN3_INCLUDE_DIRS})
12+
13+
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR})
14+
add_executable(eigen lm_regression.cc)
15+

eigen/build.sh

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
cd ./build
3+
cmake ..
4+
make

eigen/lm_regression.cc

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include <iostream>
2+
3+
#include <eigen3/Eigen/Dense>
4+
#include <eigen3/Eigen/Sparse>
5+
6+
#include <eigen3/unsupported/Eigen/NonLinearOptimization>
7+
//#include <unsupported/Eigen/LevenbergMarquardt>
8+
9+
// LM minimize for the model y = a x + b
10+
using Point2DVector = std::vector<Eigen::Vector2d,Eigen::aligned_allocator<Eigen::Vector2d> > ;
11+
12+
Point2DVector GeneratePoints();
13+
14+
// anther example:
15+
// https://stackoverflow.com/questions/18509228/how-to-use-the-eigen-unsupported-levenberg-marquardt-implementation?rq=1
16+
17+
// Generic functor
18+
template<typename _Scalar, int NX = Eigen::Dynamic, int NY = Eigen::Dynamic>
19+
struct Functor
20+
{
21+
// Information that tells the caller the numeric type (eg. double) and size (input / output dim)
22+
typedef _Scalar Scalar;
23+
enum {// Required by numerical differentiation module
24+
InputsAtCompileTime = NX,
25+
ValuesAtCompileTime = NY
26+
};
27+
// Tell the caller the matrix sizes associated with the input, output, and jacobian
28+
typedef Eigen::Matrix<Scalar,InputsAtCompileTime,1> InputType;
29+
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,1> ValueType;
30+
typedef Eigen::Matrix<Scalar,ValuesAtCompileTime,InputsAtCompileTime> JacobianType;
31+
32+
// Local copy of the number of inputs
33+
int m_inputs, m_values;
34+
35+
// Two constructors:
36+
Functor() : m_inputs(InputsAtCompileTime), m_values(ValuesAtCompileTime) {}
37+
Functor(int inputs, int values) : m_inputs(inputs), m_values(values) {}
38+
39+
// Get methods for users to determine function input and output dimensions
40+
int inputs() const { return m_inputs; }
41+
int values() const { return m_values; }
42+
};
43+
44+
45+
struct MyFunctor : Functor<double>
46+
{
47+
// fvec:
48+
int operator()(const Eigen::VectorXd &x, Eigen::VectorXd &fvec) const
49+
{
50+
// "a" in the model is x(0), and "b" is x(1)
51+
for(unsigned int i = 0; i < this->Points.size(); ++i) {
52+
fvec(i) = this->Points[i](1) - (x(0) * this->Points[i](0) + x(1));
53+
}
54+
std::cout<< "optimizing..." << x(0) << " " << x(1) <<std::endl;
55+
return 0;
56+
}
57+
// target(observations)
58+
Point2DVector Points;
59+
60+
int inputs() const { return 2; } // There are two parameters of the model
61+
int values() const { return this->Points.size(); } // The number of observations
62+
};
63+
64+
// https://en.wikipedia.org/wiki/Test_functions_for_optimization
65+
// Booth Function
66+
// Implement f(x,y) = (x + 2*y -7)^2 + (2*x + y - 5)^2
67+
struct BoothFunctor : Functor<double>
68+
{
69+
// Simple constructor
70+
BoothFunctor(): Functor<double>(2,2) {}
71+
72+
// Implementation of the objective function
73+
int operator()(const Eigen::VectorXd &z, Eigen::VectorXd &fvec) const {
74+
double x = z(0); double y = z(1);
75+
/*
76+
* Evaluate the Booth function.
77+
* Important: LevenbergMarquardt is designed to work with objective functions that are a sum
78+
* of squared terms. The algorithm takes this into account: do not do it yourself.
79+
* In other words: objFun = sum(fvec(i)^2)
80+
*/
81+
fvec(0) = x + 2*y - 7;
82+
fvec(1) = 2*x + y - 5;
83+
return 0;
84+
}
85+
};
86+
87+
struct MyFunctorNumericalDiff : Eigen::NumericalDiff<MyFunctor> {};
88+
89+
Point2DVector GeneratePoints(const unsigned int numberOfPoints)
90+
{
91+
Point2DVector points;
92+
// Model y = 2*x + 5 with some noise (meaning that the resulting minimization should be about (2,5)
93+
for(unsigned int i = 0; i < numberOfPoints; ++i)
94+
{
95+
double x = static_cast<double>(i);
96+
Eigen::Vector2d point;
97+
point(0) = x;
98+
point(1) = 2.0 * x + 5.0 + drand48()/10.0;
99+
points.push_back(point);
100+
}
101+
102+
return points;
103+
}
104+
105+
int main(int , char *[])
106+
{
107+
unsigned int numberOfPoints = 50;
108+
Point2DVector points = GeneratePoints(numberOfPoints);
109+
110+
Eigen::VectorXd x(2);
111+
x.fill(1.0f);
112+
113+
MyFunctorNumericalDiff functor;
114+
functor.Points = points;
115+
Eigen::LevenbergMarquardt<MyFunctorNumericalDiff> lm(functor);
116+
117+
Eigen::LevenbergMarquardtSpace::Status status = lm.minimize(x);
118+
std::cout << "status: " << status << std::endl;
119+
120+
//std::cout << "info: " << lm.info() << std::endl;
121+
122+
std::cout << "x that minimizes the function: " << std::endl << x << std::endl;
123+
124+
return 0;
125+
}

0 commit comments

Comments
 (0)