From df6dd9fe17042c522b91a5394b7103aced29711e Mon Sep 17 00:00:00 2001 From: Scott Stephens Date: Fri, 1 Feb 2013 19:06:07 -0600 Subject: [PATCH] Optimization: Improve error handling and reporting. --- .../ConjugateGradientMinimizer.cs | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs index d2aa1049..707459d6 100644 --- a/src/Numerics/Optimization/ConjugateGradientMinimizer.cs +++ b/src/Numerics/Optimization/ConjugateGradientMinimizer.cs @@ -11,18 +11,18 @@ namespace MathNet.Numerics.Optimization public ConjugateGradientMinimizer(double gradientTolerance, int maximumIterations) { - this.GradientTolerance = gradientTolerance; - this.MaximumIterations = maximumIterations; + GradientTolerance = gradientTolerance; + MaximumIterations = maximumIterations; } public MinimizationResult FindMinimum(IObjectiveFunction objective, Vector initialGuess) { if (!objective.IsGradientSupported) - throw new Exception("Gradient not supported in objective function, but required for ConjugateGradient minimization."); + throw new IncompatibleObjectiveException("Gradient not supported in objective function, but required for ConjugateGradient minimization."); objective.EvaluateAt(initialGuess); var gradient = objective.Gradient; - ValidateGradient(gradient, initialGuess); + ValidateGradient(objective); // Check that we're not already done if (ExitCriteriaSatisfied(initialGuess, gradient)) @@ -35,11 +35,22 @@ namespace MathNet.Numerics.Optimization var steepestDirection = -gradient; var searchDirection = steepestDirection; double initialStepSize = 100 * GradientTolerance / (gradient * gradient); - var result = lineSearcher.FindConformingStep(objective, searchDirection, initialStepSize); + + LineSearchResult result; + try + { + result = lineSearcher.FindConformingStep(objective, searchDirection, initialStepSize); + } + catch (Exception e) + { + throw new InnerOptimizationException("Line search failed.", e); + } + objective = result.FunctionInfoAtMinimum; - ValidateGradient(objective.Gradient, objective.Point); + ValidateGradient(objective); double stepSize = (objective.Point - initialGuess).Norm(2.0); + // Subsequent steps int iterations = 1; int totalLineSearchSteps = result.Iterations; @@ -57,8 +68,14 @@ namespace MathNet.Numerics.Optimization steepestDescentResets += 1; } - - result = lineSearcher.FindConformingStep(objective, searchDirection, stepSize); + try + { + result = lineSearcher.FindConformingStep(objective, searchDirection, stepSize); + } + catch (Exception e) + { + throw new InnerOptimizationException("Line search failed.", e); + } noLineSearchIterations += result.Iterations == 0 ? 1 : 0; totalLineSearchSteps += result.Iterations; @@ -68,27 +85,32 @@ namespace MathNet.Numerics.Optimization iterations += 1; } + if (iterations == MaximumIterations) + { + throw new MaximumIterationsException(String.Format("Maximum iterations ({0}) reached.", MaximumIterations)); + } + return new MinimizationWithLineSearchResult(objective, iterations, MinimizationResult.ExitCondition.AbsoluteGradient, totalLineSearchSteps, noLineSearchIterations); } - private bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient) + bool ExitCriteriaSatisfied(Vector candidatePoint, Vector gradient) { return gradient.Norm(2.0) < GradientTolerance; } - private void ValidateGradient(Vector gradient, Vector input) + void ValidateGradient(IObjectiveFunction objective) { - foreach (var x in gradient) + foreach (var x in objective.Gradient) { if (Double.IsNaN(x) || Double.IsInfinity(x)) - throw new Exception("Non-finite gradient returned."); + throw new EvaluationException("Non-finite gradient returned.", objective); } } - private void ValidateObjective(double objective, Vector input) + void ValidateObjective(IObjectiveFunction objective) { - if (Double.IsNaN(objective) || Double.IsInfinity(objective)) - throw new Exception("Non-finite objective function returned."); + if (Double.IsNaN(objective.Value) || Double.IsInfinity(objective.Value)) + throw new EvaluationException("Non-finite objective function returned.", objective); } } }