1 // -*- coding: utf-8 2 // vim: set fileencoding=utf-8 3 4 // This file is part of Eigen, a lightweight C++ template library 5 // for linear algebra. 6 // 7 // Copyright (C) 2009 Thomas Capricelli <orzel (at) freehackers.org> 8 // 9 // This Source Code Form is subject to the terms of the Mozilla 10 // Public License v. 2.0. If a copy of the MPL was not distributed 11 // with this file, You can obtain one at http://mozilla.org/MPL/2.0/. 12 13 #ifndef EIGEN_LEVENBERGMARQUARDT__H 14 #define EIGEN_LEVENBERGMARQUARDT__H 15 16 namespace Eigen { 17 18 namespace LevenbergMarquardtSpace { 19 enum Status { 20 NotStarted = -2, 21 Running = -1, 22 ImproperInputParameters = 0, 23 RelativeReductionTooSmall = 1, 24 RelativeErrorTooSmall = 2, 25 RelativeErrorAndReductionTooSmall = 3, 26 CosinusTooSmall = 4, 27 TooManyFunctionEvaluation = 5, 28 FtolTooSmall = 6, 29 XtolTooSmall = 7, 30 GtolTooSmall = 8, 31 UserAsked = 9 32 }; 33 } 34 35 36 37 /** 38 * \ingroup NonLinearOptimization_Module 39 * \brief Performs non linear optimization over a non-linear function, 40 * using a variant of the Levenberg Marquardt algorithm. 41 * 42 * Check wikipedia for more information. 43 * http://en.wikipedia.org/wiki/Levenberg%E2%80%93Marquardt_algorithm 44 */ 45 template<typename FunctorType, typename Scalar=double> 46 class LevenbergMarquardt 47 { 48 public: 49 LevenbergMarquardt(FunctorType &_functor) 50 : functor(_functor) { nfev = njev = iter = 0; fnorm = gnorm = 0.; useExternalScaling=false; } 51 52 typedef DenseIndex Index; 53 54 struct Parameters { 55 Parameters() 56 : factor(Scalar(100.)) 57 , maxfev(400) 58 , ftol(internal::sqrt(NumTraits<Scalar>::epsilon())) 59 , xtol(internal::sqrt(NumTraits<Scalar>::epsilon())) 60 , gtol(Scalar(0.)) 61 , epsfcn(Scalar(0.)) {} 62 Scalar factor; 63 Index maxfev; // maximum number of function evaluation 64 Scalar ftol; 65 Scalar xtol; 66 Scalar gtol; 67 Scalar epsfcn; 68 }; 69 70 typedef Matrix< Scalar, Dynamic, 1 > FVectorType; 71 typedef Matrix< Scalar, Dynamic, Dynamic > JacobianType; 72 73 LevenbergMarquardtSpace::Status lmder1( 74 FVectorType &x, 75 const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon()) 76 ); 77 78 LevenbergMarquardtSpace::Status minimize(FVectorType &x); 79 LevenbergMarquardtSpace::Status minimizeInit(FVectorType &x); 80 LevenbergMarquardtSpace::Status minimizeOneStep(FVectorType &x); 81 82 static LevenbergMarquardtSpace::Status lmdif1( 83 FunctorType &functor, 84 FVectorType &x, 85 Index *nfev, 86 const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon()) 87 ); 88 89 LevenbergMarquardtSpace::Status lmstr1( 90 FVectorType &x, 91 const Scalar tol = internal::sqrt(NumTraits<Scalar>::epsilon()) 92 ); 93 94 LevenbergMarquardtSpace::Status minimizeOptimumStorage(FVectorType &x); 95 LevenbergMarquardtSpace::Status minimizeOptimumStorageInit(FVectorType &x); 96 LevenbergMarquardtSpace::Status minimizeOptimumStorageOneStep(FVectorType &x); 97 98 void resetParameters(void) { parameters = Parameters(); } 99 100 Parameters parameters; 101 FVectorType fvec, qtf, diag; 102 JacobianType fjac; 103 PermutationMatrix<Dynamic,Dynamic> permutation; 104 Index nfev; 105 Index njev; 106 Index iter; 107 Scalar fnorm, gnorm; 108 bool useExternalScaling; 109 110 Scalar lm_param(void) { return par; } 111 private: 112 FunctorType &functor; 113 Index n; 114 Index m; 115 FVectorType wa1, wa2, wa3, wa4; 116 117 Scalar par, sum; 118 Scalar temp, temp1, temp2; 119 Scalar delta; 120 Scalar ratio; 121 Scalar pnorm, xnorm, fnorm1, actred, dirder, prered; 122 123 LevenbergMarquardt& operator=(const LevenbergMarquardt&); 124 }; 125 126 template<typename FunctorType, typename Scalar> 127 LevenbergMarquardtSpace::Status 128 LevenbergMarquardt<FunctorType,Scalar>::lmder1( 129 FVectorType &x, 130 const Scalar tol 131 ) 132 { 133 n = x.size(); 134 m = functor.values(); 135 136 /* check the input parameters for errors. */ 137 if (n <= 0 || m < n || tol < 0.) 138 return LevenbergMarquardtSpace::ImproperInputParameters; 139 140 resetParameters(); 141 parameters.ftol = tol; 142 parameters.xtol = tol; 143 parameters.maxfev = 100*(n+1); 144 145 return minimize(x); 146 } 147 148 149 template<typename FunctorType, typename Scalar> 150 LevenbergMarquardtSpace::Status 151 LevenbergMarquardt<FunctorType,Scalar>::minimize(FVectorType &x) 152 { 153 LevenbergMarquardtSpace::Status status = minimizeInit(x); 154 if (status==LevenbergMarquardtSpace::ImproperInputParameters) 155 return status; 156 do { 157 status = minimizeOneStep(x); 158 } while (status==LevenbergMarquardtSpace::Running); 159 return status; 160 } 161 162 template<typename FunctorType, typename Scalar> 163 LevenbergMarquardtSpace::Status 164 LevenbergMarquardt<FunctorType,Scalar>::minimizeInit(FVectorType &x) 165 { 166 n = x.size(); 167 m = functor.values(); 168 169 wa1.resize(n); wa2.resize(n); wa3.resize(n); 170 wa4.resize(m); 171 fvec.resize(m); 172 fjac.resize(m, n); 173 if (!useExternalScaling) 174 diag.resize(n); 175 assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'"); 176 qtf.resize(n); 177 178 /* Function Body */ 179 nfev = 0; 180 njev = 0; 181 182 /* check the input parameters for errors. */ 183 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) 184 return LevenbergMarquardtSpace::ImproperInputParameters; 185 186 if (useExternalScaling) 187 for (Index j = 0; j < n; ++j) 188 if (diag[j] <= 0.) 189 return LevenbergMarquardtSpace::ImproperInputParameters; 190 191 /* evaluate the function at the starting point */ 192 /* and calculate its norm. */ 193 nfev = 1; 194 if ( functor(x, fvec) < 0) 195 return LevenbergMarquardtSpace::UserAsked; 196 fnorm = fvec.stableNorm(); 197 198 /* initialize levenberg-marquardt parameter and iteration counter. */ 199 par = 0.; 200 iter = 1; 201 202 return LevenbergMarquardtSpace::NotStarted; 203 } 204 205 template<typename FunctorType, typename Scalar> 206 LevenbergMarquardtSpace::Status 207 LevenbergMarquardt<FunctorType,Scalar>::minimizeOneStep(FVectorType &x) 208 { 209 assert(x.size()==n); // check the caller is not cheating us 210 211 /* calculate the jacobian matrix. */ 212 Index df_ret = functor.df(x, fjac); 213 if (df_ret<0) 214 return LevenbergMarquardtSpace::UserAsked; 215 if (df_ret>0) 216 // numerical diff, we evaluated the function df_ret times 217 nfev += df_ret; 218 else njev++; 219 220 /* compute the qr factorization of the jacobian. */ 221 wa2 = fjac.colwise().blueNorm(); 222 ColPivHouseholderQR<JacobianType> qrfac(fjac); 223 fjac = qrfac.matrixQR(); 224 permutation = qrfac.colsPermutation(); 225 226 /* on the first iteration and if external scaling is not used, scale according */ 227 /* to the norms of the columns of the initial jacobian. */ 228 if (iter == 1) { 229 if (!useExternalScaling) 230 for (Index j = 0; j < n; ++j) 231 diag[j] = (wa2[j]==0.)? 1. : wa2[j]; 232 233 /* on the first iteration, calculate the norm of the scaled x */ 234 /* and initialize the step bound delta. */ 235 xnorm = diag.cwiseProduct(x).stableNorm(); 236 delta = parameters.factor * xnorm; 237 if (delta == 0.) 238 delta = parameters.factor; 239 } 240 241 /* form (q transpose)*fvec and store the first n components in */ 242 /* qtf. */ 243 wa4 = fvec; 244 wa4.applyOnTheLeft(qrfac.householderQ().adjoint()); 245 qtf = wa4.head(n); 246 247 /* compute the norm of the scaled gradient. */ 248 gnorm = 0.; 249 if (fnorm != 0.) 250 for (Index j = 0; j < n; ++j) 251 if (wa2[permutation.indices()[j]] != 0.) 252 gnorm = (std::max)(gnorm, internal::abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]])); 253 254 /* test for convergence of the gradient norm. */ 255 if (gnorm <= parameters.gtol) 256 return LevenbergMarquardtSpace::CosinusTooSmall; 257 258 /* rescale if necessary. */ 259 if (!useExternalScaling) 260 diag = diag.cwiseMax(wa2); 261 262 do { 263 264 /* determine the levenberg-marquardt parameter. */ 265 internal::lmpar2<Scalar>(qrfac, diag, qtf, delta, par, wa1); 266 267 /* store the direction p and x + p. calculate the norm of p. */ 268 wa1 = -wa1; 269 wa2 = x + wa1; 270 pnorm = diag.cwiseProduct(wa1).stableNorm(); 271 272 /* on the first iteration, adjust the initial step bound. */ 273 if (iter == 1) 274 delta = (std::min)(delta,pnorm); 275 276 /* evaluate the function at x + p and calculate its norm. */ 277 if ( functor(wa2, wa4) < 0) 278 return LevenbergMarquardtSpace::UserAsked; 279 ++nfev; 280 fnorm1 = wa4.stableNorm(); 281 282 /* compute the scaled actual reduction. */ 283 actred = -1.; 284 if (Scalar(.1) * fnorm1 < fnorm) 285 actred = 1. - internal::abs2(fnorm1 / fnorm); 286 287 /* compute the scaled predicted reduction and */ 288 /* the scaled directional derivative. */ 289 wa3 = fjac.template triangularView<Upper>() * (qrfac.colsPermutation().inverse() *wa1); 290 temp1 = internal::abs2(wa3.stableNorm() / fnorm); 291 temp2 = internal::abs2(internal::sqrt(par) * pnorm / fnorm); 292 prered = temp1 + temp2 / Scalar(.5); 293 dirder = -(temp1 + temp2); 294 295 /* compute the ratio of the actual to the predicted */ 296 /* reduction. */ 297 ratio = 0.; 298 if (prered != 0.) 299 ratio = actred / prered; 300 301 /* update the step bound. */ 302 if (ratio <= Scalar(.25)) { 303 if (actred >= 0.) 304 temp = Scalar(.5); 305 if (actred < 0.) 306 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred); 307 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1)) 308 temp = Scalar(.1); 309 /* Computing MIN */ 310 delta = temp * (std::min)(delta, pnorm / Scalar(.1)); 311 par /= temp; 312 } else if (!(par != 0. && ratio < Scalar(.75))) { 313 delta = pnorm / Scalar(.5); 314 par = Scalar(.5) * par; 315 } 316 317 /* test for successful iteration. */ 318 if (ratio >= Scalar(1e-4)) { 319 /* successful iteration. update x, fvec, and their norms. */ 320 x = wa2; 321 wa2 = diag.cwiseProduct(x); 322 fvec = wa4; 323 xnorm = wa2.stableNorm(); 324 fnorm = fnorm1; 325 ++iter; 326 } 327 328 /* tests for convergence. */ 329 if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) 330 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall; 331 if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) 332 return LevenbergMarquardtSpace::RelativeReductionTooSmall; 333 if (delta <= parameters.xtol * xnorm) 334 return LevenbergMarquardtSpace::RelativeErrorTooSmall; 335 336 /* tests for termination and stringent tolerances. */ 337 if (nfev >= parameters.maxfev) 338 return LevenbergMarquardtSpace::TooManyFunctionEvaluation; 339 if (internal::abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.) 340 return LevenbergMarquardtSpace::FtolTooSmall; 341 if (delta <= NumTraits<Scalar>::epsilon() * xnorm) 342 return LevenbergMarquardtSpace::XtolTooSmall; 343 if (gnorm <= NumTraits<Scalar>::epsilon()) 344 return LevenbergMarquardtSpace::GtolTooSmall; 345 346 } while (ratio < Scalar(1e-4)); 347 348 return LevenbergMarquardtSpace::Running; 349 } 350 351 template<typename FunctorType, typename Scalar> 352 LevenbergMarquardtSpace::Status 353 LevenbergMarquardt<FunctorType,Scalar>::lmstr1( 354 FVectorType &x, 355 const Scalar tol 356 ) 357 { 358 n = x.size(); 359 m = functor.values(); 360 361 /* check the input parameters for errors. */ 362 if (n <= 0 || m < n || tol < 0.) 363 return LevenbergMarquardtSpace::ImproperInputParameters; 364 365 resetParameters(); 366 parameters.ftol = tol; 367 parameters.xtol = tol; 368 parameters.maxfev = 100*(n+1); 369 370 return minimizeOptimumStorage(x); 371 } 372 373 template<typename FunctorType, typename Scalar> 374 LevenbergMarquardtSpace::Status 375 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageInit(FVectorType &x) 376 { 377 n = x.size(); 378 m = functor.values(); 379 380 wa1.resize(n); wa2.resize(n); wa3.resize(n); 381 wa4.resize(m); 382 fvec.resize(m); 383 // Only R is stored in fjac. Q is only used to compute 'qtf', which is 384 // Q.transpose()*rhs. qtf will be updated using givens rotation, 385 // instead of storing them in Q. 386 // The purpose it to only use a nxn matrix, instead of mxn here, so 387 // that we can handle cases where m>>n : 388 fjac.resize(n, n); 389 if (!useExternalScaling) 390 diag.resize(n); 391 assert( (!useExternalScaling || diag.size()==n) || "When useExternalScaling is set, the caller must provide a valid 'diag'"); 392 qtf.resize(n); 393 394 /* Function Body */ 395 nfev = 0; 396 njev = 0; 397 398 /* check the input parameters for errors. */ 399 if (n <= 0 || m < n || parameters.ftol < 0. || parameters.xtol < 0. || parameters.gtol < 0. || parameters.maxfev <= 0 || parameters.factor <= 0.) 400 return LevenbergMarquardtSpace::ImproperInputParameters; 401 402 if (useExternalScaling) 403 for (Index j = 0; j < n; ++j) 404 if (diag[j] <= 0.) 405 return LevenbergMarquardtSpace::ImproperInputParameters; 406 407 /* evaluate the function at the starting point */ 408 /* and calculate its norm. */ 409 nfev = 1; 410 if ( functor(x, fvec) < 0) 411 return LevenbergMarquardtSpace::UserAsked; 412 fnorm = fvec.stableNorm(); 413 414 /* initialize levenberg-marquardt parameter and iteration counter. */ 415 par = 0.; 416 iter = 1; 417 418 return LevenbergMarquardtSpace::NotStarted; 419 } 420 421 422 template<typename FunctorType, typename Scalar> 423 LevenbergMarquardtSpace::Status 424 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorageOneStep(FVectorType &x) 425 { 426 assert(x.size()==n); // check the caller is not cheating us 427 428 Index i, j; 429 bool sing; 430 431 /* compute the qr factorization of the jacobian matrix */ 432 /* calculated one row at a time, while simultaneously */ 433 /* forming (q transpose)*fvec and storing the first */ 434 /* n components in qtf. */ 435 qtf.fill(0.); 436 fjac.fill(0.); 437 Index rownb = 2; 438 for (i = 0; i < m; ++i) { 439 if (functor.df(x, wa3, rownb) < 0) return LevenbergMarquardtSpace::UserAsked; 440 internal::rwupdt<Scalar>(fjac, wa3, qtf, fvec[i]); 441 ++rownb; 442 } 443 ++njev; 444 445 /* if the jacobian is rank deficient, call qrfac to */ 446 /* reorder its columns and update the components of qtf. */ 447 sing = false; 448 for (j = 0; j < n; ++j) { 449 if (fjac(j,j) == 0.) 450 sing = true; 451 wa2[j] = fjac.col(j).head(j).stableNorm(); 452 } 453 permutation.setIdentity(n); 454 if (sing) { 455 wa2 = fjac.colwise().blueNorm(); 456 // TODO We have no unit test covering this code path, do not modify 457 // until it is carefully tested 458 ColPivHouseholderQR<JacobianType> qrfac(fjac); 459 fjac = qrfac.matrixQR(); 460 wa1 = fjac.diagonal(); 461 fjac.diagonal() = qrfac.hCoeffs(); 462 permutation = qrfac.colsPermutation(); 463 // TODO : avoid this: 464 for(Index ii=0; ii< fjac.cols(); ii++) fjac.col(ii).segment(ii+1, fjac.rows()-ii-1) *= fjac(ii,ii); // rescale vectors 465 466 for (j = 0; j < n; ++j) { 467 if (fjac(j,j) != 0.) { 468 sum = 0.; 469 for (i = j; i < n; ++i) 470 sum += fjac(i,j) * qtf[i]; 471 temp = -sum / fjac(j,j); 472 for (i = j; i < n; ++i) 473 qtf[i] += fjac(i,j) * temp; 474 } 475 fjac(j,j) = wa1[j]; 476 } 477 } 478 479 /* on the first iteration and if external scaling is not used, scale according */ 480 /* to the norms of the columns of the initial jacobian. */ 481 if (iter == 1) { 482 if (!useExternalScaling) 483 for (j = 0; j < n; ++j) 484 diag[j] = (wa2[j]==0.)? 1. : wa2[j]; 485 486 /* on the first iteration, calculate the norm of the scaled x */ 487 /* and initialize the step bound delta. */ 488 xnorm = diag.cwiseProduct(x).stableNorm(); 489 delta = parameters.factor * xnorm; 490 if (delta == 0.) 491 delta = parameters.factor; 492 } 493 494 /* compute the norm of the scaled gradient. */ 495 gnorm = 0.; 496 if (fnorm != 0.) 497 for (j = 0; j < n; ++j) 498 if (wa2[permutation.indices()[j]] != 0.) 499 gnorm = (std::max)(gnorm, internal::abs( fjac.col(j).head(j+1).dot(qtf.head(j+1)/fnorm) / wa2[permutation.indices()[j]])); 500 501 /* test for convergence of the gradient norm. */ 502 if (gnorm <= parameters.gtol) 503 return LevenbergMarquardtSpace::CosinusTooSmall; 504 505 /* rescale if necessary. */ 506 if (!useExternalScaling) 507 diag = diag.cwiseMax(wa2); 508 509 do { 510 511 /* determine the levenberg-marquardt parameter. */ 512 internal::lmpar<Scalar>(fjac, permutation.indices(), diag, qtf, delta, par, wa1); 513 514 /* store the direction p and x + p. calculate the norm of p. */ 515 wa1 = -wa1; 516 wa2 = x + wa1; 517 pnorm = diag.cwiseProduct(wa1).stableNorm(); 518 519 /* on the first iteration, adjust the initial step bound. */ 520 if (iter == 1) 521 delta = (std::min)(delta,pnorm); 522 523 /* evaluate the function at x + p and calculate its norm. */ 524 if ( functor(wa2, wa4) < 0) 525 return LevenbergMarquardtSpace::UserAsked; 526 ++nfev; 527 fnorm1 = wa4.stableNorm(); 528 529 /* compute the scaled actual reduction. */ 530 actred = -1.; 531 if (Scalar(.1) * fnorm1 < fnorm) 532 actred = 1. - internal::abs2(fnorm1 / fnorm); 533 534 /* compute the scaled predicted reduction and */ 535 /* the scaled directional derivative. */ 536 wa3 = fjac.topLeftCorner(n,n).template triangularView<Upper>() * (permutation.inverse() * wa1); 537 temp1 = internal::abs2(wa3.stableNorm() / fnorm); 538 temp2 = internal::abs2(internal::sqrt(par) * pnorm / fnorm); 539 prered = temp1 + temp2 / Scalar(.5); 540 dirder = -(temp1 + temp2); 541 542 /* compute the ratio of the actual to the predicted */ 543 /* reduction. */ 544 ratio = 0.; 545 if (prered != 0.) 546 ratio = actred / prered; 547 548 /* update the step bound. */ 549 if (ratio <= Scalar(.25)) { 550 if (actred >= 0.) 551 temp = Scalar(.5); 552 if (actred < 0.) 553 temp = Scalar(.5) * dirder / (dirder + Scalar(.5) * actred); 554 if (Scalar(.1) * fnorm1 >= fnorm || temp < Scalar(.1)) 555 temp = Scalar(.1); 556 /* Computing MIN */ 557 delta = temp * (std::min)(delta, pnorm / Scalar(.1)); 558 par /= temp; 559 } else if (!(par != 0. && ratio < Scalar(.75))) { 560 delta = pnorm / Scalar(.5); 561 par = Scalar(.5) * par; 562 } 563 564 /* test for successful iteration. */ 565 if (ratio >= Scalar(1e-4)) { 566 /* successful iteration. update x, fvec, and their norms. */ 567 x = wa2; 568 wa2 = diag.cwiseProduct(x); 569 fvec = wa4; 570 xnorm = wa2.stableNorm(); 571 fnorm = fnorm1; 572 ++iter; 573 } 574 575 /* tests for convergence. */ 576 if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1. && delta <= parameters.xtol * xnorm) 577 return LevenbergMarquardtSpace::RelativeErrorAndReductionTooSmall; 578 if (internal::abs(actred) <= parameters.ftol && prered <= parameters.ftol && Scalar(.5) * ratio <= 1.) 579 return LevenbergMarquardtSpace::RelativeReductionTooSmall; 580 if (delta <= parameters.xtol * xnorm) 581 return LevenbergMarquardtSpace::RelativeErrorTooSmall; 582 583 /* tests for termination and stringent tolerances. */ 584 if (nfev >= parameters.maxfev) 585 return LevenbergMarquardtSpace::TooManyFunctionEvaluation; 586 if (internal::abs(actred) <= NumTraits<Scalar>::epsilon() && prered <= NumTraits<Scalar>::epsilon() && Scalar(.5) * ratio <= 1.) 587 return LevenbergMarquardtSpace::FtolTooSmall; 588 if (delta <= NumTraits<Scalar>::epsilon() * xnorm) 589 return LevenbergMarquardtSpace::XtolTooSmall; 590 if (gnorm <= NumTraits<Scalar>::epsilon()) 591 return LevenbergMarquardtSpace::GtolTooSmall; 592 593 } while (ratio < Scalar(1e-4)); 594 595 return LevenbergMarquardtSpace::Running; 596 } 597 598 template<typename FunctorType, typename Scalar> 599 LevenbergMarquardtSpace::Status 600 LevenbergMarquardt<FunctorType,Scalar>::minimizeOptimumStorage(FVectorType &x) 601 { 602 LevenbergMarquardtSpace::Status status = minimizeOptimumStorageInit(x); 603 if (status==LevenbergMarquardtSpace::ImproperInputParameters) 604 return status; 605 do { 606 status = minimizeOptimumStorageOneStep(x); 607 } while (status==LevenbergMarquardtSpace::Running); 608 return status; 609 } 610 611 template<typename FunctorType, typename Scalar> 612 LevenbergMarquardtSpace::Status 613 LevenbergMarquardt<FunctorType,Scalar>::lmdif1( 614 FunctorType &functor, 615 FVectorType &x, 616 Index *nfev, 617 const Scalar tol 618 ) 619 { 620 Index n = x.size(); 621 Index m = functor.values(); 622 623 /* check the input parameters for errors. */ 624 if (n <= 0 || m < n || tol < 0.) 625 return LevenbergMarquardtSpace::ImproperInputParameters; 626 627 NumericalDiff<FunctorType> numDiff(functor); 628 // embedded LevenbergMarquardt 629 LevenbergMarquardt<NumericalDiff<FunctorType>, Scalar > lm(numDiff); 630 lm.parameters.ftol = tol; 631 lm.parameters.xtol = tol; 632 lm.parameters.maxfev = 200*(n+1); 633 634 LevenbergMarquardtSpace::Status info = LevenbergMarquardtSpace::Status(lm.minimize(x)); 635 if (nfev) 636 * nfev = lm.nfev; 637 return info; 638 } 639 640 } // end namespace Eigen 641 642 #endif // EIGEN_LEVENBERGMARQUARDT__H 643 644 //vim: ai ts=4 sts=4 et sw=4 645