1 // This file is part of Eigen, a lightweight C++ template library
2 // for linear algebra.
3 //
4 // Copyright (C) 2012 Desire Nuentsa <desire.nuentsa_wakam@inria.fr>
5 // Copyright (C) 2012 Gael Guennebaud <gael.guennebaud@inria.fr>
6 //
7 // This Source Code Form is subject to the terms of the Mozilla
8 // Public License v. 2.0. If a copy of the MPL was not distributed
9 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11 #include <iostream>
12 #include <fstream>
13 #include <iomanip>
14
15 #include "main.h"
16 #include <Eigen/LevenbergMarquardt>
17 using namespace std;
18 using namespace Eigen;
19
20 template<typename Scalar>
21 struct DenseLM : DenseFunctor<Scalar>
22 {
23 typedef DenseFunctor<Scalar> Base;
24 typedef typename Base::JacobianType JacobianType;
25 typedef Matrix<Scalar,Dynamic,1> VectorType;
26
DenseLMDenseLM27 DenseLM(int n, int m) : DenseFunctor<Scalar>(n,m)
28 { }
29
modelDenseLM30 VectorType model(const VectorType& uv, VectorType& x)
31 {
32 VectorType y; // Should change to use expression template
33 int m = Base::values();
34 int n = Base::inputs();
35 eigen_assert(uv.size()%2 == 0);
36 eigen_assert(uv.size() == n);
37 eigen_assert(x.size() == m);
38 y.setZero(m);
39 int half = n/2;
40 VectorBlock<const VectorType> u(uv, 0, half);
41 VectorBlock<const VectorType> v(uv, half, half);
42 for (int j = 0; j < m; j++)
43 {
44 for (int i = 0; i < half; i++)
45 y(j) += u(i)*std::exp(-(x(j)-i)*(x(j)-i)/(v(i)*v(i)));
46 }
47 return y;
48
49 }
initPointsDenseLM50 void initPoints(VectorType& uv_ref, VectorType& x)
51 {
52 m_x = x;
53 m_y = this->model(uv_ref, x);
54 }
55
operator ()DenseLM56 int operator()(const VectorType& uv, VectorType& fvec)
57 {
58
59 int m = Base::values();
60 int n = Base::inputs();
61 eigen_assert(uv.size()%2 == 0);
62 eigen_assert(uv.size() == n);
63 eigen_assert(fvec.size() == m);
64 int half = n/2;
65 VectorBlock<const VectorType> u(uv, 0, half);
66 VectorBlock<const VectorType> v(uv, half, half);
67 for (int j = 0; j < m; j++)
68 {
69 fvec(j) = m_y(j);
70 for (int i = 0; i < half; i++)
71 {
72 fvec(j) -= u(i) *std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
73 }
74 }
75
76 return 0;
77 }
dfDenseLM78 int df(const VectorType& uv, JacobianType& fjac)
79 {
80 int m = Base::values();
81 int n = Base::inputs();
82 eigen_assert(n == uv.size());
83 eigen_assert(fjac.rows() == m);
84 eigen_assert(fjac.cols() == n);
85 int half = n/2;
86 VectorBlock<const VectorType> u(uv, 0, half);
87 VectorBlock<const VectorType> v(uv, half, half);
88 for (int j = 0; j < m; j++)
89 {
90 for (int i = 0; i < half; i++)
91 {
92 fjac.coeffRef(j,i) = -std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
93 fjac.coeffRef(j,i+half) = -2.*u(i)*(m_x(j)-i)*(m_x(j)-i)/(std::pow(v(i),3)) * std::exp(-(m_x(j)-i)*(m_x(j)-i)/(v(i)*v(i)));
94 }
95 }
96 return 0;
97 }
98 VectorType m_x, m_y; //Data Points
99 };
100
101 template<typename FunctorType, typename VectorType>
test_minimizeLM(FunctorType & functor,VectorType & uv)102 int test_minimizeLM(FunctorType& functor, VectorType& uv)
103 {
104 LevenbergMarquardt<FunctorType> lm(functor);
105 LevenbergMarquardtSpace::Status info;
106
107 info = lm.minimize(uv);
108
109 VERIFY_IS_EQUAL(info, 1);
110 //FIXME Check other parameters
111 return info;
112 }
113
114 template<typename FunctorType, typename VectorType>
test_lmder(FunctorType & functor,VectorType & uv)115 int test_lmder(FunctorType& functor, VectorType& uv)
116 {
117 typedef typename VectorType::Scalar Scalar;
118 LevenbergMarquardtSpace::Status info;
119 LevenbergMarquardt<FunctorType> lm(functor);
120 info = lm.lmder1(uv);
121
122 VERIFY_IS_EQUAL(info, 1);
123 //FIXME Check other parameters
124 return info;
125 }
126
127 template<typename FunctorType, typename VectorType>
test_minimizeSteps(FunctorType & functor,VectorType & uv)128 int test_minimizeSteps(FunctorType& functor, VectorType& uv)
129 {
130 LevenbergMarquardtSpace::Status info;
131 LevenbergMarquardt<FunctorType> lm(functor);
132 info = lm.minimizeInit(uv);
133 if (info==LevenbergMarquardtSpace::ImproperInputParameters)
134 return info;
135 do
136 {
137 info = lm.minimizeOneStep(uv);
138 } while (info==LevenbergMarquardtSpace::Running);
139
140 VERIFY_IS_EQUAL(info, 1);
141 //FIXME Check other parameters
142 return info;
143 }
144
145 template<typename T>
test_denseLM_T()146 void test_denseLM_T()
147 {
148 typedef Matrix<T,Dynamic,1> VectorType;
149
150 int inputs = 10;
151 int values = 1000;
152 DenseLM<T> dense_gaussian(inputs, values);
153 VectorType uv(inputs),uv_ref(inputs);
154 VectorType x(values);
155
156 // Generate the reference solution
157 uv_ref << -2, 1, 4 ,8, 6, 1.8, 1.2, 1.1, 1.9 , 3;
158
159 //Generate the reference data points
160 x.setRandom();
161 x = 10*x;
162 x.array() += 10;
163 dense_gaussian.initPoints(uv_ref, x);
164
165 // Generate the initial parameters
166 VectorBlock<VectorType> u(uv, 0, inputs/2);
167 VectorBlock<VectorType> v(uv, inputs/2, inputs/2);
168
169 // Solve the optimization problem
170
171 //Solve in one go
172 u.setOnes(); v.setOnes();
173 test_minimizeLM(dense_gaussian, uv);
174
175 //Solve until the machine precision
176 u.setOnes(); v.setOnes();
177 test_lmder(dense_gaussian, uv);
178
179 // Solve step by step
180 v.setOnes(); u.setOnes();
181 test_minimizeSteps(dense_gaussian, uv);
182
183 }
184
EIGEN_DECLARE_TEST(denseLM)185 EIGEN_DECLARE_TEST(denseLM)
186 {
187 CALL_SUBTEST_2(test_denseLM_T<double>());
188
189 // CALL_SUBTEST_2(test_sparseLM_T<std::complex<double>());
190 }
191