1 // This file is part of Eigen, a lightweight C++ template library 2 // for linear algebra. 3 // 4 // Copyright (C) 2009 Thomas Capricelli <orzel@freehackers.org> 5 // Copyright (C) 2012 desire Nuentsa <desire.nuentsa_wakam@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 12 // FIXME: These tests all check for hard-coded values. Ideally, parameters and start estimates should be randomized. 13 14 15 #include <stdio.h> 16 17 #include "main.h" 18 #include <unsupported/Eigen/LevenbergMarquardt> 19 20 // This disables some useless Warnings on MSVC. 21 // It is intended to be done for this test only. 22 #include <Eigen/src/Core/util/DisableStupidWarnings.h> 23 24 using std::sqrt; 25 26 // tolerance for chekcing number of iterations 27 #define LM_EVAL_COUNT_TOL 4/3 28 29 struct lmder_functor : DenseFunctor<double> 30 { 31 lmder_functor(void): DenseFunctor<double>(3,15) {} 32 int operator()(const VectorXd &x, VectorXd &fvec) const 33 { 34 double tmp1, tmp2, tmp3; 35 static const double y[15] = {1.4e-1, 1.8e-1, 2.2e-1, 2.5e-1, 2.9e-1, 3.2e-1, 3.5e-1, 36 3.9e-1, 3.7e-1, 5.8e-1, 7.3e-1, 9.6e-1, 1.34, 2.1, 4.39}; 37 38 for (int i = 0; i < values(); i++) 39 { 40 tmp1 = i+1; 41 tmp2 = 16 - i - 1; 42 tmp3 = (i>=8)? tmp2 : tmp1; 43 fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); 44 } 45 return 0; 46 } 47 48 int df(const VectorXd &x, MatrixXd &fjac) const 49 { 50 double tmp1, tmp2, tmp3, tmp4; 51 for (int i = 0; i < values(); i++) 52 { 53 tmp1 = i+1; 54 tmp2 = 16 - i - 1; 55 tmp3 = (i>=8)? tmp2 : tmp1; 56 tmp4 = (x[1]*tmp2 + x[2]*tmp3); tmp4 = tmp4*tmp4; 57 fjac(i,0) = -1; 58 fjac(i,1) = tmp1*tmp2/tmp4; 59 fjac(i,2) = tmp1*tmp3/tmp4; 60 } 61 return 0; 62 } 63 }; 64 65 void testLmder1() 66 { 67 int n=3, info; 68 69 VectorXd x; 70 71 /* the following starting values provide a rough fit. */ 72 x.setConstant(n, 1.); 73 74 // do the computation 75 lmder_functor functor; 76 LevenbergMarquardt<lmder_functor> lm(functor); 77 info = lm.lmder1(x); 78 79 // check return value 80 VERIFY_IS_EQUAL(info, 1); 81 VERIFY_IS_EQUAL(lm.nfev(), 6); 82 VERIFY_IS_EQUAL(lm.njev(), 5); 83 84 // check norm 85 VERIFY_IS_APPROX(lm.fvec().blueNorm(), 0.09063596); 86 87 // check x 88 VectorXd x_ref(n); 89 x_ref << 0.08241058, 1.133037, 2.343695; 90 VERIFY_IS_APPROX(x, x_ref); 91 } 92 93 void testLmder() 94 { 95 const int m=15, n=3; 96 int info; 97 double fnorm, covfac; 98 VectorXd x; 99 100 /* the following starting values provide a rough fit. */ 101 x.setConstant(n, 1.); 102 103 // do the computation 104 lmder_functor functor; 105 LevenbergMarquardt<lmder_functor> lm(functor); 106 info = lm.minimize(x); 107 108 // check return values 109 VERIFY_IS_EQUAL(info, 1); 110 VERIFY_IS_EQUAL(lm.nfev(), 6); 111 VERIFY_IS_EQUAL(lm.njev(), 5); 112 113 // check norm 114 fnorm = lm.fvec().blueNorm(); 115 VERIFY_IS_APPROX(fnorm, 0.09063596); 116 117 // check x 118 VectorXd x_ref(n); 119 x_ref << 0.08241058, 1.133037, 2.343695; 120 VERIFY_IS_APPROX(x, x_ref); 121 122 // check covariance 123 covfac = fnorm*fnorm/(m-n); 124 internal::covar(lm.matrixR(), lm.permutation().indices()); // TODO : move this as a function of lm 125 126 MatrixXd cov_ref(n,n); 127 cov_ref << 128 0.0001531202, 0.002869941, -0.002656662, 129 0.002869941, 0.09480935, -0.09098995, 130 -0.002656662, -0.09098995, 0.08778727; 131 132 // std::cout << fjac*covfac << std::endl; 133 134 MatrixXd cov; 135 cov = covfac*lm.matrixR().topLeftCorner<n,n>(); 136 VERIFY_IS_APPROX( cov, cov_ref); 137 // TODO: why isn't this allowed ? : 138 // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); 139 } 140 141 struct lmdif_functor : DenseFunctor<double> 142 { 143 lmdif_functor(void) : DenseFunctor<double>(3,15) {} 144 int operator()(const VectorXd &x, VectorXd &fvec) const 145 { 146 int i; 147 double tmp1,tmp2,tmp3; 148 static const double y[15]={1.4e-1,1.8e-1,2.2e-1,2.5e-1,2.9e-1,3.2e-1,3.5e-1,3.9e-1, 149 3.7e-1,5.8e-1,7.3e-1,9.6e-1,1.34e0,2.1e0,4.39e0}; 150 151 assert(x.size()==3); 152 assert(fvec.size()==15); 153 for (i=0; i<15; i++) 154 { 155 tmp1 = i+1; 156 tmp2 = 15 - i; 157 tmp3 = tmp1; 158 159 if (i >= 8) tmp3 = tmp2; 160 fvec[i] = y[i] - (x[0] + tmp1/(x[1]*tmp2 + x[2]*tmp3)); 161 } 162 return 0; 163 } 164 }; 165 166 void testLmdif1() 167 { 168 const int n=3; 169 int info; 170 171 VectorXd x(n), fvec(15); 172 173 /* the following starting values provide a rough fit. */ 174 x.setConstant(n, 1.); 175 176 // do the computation 177 lmdif_functor functor; 178 DenseIndex nfev; 179 info = LevenbergMarquardt<lmdif_functor>::lmdif1(functor, x, &nfev); 180 181 // check return value 182 VERIFY_IS_EQUAL(info, 1); 183 // VERIFY_IS_EQUAL(nfev, 26); 184 185 // check norm 186 functor(x, fvec); 187 VERIFY_IS_APPROX(fvec.blueNorm(), 0.09063596); 188 189 // check x 190 VectorXd x_ref(n); 191 x_ref << 0.0824106, 1.1330366, 2.3436947; 192 VERIFY_IS_APPROX(x, x_ref); 193 194 } 195 196 void testLmdif() 197 { 198 const int m=15, n=3; 199 int info; 200 double fnorm, covfac; 201 VectorXd x(n); 202 203 /* the following starting values provide a rough fit. */ 204 x.setConstant(n, 1.); 205 206 // do the computation 207 lmdif_functor functor; 208 NumericalDiff<lmdif_functor> numDiff(functor); 209 LevenbergMarquardt<NumericalDiff<lmdif_functor> > lm(numDiff); 210 info = lm.minimize(x); 211 212 // check return values 213 VERIFY_IS_EQUAL(info, 1); 214 // VERIFY_IS_EQUAL(lm.nfev(), 26); 215 216 // check norm 217 fnorm = lm.fvec().blueNorm(); 218 VERIFY_IS_APPROX(fnorm, 0.09063596); 219 220 // check x 221 VectorXd x_ref(n); 222 x_ref << 0.08241058, 1.133037, 2.343695; 223 VERIFY_IS_APPROX(x, x_ref); 224 225 // check covariance 226 covfac = fnorm*fnorm/(m-n); 227 internal::covar(lm.matrixR(), lm.permutation().indices()); // TODO : move this as a function of lm 228 229 MatrixXd cov_ref(n,n); 230 cov_ref << 231 0.0001531202, 0.002869942, -0.002656662, 232 0.002869942, 0.09480937, -0.09098997, 233 -0.002656662, -0.09098997, 0.08778729; 234 235 // std::cout << fjac*covfac << std::endl; 236 237 MatrixXd cov; 238 cov = covfac*lm.matrixR().topLeftCorner<n,n>(); 239 VERIFY_IS_APPROX( cov, cov_ref); 240 // TODO: why isn't this allowed ? : 241 // VERIFY_IS_APPROX( covfac*fjac.topLeftCorner<n,n>() , cov_ref); 242 } 243 244 struct chwirut2_functor : DenseFunctor<double> 245 { 246 chwirut2_functor(void) : DenseFunctor<double>(3,54) {} 247 static const double m_x[54]; 248 static const double m_y[54]; 249 int operator()(const VectorXd &b, VectorXd &fvec) 250 { 251 int i; 252 253 assert(b.size()==3); 254 assert(fvec.size()==54); 255 for(i=0; i<54; i++) { 256 double x = m_x[i]; 257 fvec[i] = exp(-b[0]*x)/(b[1]+b[2]*x) - m_y[i]; 258 } 259 return 0; 260 } 261 int df(const VectorXd &b, MatrixXd &fjac) 262 { 263 assert(b.size()==3); 264 assert(fjac.rows()==54); 265 assert(fjac.cols()==3); 266 for(int i=0; i<54; i++) { 267 double x = m_x[i]; 268 double factor = 1./(b[1]+b[2]*x); 269 double e = exp(-b[0]*x); 270 fjac(i,0) = -x*e*factor; 271 fjac(i,1) = -e*factor*factor; 272 fjac(i,2) = -x*e*factor*factor; 273 } 274 return 0; 275 } 276 }; 277 const double chwirut2_functor::m_x[54] = { 0.500E0, 1.000E0, 1.750E0, 3.750E0, 5.750E0, 0.875E0, 2.250E0, 3.250E0, 5.250E0, 0.750E0, 1.750E0, 2.750E0, 4.750E0, 0.625E0, 1.250E0, 2.250E0, 4.250E0, .500E0, 3.000E0, .750E0, 3.000E0, 1.500E0, 6.000E0, 3.000E0, 6.000E0, 1.500E0, 3.000E0, .500E0, 2.000E0, 4.000E0, .750E0, 2.000E0, 5.000E0, .750E0, 2.250E0, 3.750E0, 5.750E0, 3.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .750E0, 2.500E0, 4.000E0, .500E0, 6.000E0, 3.000E0, .500E0, 2.750E0, .500E0, 1.750E0}; 278 const double chwirut2_functor::m_y[54] = { 92.9000E0 ,57.1000E0 ,31.0500E0 ,11.5875E0 ,8.0250E0 ,63.6000E0 ,21.4000E0 ,14.2500E0 ,8.4750E0 ,63.8000E0 ,26.8000E0 ,16.4625E0 ,7.1250E0 ,67.3000E0 ,41.0000E0 ,21.1500E0 ,8.1750E0 ,81.5000E0 ,13.1200E0 ,59.9000E0 ,14.6200E0 ,32.9000E0 ,5.4400E0 ,12.5600E0 ,5.4400E0 ,32.0000E0 ,13.9500E0 ,75.8000E0 ,20.0000E0 ,10.4200E0 ,59.5000E0 ,21.6700E0 ,8.5500E0 ,62.0000E0 ,20.2000E0 ,7.7600E0 ,3.7500E0 ,11.8100E0 ,54.7000E0 ,23.7000E0 ,11.5500E0 ,61.3000E0 ,17.7000E0 ,8.7400E0 ,59.2000E0 ,16.3000E0 ,8.6200E0 ,81.0000E0 ,4.8700E0 ,14.6200E0 ,81.7000E0 ,17.1700E0 ,81.3000E0 ,28.9000E0 }; 279 280 // http://www.itl.nist.gov/div898/strd/nls/data/chwirut2.shtml 281 void testNistChwirut2(void) 282 { 283 const int n=3; 284 LevenbergMarquardtSpace::Status info; 285 286 VectorXd x(n); 287 288 /* 289 * First try 290 */ 291 x<< 0.1, 0.01, 0.02; 292 // do the computation 293 chwirut2_functor functor; 294 LevenbergMarquardt<chwirut2_functor> lm(functor); 295 info = lm.minimize(x); 296 297 // check return value 298 VERIFY_IS_EQUAL(info, 1); 299 // VERIFY_IS_EQUAL(lm.nfev(), 10); 300 VERIFY_IS_EQUAL(lm.njev(), 8); 301 // check norm^2 302 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.1304802941E+02); 303 // check x 304 VERIFY_IS_APPROX(x[0], 1.6657666537E-01); 305 VERIFY_IS_APPROX(x[1], 5.1653291286E-03); 306 VERIFY_IS_APPROX(x[2], 1.2150007096E-02); 307 308 /* 309 * Second try 310 */ 311 x<< 0.15, 0.008, 0.010; 312 // do the computation 313 lm.resetParameters(); 314 lm.setFtol(1.E6*NumTraits<double>::epsilon()); 315 lm.setXtol(1.E6*NumTraits<double>::epsilon()); 316 info = lm.minimize(x); 317 318 // check return value 319 VERIFY_IS_EQUAL(info, 1); 320 // VERIFY_IS_EQUAL(lm.nfev(), 7); 321 VERIFY_IS_EQUAL(lm.njev(), 6); 322 // check norm^2 323 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.1304802941E+02); 324 // check x 325 VERIFY_IS_APPROX(x[0], 1.6657666537E-01); 326 VERIFY_IS_APPROX(x[1], 5.1653291286E-03); 327 VERIFY_IS_APPROX(x[2], 1.2150007096E-02); 328 } 329 330 331 struct misra1a_functor : DenseFunctor<double> 332 { 333 misra1a_functor(void) : DenseFunctor<double>(2,14) {} 334 static const double m_x[14]; 335 static const double m_y[14]; 336 int operator()(const VectorXd &b, VectorXd &fvec) 337 { 338 assert(b.size()==2); 339 assert(fvec.size()==14); 340 for(int i=0; i<14; i++) { 341 fvec[i] = b[0]*(1.-exp(-b[1]*m_x[i])) - m_y[i] ; 342 } 343 return 0; 344 } 345 int df(const VectorXd &b, MatrixXd &fjac) 346 { 347 assert(b.size()==2); 348 assert(fjac.rows()==14); 349 assert(fjac.cols()==2); 350 for(int i=0; i<14; i++) { 351 fjac(i,0) = (1.-exp(-b[1]*m_x[i])); 352 fjac(i,1) = (b[0]*m_x[i]*exp(-b[1]*m_x[i])); 353 } 354 return 0; 355 } 356 }; 357 const double misra1a_functor::m_x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; 358 const double misra1a_functor::m_y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; 359 360 // http://www.itl.nist.gov/div898/strd/nls/data/misra1a.shtml 361 void testNistMisra1a(void) 362 { 363 const int n=2; 364 int info; 365 366 VectorXd x(n); 367 368 /* 369 * First try 370 */ 371 x<< 500., 0.0001; 372 // do the computation 373 misra1a_functor functor; 374 LevenbergMarquardt<misra1a_functor> lm(functor); 375 info = lm.minimize(x); 376 377 // check return value 378 VERIFY_IS_EQUAL(info, 1); 379 VERIFY_IS_EQUAL(lm.nfev(), 19); 380 VERIFY_IS_EQUAL(lm.njev(), 15); 381 // check norm^2 382 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.2455138894E-01); 383 // check x 384 VERIFY_IS_APPROX(x[0], 2.3894212918E+02); 385 VERIFY_IS_APPROX(x[1], 5.5015643181E-04); 386 387 /* 388 * Second try 389 */ 390 x<< 250., 0.0005; 391 // do the computation 392 info = lm.minimize(x); 393 394 // check return value 395 VERIFY_IS_EQUAL(info, 1); 396 VERIFY_IS_EQUAL(lm.nfev(), 5); 397 VERIFY_IS_EQUAL(lm.njev(), 4); 398 // check norm^2 399 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.2455138894E-01); 400 // check x 401 VERIFY_IS_APPROX(x[0], 2.3894212918E+02); 402 VERIFY_IS_APPROX(x[1], 5.5015643181E-04); 403 } 404 405 struct hahn1_functor : DenseFunctor<double> 406 { 407 hahn1_functor(void) : DenseFunctor<double>(7,236) {} 408 static const double m_x[236]; 409 int operator()(const VectorXd &b, VectorXd &fvec) 410 { 411 static const double m_y[236] = { .591E0 , 1.547E0 , 2.902E0 , 2.894E0 , 4.703E0 , 6.307E0 , 7.03E0 , 7.898E0 , 9.470E0 , 9.484E0 , 10.072E0 , 10.163E0 , 11.615E0 , 12.005E0 , 12.478E0 , 12.982E0 , 12.970E0 , 13.926E0 , 14.452E0 , 14.404E0 , 15.190E0 , 15.550E0 , 15.528E0 , 15.499E0 , 16.131E0 , 16.438E0 , 16.387E0 , 16.549E0 , 16.872E0 , 16.830E0 , 16.926E0 , 16.907E0 , 16.966E0 , 17.060E0 , 17.122E0 , 17.311E0 , 17.355E0 , 17.668E0 , 17.767E0 , 17.803E0 , 17.765E0 , 17.768E0 , 17.736E0 , 17.858E0 , 17.877E0 , 17.912E0 , 18.046E0 , 18.085E0 , 18.291E0 , 18.357E0 , 18.426E0 , 18.584E0 , 18.610E0 , 18.870E0 , 18.795E0 , 19.111E0 , .367E0 , .796E0 , 0.892E0 , 1.903E0 , 2.150E0 , 3.697E0 , 5.870E0 , 6.421E0 , 7.422E0 , 9.944E0 , 11.023E0 , 11.87E0 , 12.786E0 , 14.067E0 , 13.974E0 , 14.462E0 , 14.464E0 , 15.381E0 , 15.483E0 , 15.59E0 , 16.075E0 , 16.347E0 , 16.181E0 , 16.915E0 , 17.003E0 , 16.978E0 , 17.756E0 , 17.808E0 , 17.868E0 , 18.481E0 , 18.486E0 , 19.090E0 , 16.062E0 , 16.337E0 , 16.345E0 , 412 16.388E0 , 17.159E0 , 17.116E0 , 17.164E0 , 17.123E0 , 17.979E0 , 17.974E0 , 18.007E0 , 17.993E0 , 18.523E0 , 18.669E0 , 18.617E0 , 19.371E0 , 19.330E0 , 0.080E0 , 0.248E0 , 1.089E0 , 1.418E0 , 2.278E0 , 3.624E0 , 4.574E0 , 5.556E0 , 7.267E0 , 7.695E0 , 9.136E0 , 9.959E0 , 9.957E0 , 11.600E0 , 13.138E0 , 13.564E0 , 13.871E0 , 13.994E0 , 14.947E0 , 15.473E0 , 15.379E0 , 15.455E0 , 15.908E0 , 16.114E0 , 17.071E0 , 17.135E0 , 17.282E0 , 17.368E0 , 17.483E0 , 17.764E0 , 18.185E0 , 18.271E0 , 18.236E0 , 18.237E0 , 18.523E0 , 18.627E0 , 18.665E0 , 19.086E0 , 0.214E0 , 0.943E0 , 1.429E0 , 2.241E0 , 2.951E0 , 3.782E0 , 4.757E0 , 5.602E0 , 7.169E0 , 8.920E0 , 10.055E0 , 12.035E0 , 12.861E0 , 13.436E0 , 14.167E0 , 14.755E0 , 15.168E0 , 15.651E0 , 15.746E0 , 16.216E0 , 16.445E0 , 16.965E0 , 17.121E0 , 17.206E0 , 17.250E0 , 17.339E0 , 17.793E0 , 18.123E0 , 18.49E0 , 18.566E0 , 18.645E0 , 18.706E0 , 18.924E0 , 19.1E0 , 0.375E0 , 0.471E0 , 1.504E0 , 2.204E0 , 2.813E0 , 4.765E0 , 9.835E0 , 10.040E0 , 11.946E0 , 413 12.596E0 , 414 13.303E0 , 13.922E0 , 14.440E0 , 14.951E0 , 15.627E0 , 15.639E0 , 15.814E0 , 16.315E0 , 16.334E0 , 16.430E0 , 16.423E0 , 17.024E0 , 17.009E0 , 17.165E0 , 17.134E0 , 17.349E0 , 17.576E0 , 17.848E0 , 18.090E0 , 18.276E0 , 18.404E0 , 18.519E0 , 19.133E0 , 19.074E0 , 19.239E0 , 19.280E0 , 19.101E0 , 19.398E0 , 19.252E0 , 19.89E0 , 20.007E0 , 19.929E0 , 19.268E0 , 19.324E0 , 20.049E0 , 20.107E0 , 20.062E0 , 20.065E0 , 19.286E0 , 19.972E0 , 20.088E0 , 20.743E0 , 20.83E0 , 20.935E0 , 21.035E0 , 20.93E0 , 21.074E0 , 21.085E0 , 20.935E0 }; 415 416 // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; 417 418 assert(b.size()==7); 419 assert(fvec.size()==236); 420 for(int i=0; i<236; i++) { 421 double x=m_x[i], xx=x*x, xxx=xx*x; 422 fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - m_y[i]; 423 } 424 return 0; 425 } 426 427 int df(const VectorXd &b, MatrixXd &fjac) 428 { 429 assert(b.size()==7); 430 assert(fjac.rows()==236); 431 assert(fjac.cols()==7); 432 for(int i=0; i<236; i++) { 433 double x=m_x[i], xx=x*x, xxx=xx*x; 434 double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); 435 fjac(i,0) = 1.*fact; 436 fjac(i,1) = x*fact; 437 fjac(i,2) = xx*fact; 438 fjac(i,3) = xxx*fact; 439 fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; 440 fjac(i,4) = x*fact; 441 fjac(i,5) = xx*fact; 442 fjac(i,6) = xxx*fact; 443 } 444 return 0; 445 } 446 }; 447 const double hahn1_functor::m_x[236] = { 24.41E0 , 34.82E0 , 44.09E0 , 45.07E0 , 54.98E0 , 65.51E0 , 70.53E0 , 75.70E0 , 89.57E0 , 91.14E0 , 96.40E0 , 97.19E0 , 114.26E0 , 120.25E0 , 127.08E0 , 133.55E0 , 133.61E0 , 158.67E0 , 172.74E0 , 171.31E0 , 202.14E0 , 220.55E0 , 221.05E0 , 221.39E0 , 250.99E0 , 268.99E0 , 271.80E0 , 271.97E0 , 321.31E0 , 321.69E0 , 330.14E0 , 333.03E0 , 333.47E0 , 340.77E0 , 345.65E0 , 373.11E0 , 373.79E0 , 411.82E0 , 419.51E0 , 421.59E0 , 422.02E0 , 422.47E0 , 422.61E0 , 441.75E0 , 447.41E0 , 448.7E0 , 472.89E0 , 476.69E0 , 522.47E0 , 522.62E0 , 524.43E0 , 546.75E0 , 549.53E0 , 575.29E0 , 576.00E0 , 625.55E0 , 20.15E0 , 28.78E0 , 29.57E0 , 37.41E0 , 39.12E0 , 50.24E0 , 61.38E0 , 66.25E0 , 73.42E0 , 95.52E0 , 107.32E0 , 122.04E0 , 134.03E0 , 163.19E0 , 163.48E0 , 175.70E0 , 179.86E0 , 211.27E0 , 217.78E0 , 219.14E0 , 262.52E0 , 268.01E0 , 268.62E0 , 336.25E0 , 337.23E0 , 339.33E0 , 427.38E0 , 428.58E0 , 432.68E0 , 528.99E0 , 531.08E0 , 628.34E0 , 253.24E0 , 273.13E0 , 273.66E0 , 448 282.10E0 , 346.62E0 , 347.19E0 , 348.78E0 , 351.18E0 , 450.10E0 , 450.35E0 , 451.92E0 , 455.56E0 , 552.22E0 , 553.56E0 , 555.74E0 , 652.59E0 , 656.20E0 , 14.13E0 , 20.41E0 , 31.30E0 , 33.84E0 , 39.70E0 , 48.83E0 , 54.50E0 , 60.41E0 , 72.77E0 , 75.25E0 , 86.84E0 , 94.88E0 , 96.40E0 , 117.37E0 , 139.08E0 , 147.73E0 , 158.63E0 , 161.84E0 , 192.11E0 , 206.76E0 , 209.07E0 , 213.32E0 , 226.44E0 , 237.12E0 , 330.90E0 , 358.72E0 , 370.77E0 , 372.72E0 , 396.24E0 , 416.59E0 , 484.02E0 , 495.47E0 , 514.78E0 , 515.65E0 , 519.47E0 , 544.47E0 , 560.11E0 , 620.77E0 , 18.97E0 , 28.93E0 , 33.91E0 , 40.03E0 , 44.66E0 , 49.87E0 , 55.16E0 , 60.90E0 , 72.08E0 , 85.15E0 , 97.06E0 , 119.63E0 , 133.27E0 , 143.84E0 , 161.91E0 , 180.67E0 , 198.44E0 , 226.86E0 , 229.65E0 , 258.27E0 , 273.77E0 , 339.15E0 , 350.13E0 , 362.75E0 , 371.03E0 , 393.32E0 , 448.53E0 , 473.78E0 , 511.12E0 , 524.70E0 , 548.75E0 , 551.64E0 , 574.02E0 , 623.86E0 , 21.46E0 , 24.33E0 , 33.43E0 , 39.22E0 , 44.18E0 , 55.02E0 , 94.33E0 , 96.44E0 , 118.82E0 , 128.48E0 , 449 141.94E0 , 156.92E0 , 171.65E0 , 190.00E0 , 223.26E0 , 223.88E0 , 231.50E0 , 265.05E0 , 269.44E0 , 271.78E0 , 273.46E0 , 334.61E0 , 339.79E0 , 349.52E0 , 358.18E0 , 377.98E0 , 394.77E0 , 429.66E0 , 468.22E0 , 487.27E0 , 519.54E0 , 523.03E0 , 612.99E0 , 638.59E0 , 641.36E0 , 622.05E0 , 631.50E0 , 663.97E0 , 646.9E0 , 748.29E0 , 749.21E0 , 750.14E0 , 647.04E0 , 646.89E0 , 746.9E0 , 748.43E0 , 747.35E0 , 749.27E0 , 647.61E0 , 747.78E0 , 750.51E0 , 851.37E0 , 845.97E0 , 847.54E0 , 849.93E0 , 851.61E0 , 849.75E0 , 850.98E0 , 848.23E0}; 450 451 // http://www.itl.nist.gov/div898/strd/nls/data/hahn1.shtml 452 void testNistHahn1(void) 453 { 454 const int n=7; 455 int info; 456 457 VectorXd x(n); 458 459 /* 460 * First try 461 */ 462 x<< 10., -1., .05, -.00001, -.05, .001, -.000001; 463 // do the computation 464 hahn1_functor functor; 465 LevenbergMarquardt<hahn1_functor> lm(functor); 466 info = lm.minimize(x); 467 468 // check return value 469 VERIFY_IS_EQUAL(info, 1); 470 VERIFY_IS_EQUAL(lm.nfev(), 11); 471 VERIFY_IS_EQUAL(lm.njev(), 10); 472 // check norm^2 473 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.5324382854E+00); 474 // check x 475 VERIFY_IS_APPROX(x[0], 1.0776351733E+00); 476 VERIFY_IS_APPROX(x[1],-1.2269296921E-01); 477 VERIFY_IS_APPROX(x[2], 4.0863750610E-03); 478 VERIFY_IS_APPROX(x[3],-1.426264e-06); // shoulde be : -1.4262662514E-06 479 VERIFY_IS_APPROX(x[4],-5.7609940901E-03); 480 VERIFY_IS_APPROX(x[5], 2.4053735503E-04); 481 VERIFY_IS_APPROX(x[6],-1.2314450199E-07); 482 483 /* 484 * Second try 485 */ 486 x<< .1, -.1, .005, -.000001, -.005, .0001, -.0000001; 487 // do the computation 488 info = lm.minimize(x); 489 490 // check return value 491 VERIFY_IS_EQUAL(info, 1); 492 // VERIFY_IS_EQUAL(lm.nfev(), 11); 493 VERIFY_IS_EQUAL(lm.njev(), 10); 494 // check norm^2 495 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.5324382854E+00); 496 // check x 497 VERIFY_IS_APPROX(x[0], 1.077640); // should be : 1.0776351733E+00 498 VERIFY_IS_APPROX(x[1], -0.1226933); // should be : -1.2269296921E-01 499 VERIFY_IS_APPROX(x[2], 0.004086383); // should be : 4.0863750610E-03 500 VERIFY_IS_APPROX(x[3], -1.426277e-06); // shoulde be : -1.4262662514E-06 501 VERIFY_IS_APPROX(x[4],-5.7609940901E-03); 502 VERIFY_IS_APPROX(x[5], 0.00024053772); // should be : 2.4053735503E-04 503 VERIFY_IS_APPROX(x[6], -1.231450e-07); // should be : -1.2314450199E-07 504 505 } 506 507 struct misra1d_functor : DenseFunctor<double> 508 { 509 misra1d_functor(void) : DenseFunctor<double>(2,14) {} 510 static const double x[14]; 511 static const double y[14]; 512 int operator()(const VectorXd &b, VectorXd &fvec) 513 { 514 assert(b.size()==2); 515 assert(fvec.size()==14); 516 for(int i=0; i<14; i++) { 517 fvec[i] = b[0]*b[1]*x[i]/(1.+b[1]*x[i]) - y[i]; 518 } 519 return 0; 520 } 521 int df(const VectorXd &b, MatrixXd &fjac) 522 { 523 assert(b.size()==2); 524 assert(fjac.rows()==14); 525 assert(fjac.cols()==2); 526 for(int i=0; i<14; i++) { 527 double den = 1.+b[1]*x[i]; 528 fjac(i,0) = b[1]*x[i] / den; 529 fjac(i,1) = b[0]*x[i]*(den-b[1]*x[i])/den/den; 530 } 531 return 0; 532 } 533 }; 534 const double misra1d_functor::x[14] = { 77.6E0, 114.9E0, 141.1E0, 190.8E0, 239.9E0, 289.0E0, 332.8E0, 378.4E0, 434.8E0, 477.3E0, 536.8E0, 593.1E0, 689.1E0, 760.0E0}; 535 const double misra1d_functor::y[14] = { 10.07E0, 14.73E0, 17.94E0, 23.93E0, 29.61E0, 35.18E0, 40.02E0, 44.82E0, 50.76E0, 55.05E0, 61.01E0, 66.40E0, 75.47E0, 81.78E0}; 536 537 // http://www.itl.nist.gov/div898/strd/nls/data/misra1d.shtml 538 void testNistMisra1d(void) 539 { 540 const int n=2; 541 int info; 542 543 VectorXd x(n); 544 545 /* 546 * First try 547 */ 548 x<< 500., 0.0001; 549 // do the computation 550 misra1d_functor functor; 551 LevenbergMarquardt<misra1d_functor> lm(functor); 552 info = lm.minimize(x); 553 554 // check return value 555 VERIFY_IS_EQUAL(info, 1); 556 VERIFY_IS_EQUAL(lm.nfev(), 9); 557 VERIFY_IS_EQUAL(lm.njev(), 7); 558 // check norm^2 559 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6419295283E-02); 560 // check x 561 VERIFY_IS_APPROX(x[0], 4.3736970754E+02); 562 VERIFY_IS_APPROX(x[1], 3.0227324449E-04); 563 564 /* 565 * Second try 566 */ 567 x<< 450., 0.0003; 568 // do the computation 569 info = lm.minimize(x); 570 571 // check return value 572 VERIFY_IS_EQUAL(info, 1); 573 VERIFY_IS_EQUAL(lm.nfev(), 4); 574 VERIFY_IS_EQUAL(lm.njev(), 3); 575 // check norm^2 576 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6419295283E-02); 577 // check x 578 VERIFY_IS_APPROX(x[0], 4.3736970754E+02); 579 VERIFY_IS_APPROX(x[1], 3.0227324449E-04); 580 } 581 582 583 struct lanczos1_functor : DenseFunctor<double> 584 { 585 lanczos1_functor(void) : DenseFunctor<double>(6,24) {} 586 static const double x[24]; 587 static const double y[24]; 588 int operator()(const VectorXd &b, VectorXd &fvec) 589 { 590 assert(b.size()==6); 591 assert(fvec.size()==24); 592 for(int i=0; i<24; i++) 593 fvec[i] = b[0]*exp(-b[1]*x[i]) + b[2]*exp(-b[3]*x[i]) + b[4]*exp(-b[5]*x[i]) - y[i]; 594 return 0; 595 } 596 int df(const VectorXd &b, MatrixXd &fjac) 597 { 598 assert(b.size()==6); 599 assert(fjac.rows()==24); 600 assert(fjac.cols()==6); 601 for(int i=0; i<24; i++) { 602 fjac(i,0) = exp(-b[1]*x[i]); 603 fjac(i,1) = -b[0]*x[i]*exp(-b[1]*x[i]); 604 fjac(i,2) = exp(-b[3]*x[i]); 605 fjac(i,3) = -b[2]*x[i]*exp(-b[3]*x[i]); 606 fjac(i,4) = exp(-b[5]*x[i]); 607 fjac(i,5) = -b[4]*x[i]*exp(-b[5]*x[i]); 608 } 609 return 0; 610 } 611 }; 612 const double lanczos1_functor::x[24] = { 0.000000000000E+00, 5.000000000000E-02, 1.000000000000E-01, 1.500000000000E-01, 2.000000000000E-01, 2.500000000000E-01, 3.000000000000E-01, 3.500000000000E-01, 4.000000000000E-01, 4.500000000000E-01, 5.000000000000E-01, 5.500000000000E-01, 6.000000000000E-01, 6.500000000000E-01, 7.000000000000E-01, 7.500000000000E-01, 8.000000000000E-01, 8.500000000000E-01, 9.000000000000E-01, 9.500000000000E-01, 1.000000000000E+00, 1.050000000000E+00, 1.100000000000E+00, 1.150000000000E+00 }; 613 const double lanczos1_functor::y[24] = { 2.513400000000E+00 ,2.044333373291E+00 ,1.668404436564E+00 ,1.366418021208E+00 ,1.123232487372E+00 ,9.268897180037E-01 ,7.679338563728E-01 ,6.388775523106E-01 ,5.337835317402E-01 ,4.479363617347E-01 ,3.775847884350E-01 ,3.197393199326E-01 ,2.720130773746E-01 ,2.324965529032E-01 ,1.996589546065E-01 ,1.722704126914E-01 ,1.493405660168E-01 ,1.300700206922E-01 ,1.138119324644E-01 ,1.000415587559E-01 ,8.833209084540E-02 ,7.833544019350E-02 ,6.976693743449E-02 ,6.239312536719E-02 }; 614 615 // http://www.itl.nist.gov/div898/strd/nls/data/lanczos1.shtml 616 void testNistLanczos1(void) 617 { 618 const int n=6; 619 LevenbergMarquardtSpace::Status info; 620 621 VectorXd x(n); 622 623 /* 624 * First try 625 */ 626 x<< 1.2, 0.3, 5.6, 5.5, 6.5, 7.6; 627 // do the computation 628 lanczos1_functor functor; 629 LevenbergMarquardt<lanczos1_functor> lm(functor); 630 info = lm.minimize(x); 631 632 // check return value 633 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeErrorTooSmall); 634 VERIFY_IS_EQUAL(lm.nfev(), 79); 635 VERIFY_IS_EQUAL(lm.njev(), 72); 636 // check norm^2 637 VERIFY(lm.fvec().squaredNorm() <= 1.4307867721E-25); 638 // check x 639 VERIFY_IS_APPROX(x[0], 9.5100000027E-02); 640 VERIFY_IS_APPROX(x[1], 1.0000000001E+00); 641 VERIFY_IS_APPROX(x[2], 8.6070000013E-01); 642 VERIFY_IS_APPROX(x[3], 3.0000000002E+00); 643 VERIFY_IS_APPROX(x[4], 1.5575999998E+00); 644 VERIFY_IS_APPROX(x[5], 5.0000000001E+00); 645 646 /* 647 * Second try 648 */ 649 x<< 0.5, 0.7, 3.6, 4.2, 4., 6.3; 650 // do the computation 651 info = lm.minimize(x); 652 653 // check return value 654 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeErrorTooSmall); 655 VERIFY_IS_EQUAL(lm.nfev(), 9); 656 VERIFY_IS_EQUAL(lm.njev(), 8); 657 // check norm^2 658 VERIFY(lm.fvec().squaredNorm() <= 1.4307867721E-25); 659 // check x 660 VERIFY_IS_APPROX(x[0], 9.5100000027E-02); 661 VERIFY_IS_APPROX(x[1], 1.0000000001E+00); 662 VERIFY_IS_APPROX(x[2], 8.6070000013E-01); 663 VERIFY_IS_APPROX(x[3], 3.0000000002E+00); 664 VERIFY_IS_APPROX(x[4], 1.5575999998E+00); 665 VERIFY_IS_APPROX(x[5], 5.0000000001E+00); 666 667 } 668 669 struct rat42_functor : DenseFunctor<double> 670 { 671 rat42_functor(void) : DenseFunctor<double>(3,9) {} 672 static const double x[9]; 673 static const double y[9]; 674 int operator()(const VectorXd &b, VectorXd &fvec) 675 { 676 assert(b.size()==3); 677 assert(fvec.size()==9); 678 for(int i=0; i<9; i++) { 679 fvec[i] = b[0] / (1.+exp(b[1]-b[2]*x[i])) - y[i]; 680 } 681 return 0; 682 } 683 684 int df(const VectorXd &b, MatrixXd &fjac) 685 { 686 assert(b.size()==3); 687 assert(fjac.rows()==9); 688 assert(fjac.cols()==3); 689 for(int i=0; i<9; i++) { 690 double e = exp(b[1]-b[2]*x[i]); 691 fjac(i,0) = 1./(1.+e); 692 fjac(i,1) = -b[0]*e/(1.+e)/(1.+e); 693 fjac(i,2) = +b[0]*e*x[i]/(1.+e)/(1.+e); 694 } 695 return 0; 696 } 697 }; 698 const double rat42_functor::x[9] = { 9.000E0, 14.000E0, 21.000E0, 28.000E0, 42.000E0, 57.000E0, 63.000E0, 70.000E0, 79.000E0 }; 699 const double rat42_functor::y[9] = { 8.930E0 ,10.800E0 ,18.590E0 ,22.330E0 ,39.350E0 ,56.110E0 ,61.730E0 ,64.620E0 ,67.080E0 }; 700 701 // http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky2.shtml 702 void testNistRat42(void) 703 { 704 const int n=3; 705 LevenbergMarquardtSpace::Status info; 706 707 VectorXd x(n); 708 709 /* 710 * First try 711 */ 712 x<< 100., 1., 0.1; 713 // do the computation 714 rat42_functor functor; 715 LevenbergMarquardt<rat42_functor> lm(functor); 716 info = lm.minimize(x); 717 718 // check return value 719 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeReductionTooSmall); 720 VERIFY_IS_EQUAL(lm.nfev(), 10); 721 VERIFY_IS_EQUAL(lm.njev(), 8); 722 // check norm^2 723 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.0565229338E+00); 724 // check x 725 VERIFY_IS_APPROX(x[0], 7.2462237576E+01); 726 VERIFY_IS_APPROX(x[1], 2.6180768402E+00); 727 VERIFY_IS_APPROX(x[2], 6.7359200066E-02); 728 729 /* 730 * Second try 731 */ 732 x<< 75., 2.5, 0.07; 733 // do the computation 734 info = lm.minimize(x); 735 736 // check return value 737 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeReductionTooSmall); 738 VERIFY_IS_EQUAL(lm.nfev(), 6); 739 VERIFY_IS_EQUAL(lm.njev(), 5); 740 // check norm^2 741 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.0565229338E+00); 742 // check x 743 VERIFY_IS_APPROX(x[0], 7.2462237576E+01); 744 VERIFY_IS_APPROX(x[1], 2.6180768402E+00); 745 VERIFY_IS_APPROX(x[2], 6.7359200066E-02); 746 } 747 748 struct MGH10_functor : DenseFunctor<double> 749 { 750 MGH10_functor(void) : DenseFunctor<double>(3,16) {} 751 static const double x[16]; 752 static const double y[16]; 753 int operator()(const VectorXd &b, VectorXd &fvec) 754 { 755 assert(b.size()==3); 756 assert(fvec.size()==16); 757 for(int i=0; i<16; i++) 758 fvec[i] = b[0] * exp(b[1]/(x[i]+b[2])) - y[i]; 759 return 0; 760 } 761 int df(const VectorXd &b, MatrixXd &fjac) 762 { 763 assert(b.size()==3); 764 assert(fjac.rows()==16); 765 assert(fjac.cols()==3); 766 for(int i=0; i<16; i++) { 767 double factor = 1./(x[i]+b[2]); 768 double e = exp(b[1]*factor); 769 fjac(i,0) = e; 770 fjac(i,1) = b[0]*factor*e; 771 fjac(i,2) = -b[1]*b[0]*factor*factor*e; 772 } 773 return 0; 774 } 775 }; 776 const double MGH10_functor::x[16] = { 5.000000E+01, 5.500000E+01, 6.000000E+01, 6.500000E+01, 7.000000E+01, 7.500000E+01, 8.000000E+01, 8.500000E+01, 9.000000E+01, 9.500000E+01, 1.000000E+02, 1.050000E+02, 1.100000E+02, 1.150000E+02, 1.200000E+02, 1.250000E+02 }; 777 const double MGH10_functor::y[16] = { 3.478000E+04, 2.861000E+04, 2.365000E+04, 1.963000E+04, 1.637000E+04, 1.372000E+04, 1.154000E+04, 9.744000E+03, 8.261000E+03, 7.030000E+03, 6.005000E+03, 5.147000E+03, 4.427000E+03, 3.820000E+03, 3.307000E+03, 2.872000E+03 }; 778 779 // http://www.itl.nist.gov/div898/strd/nls/data/mgh10.shtml 780 void testNistMGH10(void) 781 { 782 const int n=3; 783 LevenbergMarquardtSpace::Status info; 784 785 VectorXd x(n); 786 787 /* 788 * First try 789 */ 790 x<< 2., 400000., 25000.; 791 // do the computation 792 MGH10_functor functor; 793 LevenbergMarquardt<MGH10_functor> lm(functor); 794 info = lm.minimize(x); 795 ++g_test_level; 796 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeReductionTooSmall); 797 --g_test_level; 798 // was: VERIFY_IS_EQUAL(info, 1); 799 800 // check norm^2 801 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); 802 // check x 803 VERIFY_IS_APPROX(x[0], 5.6096364710E-03); 804 VERIFY_IS_APPROX(x[1], 6.1813463463E+03); 805 VERIFY_IS_APPROX(x[2], 3.4522363462E+02); 806 807 // check return value 808 809 ++g_test_level; 810 VERIFY_IS_EQUAL(lm.nfev(), 284 ); 811 VERIFY_IS_EQUAL(lm.njev(), 249 ); 812 --g_test_level; 813 VERIFY(lm.nfev() < 284 * LM_EVAL_COUNT_TOL); 814 VERIFY(lm.njev() < 249 * LM_EVAL_COUNT_TOL); 815 816 /* 817 * Second try 818 */ 819 x<< 0.02, 4000., 250.; 820 // do the computation 821 info = lm.minimize(x); 822 ++g_test_level; 823 VERIFY_IS_EQUAL(info, LevenbergMarquardtSpace::RelativeReductionTooSmall); 824 // was: VERIFY_IS_EQUAL(info, 1); 825 --g_test_level; 826 827 // check norm^2 828 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7945855171E+01); 829 // check x 830 VERIFY_IS_APPROX(x[0], 5.6096364710E-03); 831 VERIFY_IS_APPROX(x[1], 6.1813463463E+03); 832 VERIFY_IS_APPROX(x[2], 3.4522363462E+02); 833 834 // check return value 835 ++g_test_level; 836 VERIFY_IS_EQUAL(lm.nfev(), 126); 837 VERIFY_IS_EQUAL(lm.njev(), 116); 838 --g_test_level; 839 VERIFY(lm.nfev() < 126 * LM_EVAL_COUNT_TOL); 840 VERIFY(lm.njev() < 116 * LM_EVAL_COUNT_TOL); 841 } 842 843 844 struct BoxBOD_functor : DenseFunctor<double> 845 { 846 BoxBOD_functor(void) : DenseFunctor<double>(2,6) {} 847 static const double x[6]; 848 int operator()(const VectorXd &b, VectorXd &fvec) 849 { 850 static const double y[6] = { 109., 149., 149., 191., 213., 224. }; 851 assert(b.size()==2); 852 assert(fvec.size()==6); 853 for(int i=0; i<6; i++) 854 fvec[i] = b[0]*(1.-exp(-b[1]*x[i])) - y[i]; 855 return 0; 856 } 857 int df(const VectorXd &b, MatrixXd &fjac) 858 { 859 assert(b.size()==2); 860 assert(fjac.rows()==6); 861 assert(fjac.cols()==2); 862 for(int i=0; i<6; i++) { 863 double e = exp(-b[1]*x[i]); 864 fjac(i,0) = 1.-e; 865 fjac(i,1) = b[0]*x[i]*e; 866 } 867 return 0; 868 } 869 }; 870 const double BoxBOD_functor::x[6] = { 1., 2., 3., 5., 7., 10. }; 871 872 // http://www.itl.nist.gov/div898/strd/nls/data/boxbod.shtml 873 void testNistBoxBOD(void) 874 { 875 const int n=2; 876 int info; 877 878 VectorXd x(n); 879 880 /* 881 * First try 882 */ 883 x<< 1., 1.; 884 // do the computation 885 BoxBOD_functor functor; 886 LevenbergMarquardt<BoxBOD_functor> lm(functor); 887 lm.setFtol(1.E6*NumTraits<double>::epsilon()); 888 lm.setXtol(1.E6*NumTraits<double>::epsilon()); 889 lm.setFactor(10); 890 info = lm.minimize(x); 891 892 // check norm^2 893 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.1680088766E+03); 894 // check x 895 VERIFY_IS_APPROX(x[0], 2.1380940889E+02); 896 VERIFY_IS_APPROX(x[1], 5.4723748542E-01); 897 898 // check return value 899 VERIFY_IS_EQUAL(info, 1); 900 VERIFY(lm.nfev() < 31); // 31 901 VERIFY(lm.njev() < 25); // 25 902 903 /* 904 * Second try 905 */ 906 x<< 100., 0.75; 907 // do the computation 908 lm.resetParameters(); 909 lm.setFtol(NumTraits<double>::epsilon()); 910 lm.setXtol( NumTraits<double>::epsilon()); 911 info = lm.minimize(x); 912 913 // check return value 914 VERIFY_IS_EQUAL(info, 1); 915 ++g_test_level; 916 VERIFY_IS_EQUAL(lm.nfev(), 16 ); 917 VERIFY_IS_EQUAL(lm.njev(), 15 ); 918 --g_test_level; 919 VERIFY(lm.nfev() < 16 * LM_EVAL_COUNT_TOL); 920 VERIFY(lm.njev() < 15 * LM_EVAL_COUNT_TOL); 921 // check norm^2 922 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.1680088766E+03); 923 // check x 924 VERIFY_IS_APPROX(x[0], 2.1380940889E+02); 925 VERIFY_IS_APPROX(x[1], 5.4723748542E-01); 926 } 927 928 struct MGH17_functor : DenseFunctor<double> 929 { 930 MGH17_functor(void) : DenseFunctor<double>(5,33) {} 931 static const double x[33]; 932 static const double y[33]; 933 int operator()(const VectorXd &b, VectorXd &fvec) 934 { 935 assert(b.size()==5); 936 assert(fvec.size()==33); 937 for(int i=0; i<33; i++) 938 fvec[i] = b[0] + b[1]*exp(-b[3]*x[i]) + b[2]*exp(-b[4]*x[i]) - y[i]; 939 return 0; 940 } 941 int df(const VectorXd &b, MatrixXd &fjac) 942 { 943 assert(b.size()==5); 944 assert(fjac.rows()==33); 945 assert(fjac.cols()==5); 946 for(int i=0; i<33; i++) { 947 fjac(i,0) = 1.; 948 fjac(i,1) = exp(-b[3]*x[i]); 949 fjac(i,2) = exp(-b[4]*x[i]); 950 fjac(i,3) = -x[i]*b[1]*exp(-b[3]*x[i]); 951 fjac(i,4) = -x[i]*b[2]*exp(-b[4]*x[i]); 952 } 953 return 0; 954 } 955 }; 956 const double MGH17_functor::x[33] = { 0.000000E+00, 1.000000E+01, 2.000000E+01, 3.000000E+01, 4.000000E+01, 5.000000E+01, 6.000000E+01, 7.000000E+01, 8.000000E+01, 9.000000E+01, 1.000000E+02, 1.100000E+02, 1.200000E+02, 1.300000E+02, 1.400000E+02, 1.500000E+02, 1.600000E+02, 1.700000E+02, 1.800000E+02, 1.900000E+02, 2.000000E+02, 2.100000E+02, 2.200000E+02, 2.300000E+02, 2.400000E+02, 2.500000E+02, 2.600000E+02, 2.700000E+02, 2.800000E+02, 2.900000E+02, 3.000000E+02, 3.100000E+02, 3.200000E+02 }; 957 const double MGH17_functor::y[33] = { 8.440000E-01, 9.080000E-01, 9.320000E-01, 9.360000E-01, 9.250000E-01, 9.080000E-01, 8.810000E-01, 8.500000E-01, 8.180000E-01, 7.840000E-01, 7.510000E-01, 7.180000E-01, 6.850000E-01, 6.580000E-01, 6.280000E-01, 6.030000E-01, 5.800000E-01, 5.580000E-01, 5.380000E-01, 5.220000E-01, 5.060000E-01, 4.900000E-01, 4.780000E-01, 4.670000E-01, 4.570000E-01, 4.480000E-01, 4.380000E-01, 4.310000E-01, 4.240000E-01, 4.200000E-01, 4.140000E-01, 4.110000E-01, 4.060000E-01 }; 958 959 // http://www.itl.nist.gov/div898/strd/nls/data/mgh17.shtml 960 void testNistMGH17(void) 961 { 962 const int n=5; 963 int info; 964 965 VectorXd x(n); 966 967 /* 968 * First try 969 */ 970 x<< 50., 150., -100., 1., 2.; 971 // do the computation 972 MGH17_functor functor; 973 LevenbergMarquardt<MGH17_functor> lm(functor); 974 lm.setFtol(NumTraits<double>::epsilon()); 975 lm.setXtol(NumTraits<double>::epsilon()); 976 lm.setMaxfev(1000); 977 info = lm.minimize(x); 978 979 // check norm^2 980 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.4648946975E-05); 981 // check x 982 VERIFY_IS_APPROX(x[0], 3.7541005211E-01); 983 VERIFY_IS_APPROX(x[1], 1.9358469127E+00); 984 VERIFY_IS_APPROX(x[2], -1.4646871366E+00); 985 VERIFY_IS_APPROX(x[3], 1.2867534640E-02); 986 VERIFY_IS_APPROX(x[4], 2.2122699662E-02); 987 988 // check return value 989 // VERIFY_IS_EQUAL(info, 2); //FIXME Use (lm.info() == Success) 990 VERIFY(lm.nfev() < 700 ); // 602 991 VERIFY(lm.njev() < 600 ); // 545 992 993 /* 994 * Second try 995 */ 996 x<< 0.5 ,1.5 ,-1 ,0.01 ,0.02; 997 // do the computation 998 lm.resetParameters(); 999 info = lm.minimize(x); 1000 1001 // check return value 1002 VERIFY_IS_EQUAL(info, 1); 1003 VERIFY_IS_EQUAL(lm.nfev(), 18); 1004 VERIFY_IS_EQUAL(lm.njev(), 15); 1005 // check norm^2 1006 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.4648946975E-05); 1007 // check x 1008 VERIFY_IS_APPROX(x[0], 3.7541005211E-01); 1009 VERIFY_IS_APPROX(x[1], 1.9358469127E+00); 1010 VERIFY_IS_APPROX(x[2], -1.4646871366E+00); 1011 VERIFY_IS_APPROX(x[3], 1.2867534640E-02); 1012 VERIFY_IS_APPROX(x[4], 2.2122699662E-02); 1013 } 1014 1015 struct MGH09_functor : DenseFunctor<double> 1016 { 1017 MGH09_functor(void) : DenseFunctor<double>(4,11) {} 1018 static const double _x[11]; 1019 static const double y[11]; 1020 int operator()(const VectorXd &b, VectorXd &fvec) 1021 { 1022 assert(b.size()==4); 1023 assert(fvec.size()==11); 1024 for(int i=0; i<11; i++) { 1025 double x = _x[i], xx=x*x; 1026 fvec[i] = b[0]*(xx+x*b[1])/(xx+x*b[2]+b[3]) - y[i]; 1027 } 1028 return 0; 1029 } 1030 int df(const VectorXd &b, MatrixXd &fjac) 1031 { 1032 assert(b.size()==4); 1033 assert(fjac.rows()==11); 1034 assert(fjac.cols()==4); 1035 for(int i=0; i<11; i++) { 1036 double x = _x[i], xx=x*x; 1037 double factor = 1./(xx+x*b[2]+b[3]); 1038 fjac(i,0) = (xx+x*b[1]) * factor; 1039 fjac(i,1) = b[0]*x* factor; 1040 fjac(i,2) = - b[0]*(xx+x*b[1]) * x * factor * factor; 1041 fjac(i,3) = - b[0]*(xx+x*b[1]) * factor * factor; 1042 } 1043 return 0; 1044 } 1045 }; 1046 const double MGH09_functor::_x[11] = { 4., 2., 1., 5.E-1 , 2.5E-01, 1.670000E-01, 1.250000E-01, 1.E-01, 8.330000E-02, 7.140000E-02, 6.250000E-02 }; 1047 const double MGH09_functor::y[11] = { 1.957000E-01, 1.947000E-01, 1.735000E-01, 1.600000E-01, 8.440000E-02, 6.270000E-02, 4.560000E-02, 3.420000E-02, 3.230000E-02, 2.350000E-02, 2.460000E-02 }; 1048 1049 // http://www.itl.nist.gov/div898/strd/nls/data/mgh09.shtml 1050 void testNistMGH09(void) 1051 { 1052 const int n=4; 1053 int info; 1054 1055 VectorXd x(n); 1056 1057 /* 1058 * First try 1059 */ 1060 x<< 25., 39, 41.5, 39.; 1061 // do the computation 1062 MGH09_functor functor; 1063 LevenbergMarquardt<MGH09_functor> lm(functor); 1064 lm.setMaxfev(1000); 1065 info = lm.minimize(x); 1066 1067 // check norm^2 1068 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 3.0750560385E-04); 1069 // check x 1070 VERIFY_IS_APPROX(x[0], 0.1928077089); // should be 1.9280693458E-01 1071 VERIFY_IS_APPROX(x[1], 0.19126423573); // should be 1.9128232873E-01 1072 VERIFY_IS_APPROX(x[2], 0.12305309914); // should be 1.2305650693E-01 1073 VERIFY_IS_APPROX(x[3], 0.13605395375); // should be 1.3606233068E-01 1074 // check return value 1075 VERIFY_IS_EQUAL(info, 1); 1076 VERIFY(lm.nfev() < 510 ); // 490 1077 VERIFY(lm.njev() < 400 ); // 376 1078 1079 /* 1080 * Second try 1081 */ 1082 x<< 0.25, 0.39, 0.415, 0.39; 1083 // do the computation 1084 lm.resetParameters(); 1085 info = lm.minimize(x); 1086 1087 // check return value 1088 VERIFY_IS_EQUAL(info, 1); 1089 VERIFY_IS_EQUAL(lm.nfev(), 18); 1090 VERIFY_IS_EQUAL(lm.njev(), 16); 1091 // check norm^2 1092 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 3.0750560385E-04); 1093 // check x 1094 VERIFY_IS_APPROX(x[0], 0.19280781); // should be 1.9280693458E-01 1095 VERIFY_IS_APPROX(x[1], 0.19126265); // should be 1.9128232873E-01 1096 VERIFY_IS_APPROX(x[2], 0.12305280); // should be 1.2305650693E-01 1097 VERIFY_IS_APPROX(x[3], 0.13605322); // should be 1.3606233068E-01 1098 } 1099 1100 1101 1102 struct Bennett5_functor : DenseFunctor<double> 1103 { 1104 Bennett5_functor(void) : DenseFunctor<double>(3,154) {} 1105 static const double x[154]; 1106 static const double y[154]; 1107 int operator()(const VectorXd &b, VectorXd &fvec) 1108 { 1109 assert(b.size()==3); 1110 assert(fvec.size()==154); 1111 for(int i=0; i<154; i++) 1112 fvec[i] = b[0]* pow(b[1]+x[i],-1./b[2]) - y[i]; 1113 return 0; 1114 } 1115 int df(const VectorXd &b, MatrixXd &fjac) 1116 { 1117 assert(b.size()==3); 1118 assert(fjac.rows()==154); 1119 assert(fjac.cols()==3); 1120 for(int i=0; i<154; i++) { 1121 double e = pow(b[1]+x[i],-1./b[2]); 1122 fjac(i,0) = e; 1123 fjac(i,1) = - b[0]*e/b[2]/(b[1]+x[i]); 1124 fjac(i,2) = b[0]*e*log(b[1]+x[i])/b[2]/b[2]; 1125 } 1126 return 0; 1127 } 1128 }; 1129 const double Bennett5_functor::x[154] = { 7.447168E0, 8.102586E0, 8.452547E0, 8.711278E0, 8.916774E0, 9.087155E0, 9.232590E0, 9.359535E0, 9.472166E0, 9.573384E0, 9.665293E0, 9.749461E0, 9.827092E0, 9.899128E0, 9.966321E0, 10.029280E0, 10.088510E0, 10.144430E0, 10.197380E0, 10.247670E0, 10.295560E0, 10.341250E0, 10.384950E0, 10.426820E0, 10.467000E0, 10.505640E0, 10.542830E0, 10.578690E0, 10.613310E0, 10.646780E0, 10.679150E0, 10.710520E0, 10.740920E0, 10.770440E0, 10.799100E0, 10.826970E0, 10.854080E0, 10.880470E0, 10.906190E0, 10.931260E0, 10.955720E0, 10.979590E0, 11.002910E0, 11.025700E0, 11.047980E0, 11.069770E0, 11.091100E0, 11.111980E0, 11.132440E0, 11.152480E0, 11.172130E0, 11.191410E0, 11.210310E0, 11.228870E0, 11.247090E0, 11.264980E0, 11.282560E0, 11.299840E0, 11.316820E0, 11.333520E0, 11.349940E0, 11.366100E0, 11.382000E0, 11.397660E0, 11.413070E0, 11.428240E0, 11.443200E0, 11.457930E0, 11.472440E0, 11.486750E0, 11.500860E0, 11.514770E0, 11.528490E0, 11.542020E0, 11.555380E0, 11.568550E0, 1130 11.581560E0, 11.594420E0, 11.607121E0, 11.619640E0, 11.632000E0, 11.644210E0, 11.656280E0, 11.668200E0, 11.679980E0, 11.691620E0, 11.703130E0, 11.714510E0, 11.725760E0, 11.736880E0, 11.747890E0, 11.758780E0, 11.769550E0, 11.780200E0, 11.790730E0, 11.801160E0, 11.811480E0, 11.821700E0, 11.831810E0, 11.841820E0, 11.851730E0, 11.861550E0, 11.871270E0, 11.880890E0, 11.890420E0, 11.899870E0, 11.909220E0, 11.918490E0, 11.927680E0, 11.936780E0, 11.945790E0, 11.954730E0, 11.963590E0, 11.972370E0, 11.981070E0, 11.989700E0, 11.998260E0, 12.006740E0, 12.015150E0, 12.023490E0, 12.031760E0, 12.039970E0, 12.048100E0, 12.056170E0, 12.064180E0, 12.072120E0, 12.080010E0, 12.087820E0, 12.095580E0, 12.103280E0, 12.110920E0, 12.118500E0, 12.126030E0, 12.133500E0, 12.140910E0, 12.148270E0, 12.155570E0, 12.162830E0, 12.170030E0, 12.177170E0, 12.184270E0, 12.191320E0, 12.198320E0, 12.205270E0, 12.212170E0, 12.219030E0, 12.225840E0, 12.232600E0, 12.239320E0, 12.245990E0, 12.252620E0, 12.259200E0, 12.265750E0, 12.272240E0 }; 1131 const double Bennett5_functor::y[154] = { -34.834702E0 ,-34.393200E0 ,-34.152901E0 ,-33.979099E0 ,-33.845901E0 ,-33.732899E0 ,-33.640301E0 ,-33.559200E0 ,-33.486801E0 ,-33.423100E0 ,-33.365101E0 ,-33.313000E0 ,-33.260899E0 ,-33.217400E0 ,-33.176899E0 ,-33.139198E0 ,-33.101601E0 ,-33.066799E0 ,-33.035000E0 ,-33.003101E0 ,-32.971298E0 ,-32.942299E0 ,-32.916302E0 ,-32.890202E0 ,-32.864101E0 ,-32.841000E0 ,-32.817799E0 ,-32.797501E0 ,-32.774300E0 ,-32.757000E0 ,-32.733799E0 ,-32.716400E0 ,-32.699100E0 ,-32.678799E0 ,-32.661400E0 ,-32.644001E0 ,-32.626701E0 ,-32.612202E0 ,-32.597698E0 ,-32.583199E0 ,-32.568699E0 ,-32.554298E0 ,-32.539799E0 ,-32.525299E0 ,-32.510799E0 ,-32.499199E0 ,-32.487598E0 ,-32.473202E0 ,-32.461601E0 ,-32.435501E0 ,-32.435501E0 ,-32.426800E0 ,-32.412300E0 ,-32.400799E0 ,-32.392101E0 ,-32.380501E0 ,-32.366001E0 ,-32.357300E0 ,-32.348598E0 ,-32.339901E0 ,-32.328400E0 ,-32.319698E0 ,-32.311001E0 ,-32.299400E0 ,-32.290699E0 ,-32.282001E0 ,-32.273300E0 ,-32.264599E0 ,-32.256001E0 ,-32.247299E0 1132 ,-32.238602E0 ,-32.229900E0 ,-32.224098E0 ,-32.215401E0 ,-32.203800E0 ,-32.198002E0 ,-32.189400E0 ,-32.183601E0 ,-32.174900E0 ,-32.169102E0 ,-32.163300E0 ,-32.154598E0 ,-32.145901E0 ,-32.140099E0 ,-32.131401E0 ,-32.125599E0 ,-32.119801E0 ,-32.111198E0 ,-32.105400E0 ,-32.096699E0 ,-32.090900E0 ,-32.088001E0 ,-32.079300E0 ,-32.073502E0 ,-32.067699E0 ,-32.061901E0 ,-32.056099E0 ,-32.050301E0 ,-32.044498E0 ,-32.038799E0 ,-32.033001E0 ,-32.027199E0 ,-32.024300E0 ,-32.018501E0 ,-32.012699E0 ,-32.004002E0 ,-32.001099E0 ,-31.995300E0 ,-31.989500E0 ,-31.983700E0 ,-31.977900E0 ,-31.972099E0 ,-31.969299E0 ,-31.963501E0 ,-31.957701E0 ,-31.951900E0 ,-31.946100E0 ,-31.940300E0 ,-31.937401E0 ,-31.931601E0 ,-31.925800E0 ,-31.922899E0 ,-31.917101E0 ,-31.911301E0 ,-31.908400E0 ,-31.902599E0 ,-31.896900E0 ,-31.893999E0 ,-31.888201E0 ,-31.885300E0 ,-31.882401E0 ,-31.876600E0 ,-31.873699E0 ,-31.867901E0 ,-31.862101E0 ,-31.859200E0 ,-31.856300E0 ,-31.850500E0 ,-31.844700E0 ,-31.841801E0 ,-31.838900E0 ,-31.833099E0 ,-31.830200E0 , 1133 -31.827299E0 ,-31.821600E0 ,-31.818701E0 ,-31.812901E0 ,-31.809999E0 ,-31.807100E0 ,-31.801300E0 ,-31.798401E0 ,-31.795500E0 ,-31.789700E0 ,-31.786800E0 }; 1134 1135 // http://www.itl.nist.gov/div898/strd/nls/data/bennett5.shtml 1136 void testNistBennett5(void) 1137 { 1138 const int n=3; 1139 int info; 1140 1141 VectorXd x(n); 1142 1143 /* 1144 * First try 1145 */ 1146 x<< -2000., 50., 0.8; 1147 // do the computation 1148 Bennett5_functor functor; 1149 LevenbergMarquardt<Bennett5_functor> lm(functor); 1150 lm.setMaxfev(1000); 1151 info = lm.minimize(x); 1152 1153 // check return value 1154 VERIFY_IS_EQUAL(info, 1); 1155 VERIFY_IS_EQUAL(lm.nfev(), 758); 1156 VERIFY_IS_EQUAL(lm.njev(), 744); 1157 // check norm^2 1158 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.2404744073E-04); 1159 // check x 1160 VERIFY_IS_APPROX(x[0], -2.5235058043E+03); 1161 VERIFY_IS_APPROX(x[1], 4.6736564644E+01); 1162 VERIFY_IS_APPROX(x[2], 9.3218483193E-01); 1163 /* 1164 * Second try 1165 */ 1166 x<< -1500., 45., 0.85; 1167 // do the computation 1168 lm.resetParameters(); 1169 info = lm.minimize(x); 1170 1171 // check return value 1172 VERIFY_IS_EQUAL(info, 1); 1173 VERIFY_IS_EQUAL(lm.nfev(), 203); 1174 VERIFY_IS_EQUAL(lm.njev(), 192); 1175 // check norm^2 1176 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.2404744073E-04); 1177 // check x 1178 VERIFY_IS_APPROX(x[0], -2523.3007865); // should be -2.5235058043E+03 1179 VERIFY_IS_APPROX(x[1], 46.735705771); // should be 4.6736564644E+01); 1180 VERIFY_IS_APPROX(x[2], 0.93219881891); // should be 9.3218483193E-01); 1181 } 1182 1183 struct thurber_functor : DenseFunctor<double> 1184 { 1185 thurber_functor(void) : DenseFunctor<double>(7,37) {} 1186 static const double _x[37]; 1187 static const double _y[37]; 1188 int operator()(const VectorXd &b, VectorXd &fvec) 1189 { 1190 // int called=0; printf("call hahn1_functor with iflag=%d, called=%d\n", iflag, called); if (iflag==1) called++; 1191 assert(b.size()==7); 1192 assert(fvec.size()==37); 1193 for(int i=0; i<37; i++) { 1194 double x=_x[i], xx=x*x, xxx=xx*x; 1195 fvec[i] = (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) / (1.+b[4]*x+b[5]*xx+b[6]*xxx) - _y[i]; 1196 } 1197 return 0; 1198 } 1199 int df(const VectorXd &b, MatrixXd &fjac) 1200 { 1201 assert(b.size()==7); 1202 assert(fjac.rows()==37); 1203 assert(fjac.cols()==7); 1204 for(int i=0; i<37; i++) { 1205 double x=_x[i], xx=x*x, xxx=xx*x; 1206 double fact = 1./(1.+b[4]*x+b[5]*xx+b[6]*xxx); 1207 fjac(i,0) = 1.*fact; 1208 fjac(i,1) = x*fact; 1209 fjac(i,2) = xx*fact; 1210 fjac(i,3) = xxx*fact; 1211 fact = - (b[0]+b[1]*x+b[2]*xx+b[3]*xxx) * fact * fact; 1212 fjac(i,4) = x*fact; 1213 fjac(i,5) = xx*fact; 1214 fjac(i,6) = xxx*fact; 1215 } 1216 return 0; 1217 } 1218 }; 1219 const double thurber_functor::_x[37] = { -3.067E0, -2.981E0, -2.921E0, -2.912E0, -2.840E0, -2.797E0, -2.702E0, -2.699E0, -2.633E0, -2.481E0, -2.363E0, -2.322E0, -1.501E0, -1.460E0, -1.274E0, -1.212E0, -1.100E0, -1.046E0, -0.915E0, -0.714E0, -0.566E0, -0.545E0, -0.400E0, -0.309E0, -0.109E0, -0.103E0, 0.010E0, 0.119E0, 0.377E0, 0.790E0, 0.963E0, 1.006E0, 1.115E0, 1.572E0, 1.841E0, 2.047E0, 2.200E0 }; 1220 const double thurber_functor::_y[37] = { 80.574E0, 84.248E0, 87.264E0, 87.195E0, 89.076E0, 89.608E0, 89.868E0, 90.101E0, 92.405E0, 95.854E0, 100.696E0, 101.060E0, 401.672E0, 390.724E0, 567.534E0, 635.316E0, 733.054E0, 759.087E0, 894.206E0, 990.785E0, 1090.109E0, 1080.914E0, 1122.643E0, 1178.351E0, 1260.531E0, 1273.514E0, 1288.339E0, 1327.543E0, 1353.863E0, 1414.509E0, 1425.208E0, 1421.384E0, 1442.962E0, 1464.350E0, 1468.705E0, 1447.894E0, 1457.628E0}; 1221 1222 // http://www.itl.nist.gov/div898/strd/nls/data/thurber.shtml 1223 void testNistThurber(void) 1224 { 1225 const int n=7; 1226 int info; 1227 1228 VectorXd x(n); 1229 1230 /* 1231 * First try 1232 */ 1233 x<< 1000 ,1000 ,400 ,40 ,0.7,0.3,0.0 ; 1234 // do the computation 1235 thurber_functor functor; 1236 LevenbergMarquardt<thurber_functor> lm(functor); 1237 lm.setFtol(1.E4*NumTraits<double>::epsilon()); 1238 lm.setXtol(1.E4*NumTraits<double>::epsilon()); 1239 info = lm.minimize(x); 1240 1241 // check return value 1242 VERIFY_IS_EQUAL(info, 1); 1243 VERIFY_IS_EQUAL(lm.nfev(), 39); 1244 VERIFY_IS_EQUAL(lm.njev(), 36); 1245 // check norm^2 1246 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6427082397E+03); 1247 // check x 1248 VERIFY_IS_APPROX(x[0], 1.2881396800E+03); 1249 VERIFY_IS_APPROX(x[1], 1.4910792535E+03); 1250 VERIFY_IS_APPROX(x[2], 5.8323836877E+02); 1251 VERIFY_IS_APPROX(x[3], 7.5416644291E+01); 1252 VERIFY_IS_APPROX(x[4], 9.6629502864E-01); 1253 VERIFY_IS_APPROX(x[5], 3.9797285797E-01); 1254 VERIFY_IS_APPROX(x[6], 4.9727297349E-02); 1255 1256 /* 1257 * Second try 1258 */ 1259 x<< 1300 ,1500 ,500 ,75 ,1 ,0.4 ,0.05 ; 1260 // do the computation 1261 lm.resetParameters(); 1262 lm.setFtol(1.E4*NumTraits<double>::epsilon()); 1263 lm.setXtol(1.E4*NumTraits<double>::epsilon()); 1264 info = lm.minimize(x); 1265 1266 // check return value 1267 VERIFY_IS_EQUAL(info, 1); 1268 VERIFY_IS_EQUAL(lm.nfev(), 29); 1269 VERIFY_IS_EQUAL(lm.njev(), 28); 1270 // check norm^2 1271 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 5.6427082397E+03); 1272 // check x 1273 VERIFY_IS_APPROX(x[0], 1.2881396800E+03); 1274 VERIFY_IS_APPROX(x[1], 1.4910792535E+03); 1275 VERIFY_IS_APPROX(x[2], 5.8323836877E+02); 1276 VERIFY_IS_APPROX(x[3], 7.5416644291E+01); 1277 VERIFY_IS_APPROX(x[4], 9.6629502864E-01); 1278 VERIFY_IS_APPROX(x[5], 3.9797285797E-01); 1279 VERIFY_IS_APPROX(x[6], 4.9727297349E-02); 1280 } 1281 1282 struct rat43_functor : DenseFunctor<double> 1283 { 1284 rat43_functor(void) : DenseFunctor<double>(4,15) {} 1285 static const double x[15]; 1286 static const double y[15]; 1287 int operator()(const VectorXd &b, VectorXd &fvec) 1288 { 1289 assert(b.size()==4); 1290 assert(fvec.size()==15); 1291 for(int i=0; i<15; i++) 1292 fvec[i] = b[0] * pow(1.+exp(b[1]-b[2]*x[i]),-1./b[3]) - y[i]; 1293 return 0; 1294 } 1295 int df(const VectorXd &b, MatrixXd &fjac) 1296 { 1297 assert(b.size()==4); 1298 assert(fjac.rows()==15); 1299 assert(fjac.cols()==4); 1300 for(int i=0; i<15; i++) { 1301 double e = exp(b[1]-b[2]*x[i]); 1302 double power = -1./b[3]; 1303 fjac(i,0) = pow(1.+e, power); 1304 fjac(i,1) = power*b[0]*e*pow(1.+e, power-1.); 1305 fjac(i,2) = -power*b[0]*e*x[i]*pow(1.+e, power-1.); 1306 fjac(i,3) = b[0]*power*power*log(1.+e)*pow(1.+e, power); 1307 } 1308 return 0; 1309 } 1310 }; 1311 const double rat43_functor::x[15] = { 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15. }; 1312 const double rat43_functor::y[15] = { 16.08, 33.83, 65.80, 97.20, 191.55, 326.20, 386.87, 520.53, 590.03, 651.92, 724.93, 699.56, 689.96, 637.56, 717.41 }; 1313 1314 // http://www.itl.nist.gov/div898/strd/nls/data/ratkowsky3.shtml 1315 void testNistRat43(void) 1316 { 1317 const int n=4; 1318 int info; 1319 1320 VectorXd x(n); 1321 1322 /* 1323 * First try 1324 */ 1325 x<< 100., 10., 1., 1.; 1326 // do the computation 1327 rat43_functor functor; 1328 LevenbergMarquardt<rat43_functor> lm(functor); 1329 lm.setFtol(1.E6*NumTraits<double>::epsilon()); 1330 lm.setXtol(1.E6*NumTraits<double>::epsilon()); 1331 info = lm.minimize(x); 1332 1333 // check return value 1334 VERIFY_IS_EQUAL(info, 1); 1335 VERIFY_IS_EQUAL(lm.nfev(), 27); 1336 VERIFY_IS_EQUAL(lm.njev(), 20); 1337 // check norm^2 1338 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7864049080E+03); 1339 // check x 1340 VERIFY_IS_APPROX(x[0], 6.9964151270E+02); 1341 VERIFY_IS_APPROX(x[1], 5.2771253025E+00); 1342 VERIFY_IS_APPROX(x[2], 7.5962938329E-01); 1343 VERIFY_IS_APPROX(x[3], 1.2792483859E+00); 1344 1345 /* 1346 * Second try 1347 */ 1348 x<< 700., 5., 0.75, 1.3; 1349 // do the computation 1350 lm.resetParameters(); 1351 lm.setFtol(1.E5*NumTraits<double>::epsilon()); 1352 lm.setXtol(1.E5*NumTraits<double>::epsilon()); 1353 info = lm.minimize(x); 1354 1355 // check return value 1356 VERIFY_IS_EQUAL(info, 1); 1357 VERIFY_IS_EQUAL(lm.nfev(), 9); 1358 VERIFY_IS_EQUAL(lm.njev(), 8); 1359 // check norm^2 1360 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 8.7864049080E+03); 1361 // check x 1362 VERIFY_IS_APPROX(x[0], 6.9964151270E+02); 1363 VERIFY_IS_APPROX(x[1], 5.2771253025E+00); 1364 VERIFY_IS_APPROX(x[2], 7.5962938329E-01); 1365 VERIFY_IS_APPROX(x[3], 1.2792483859E+00); 1366 } 1367 1368 1369 1370 struct eckerle4_functor : DenseFunctor<double> 1371 { 1372 eckerle4_functor(void) : DenseFunctor<double>(3,35) {} 1373 static const double x[35]; 1374 static const double y[35]; 1375 int operator()(const VectorXd &b, VectorXd &fvec) 1376 { 1377 assert(b.size()==3); 1378 assert(fvec.size()==35); 1379 for(int i=0; i<35; i++) 1380 fvec[i] = b[0]/b[1] * exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/(b[1]*b[1])) - y[i]; 1381 return 0; 1382 } 1383 int df(const VectorXd &b, MatrixXd &fjac) 1384 { 1385 assert(b.size()==3); 1386 assert(fjac.rows()==35); 1387 assert(fjac.cols()==3); 1388 for(int i=0; i<35; i++) { 1389 double b12 = b[1]*b[1]; 1390 double e = exp(-0.5*(x[i]-b[2])*(x[i]-b[2])/b12); 1391 fjac(i,0) = e / b[1]; 1392 fjac(i,1) = ((x[i]-b[2])*(x[i]-b[2])/b12-1.) * b[0]*e/b12; 1393 fjac(i,2) = (x[i]-b[2])*e*b[0]/b[1]/b12; 1394 } 1395 return 0; 1396 } 1397 }; 1398 const double eckerle4_functor::x[35] = { 400.0, 405.0, 410.0, 415.0, 420.0, 425.0, 430.0, 435.0, 436.5, 438.0, 439.5, 441.0, 442.5, 444.0, 445.5, 447.0, 448.5, 450.0, 451.5, 453.0, 454.5, 456.0, 457.5, 459.0, 460.5, 462.0, 463.5, 465.0, 470.0, 475.0, 480.0, 485.0, 490.0, 495.0, 500.0}; 1399 const double eckerle4_functor::y[35] = { 0.0001575, 0.0001699, 0.0002350, 0.0003102, 0.0004917, 0.0008710, 0.0017418, 0.0046400, 0.0065895, 0.0097302, 0.0149002, 0.0237310, 0.0401683, 0.0712559, 0.1264458, 0.2073413, 0.2902366, 0.3445623, 0.3698049, 0.3668534, 0.3106727, 0.2078154, 0.1164354, 0.0616764, 0.0337200, 0.0194023, 0.0117831, 0.0074357, 0.0022732, 0.0008800, 0.0004579, 0.0002345, 0.0001586, 0.0001143, 0.0000710 }; 1400 1401 // http://www.itl.nist.gov/div898/strd/nls/data/eckerle4.shtml 1402 void testNistEckerle4(void) 1403 { 1404 const int n=3; 1405 int info; 1406 1407 VectorXd x(n); 1408 1409 /* 1410 * First try 1411 */ 1412 x<< 1., 10., 500.; 1413 // do the computation 1414 eckerle4_functor functor; 1415 LevenbergMarquardt<eckerle4_functor> lm(functor); 1416 info = lm.minimize(x); 1417 1418 // check return value 1419 VERIFY_IS_EQUAL(info, 1); 1420 VERIFY_IS_EQUAL(lm.nfev(), 18); 1421 VERIFY_IS_EQUAL(lm.njev(), 15); 1422 // check norm^2 1423 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.4635887487E-03); 1424 // check x 1425 VERIFY_IS_APPROX(x[0], 1.5543827178); 1426 VERIFY_IS_APPROX(x[1], 4.0888321754); 1427 VERIFY_IS_APPROX(x[2], 4.5154121844E+02); 1428 1429 /* 1430 * Second try 1431 */ 1432 x<< 1.5, 5., 450.; 1433 // do the computation 1434 info = lm.minimize(x); 1435 1436 // check return value 1437 VERIFY_IS_EQUAL(info, 1); 1438 VERIFY_IS_EQUAL(lm.nfev(), 7); 1439 VERIFY_IS_EQUAL(lm.njev(), 6); 1440 // check norm^2 1441 VERIFY_IS_APPROX(lm.fvec().squaredNorm(), 1.4635887487E-03); 1442 // check x 1443 VERIFY_IS_APPROX(x[0], 1.5543827178); 1444 VERIFY_IS_APPROX(x[1], 4.0888321754); 1445 VERIFY_IS_APPROX(x[2], 4.5154121844E+02); 1446 } 1447 1448 void test_levenberg_marquardt() 1449 { 1450 // Tests using the examples provided by (c)minpack 1451 CALL_SUBTEST(testLmder1()); 1452 CALL_SUBTEST(testLmder()); 1453 CALL_SUBTEST(testLmdif1()); 1454 // CALL_SUBTEST(testLmstr1()); 1455 // CALL_SUBTEST(testLmstr()); 1456 CALL_SUBTEST(testLmdif()); 1457 1458 // NIST tests, level of difficulty = "Lower" 1459 CALL_SUBTEST(testNistMisra1a()); 1460 CALL_SUBTEST(testNistChwirut2()); 1461 1462 // NIST tests, level of difficulty = "Average" 1463 CALL_SUBTEST(testNistHahn1()); 1464 CALL_SUBTEST(testNistMisra1d()); 1465 CALL_SUBTEST(testNistMGH17()); 1466 CALL_SUBTEST(testNistLanczos1()); 1467 1468 // // NIST tests, level of difficulty = "Higher" 1469 CALL_SUBTEST(testNistRat42()); 1470 CALL_SUBTEST(testNistMGH10()); 1471 CALL_SUBTEST(testNistBoxBOD()); 1472 // CALL_SUBTEST(testNistMGH09()); 1473 CALL_SUBTEST(testNistBennett5()); 1474 CALL_SUBTEST(testNistThurber()); 1475 CALL_SUBTEST(testNistRat43()); 1476 CALL_SUBTEST(testNistEckerle4()); 1477 } 1478