From 67e1b2a277b38f5991e8d12c23b669b3e63e7339 Mon Sep 17 00:00:00 2001 From: Jesper Andersson <jesper.andersson@ndcn.ox.ac.uk> Date: Mon, 24 Feb 2020 12:00:31 +0000 Subject: [PATCH] Made changes to Levenberg-Marquardt (levmar) so that there is now a pure Gauss-Newton option --- nonlin.cpp | 10 +++++++--- nonlin.h | 6 ++++-- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nonlin.cpp b/nonlin.cpp index 16e5641..6f7c3c5 100644 --- a/nonlin.cpp +++ b/nonlin.cpp @@ -359,7 +359,6 @@ NonlinOut levmar(const NonlinParam& p, const NonlinCF& cfo) H = cfo.hess(p.Par(),H); // Hessian evaluated at current parameters prof.EndEntry(hess_key); } - double nudge_key = prof.StartEntry("Nudge hessian"); for (int i=1; i<=p.NPar(); i++) { // Nudge it if (p.GaussNewtonType() == LM_LM) { // If Levenberg-Marquardt // H->AddTo(i,i,(p.Lambda()-olambda)*H->Peek(i,i)); @@ -368,8 +367,8 @@ NonlinOut levmar(const NonlinParam& p, const NonlinCF& cfo) else if (p.GaussNewtonType() == LM_L) { // If Levenberg H->AddTo(i,i,p.Lambda()-olambda); } + else if (p.GaussNewtonType() == LM_GN) {} // If it is pure Gauss-Newton we don't nudge at all } - prof.EndEntry(nudge_key); ColumnVector step; double ncf = 0.0; bool inv_fail = false; // Signals failure of equation solving @@ -384,7 +383,7 @@ NonlinOut levmar(const NonlinParam& p, const NonlinCF& cfo) prof.EndEntry(fail_key); } prof.EndEntry(solve_key); - if (!inv_fail && (success = (ncf < p.CF()))) { // If last step successful + if (!inv_fail && (success = (ncf < p.CF()))) { // If last step successful olambda = 0.0; // Pristine Hessian, so no need to undo old lambda p.SetPar(p.Par()+step); // Set attempt as new parameters p.SetLambda(p.Lambda()/10.0); // Decrease nudge factor @@ -395,6 +394,11 @@ NonlinOut levmar(const NonlinParam& p, const NonlinCF& cfo) p.SetCF(ncf); // Store value of cost-function } else { // If last step was unsuccesful + if (p.GaussNewtonType() == LM_GN) { // For pure Gauss-Newton we stop if unsuccessful in reducing cf + if (inv_fail) p.SetStatus(NL_INV_FAIL); // Inversion of Hessian failed + else if (!(ncf < p.CF())) p.SetStatus(NL_CF_INC_CONV);// Cost-function failed to decrease + return(p.Status()); + } success = false; olambda = p.Lambda(); // Returning to same H, so must undo old lambda p.SetLambda(10.0*p.Lambda()); // Increase nudge factor diff --git a/nonlin.h b/nonlin.h index 183e63c..63c7f02 100644 --- a/nonlin.h +++ b/nonlin.h @@ -34,7 +34,7 @@ enum NLMethod {NL_VM, // Variable-Metric (see NRin NL_GD, // Gradient Descent NL_NM}; // Nelder-Mead simplex method (see NRinC) -enum LMType {LM_L, LM_LM}; // Levenberg or Levenberg-Marquardt +enum LMType {LM_GN, LM_L, LM_LM}; // Gauss-Newton, Levenberg or Levenberg-Marquardt enum VMUpdateType {VM_DFP, VM_BFGS}; // See NRinC chapter 10. @@ -50,10 +50,12 @@ enum LinOut {LM_MAXITER, // Too many iterations in li enum NonlinOut {NL_UNDEFINED, // Initial value before minimisation NL_MAXITER, // Too many iterations - NL_LM_MAXITER, // To many iterations during a line-minimisation + NL_LM_MAXITER, // Too many iterations during a line-minimisation + NL_INV_FAIL, // Failure to invert Hessian NL_PARCONV, // Convergence. Step in parameter space small NL_GRADCONV, // Convergence. Gradient small NL_CFCONV, // Convergence. Change in cost-function small + NL_CF_INC_CONV, // Sort of convergence. Gauss-Newton step caused increase in cost NL_LCONV}; // Convergence, lambda very large const double EPS = 2.0e-16; // Losely based on NRinC 20.1 -- GitLab