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